How can you turn a number like 1k into 1000 in lua? - lua

I am currently working on a game in Roblox studio, and I'm wondering How can you turn a number like 1k into 1000 in lua?

A quick solution would be a lookup table with all postfixes, for example something like this:
local postfixes = {
["n"] = 10^(-6),
["m"] = 10^(-3),
["k"] = 10^3,
["M"] = 10^6,
["G"] = 10^9,
}
local function convert(n)
local postfix = n:sub(-1)
if postfixes[postfix] then
return tonumber(n:sub(1, -2)) * postfixes[postfix]
elseif tonumber(n) then
return tonumber(n)
else
error("invalid postfix")
end
end
print(convert("1k"))
print(convert("23M"))
print(convert("7n"))
print(convert("7x"))
1000.0
23000000.0
7e-06
invalid postfix

Related

Sticky variable value in lua vim.keymap

I want to create a mapping in my neovim lua setup such that when I have a visual selection and hit <leader>ps, a telescope search is initiated with the selected text.
Here is what I have for the moment:
local builtin = require('telescope.builtin')
local function get_visual_selection()
local s_start = vim.fn.getpos("'<")
local s_end = vim.fn.getpos("'>")
local n_lines = math.abs(s_end[2] - s_start[2]) + 1
local lines = vim.api.nvim_buf_get_lines(0, s_start[2] - 1, s_end[2], false)
lines[1] = string.sub(lines[1], s_start[3], -1)
if n_lines == 1 then
lines[n_lines] = string.sub(lines[n_lines], 1, s_end[3] - s_start[3] + 1)
else
lines[n_lines] = string.sub(lines[n_lines], 1, s_end[3])
end
return table.concat(lines, '\n')
end
vim.keymap.set('n', '<leader>ps', function() -- works fine
builtin.grep_string({ search = vim.fn.input("Grep > ") });
end)
vim.keymap.set('v', '<leader>ps', function() -- gets the same first value for sel everytime!
local sel = get_visual_selection();
builtin.grep_string({ search = vim.fn.input("Grep > " .. sel) });
end)
This code works on the first time; but then the first text retrieved from selection never changes! I get the first text I selected over and over. I don't understand what is causing that. It seems the function gets hit by some sort of caching mechanism from lua...?
I finally used a different and simpler way of doing this exact thing using a remap, yank and paste; I still don't know what's wrong in my question's lua script though.
Here is the working lua map:
vim.keymap.set('v', '<leader>ps', 'y<leader>ps<C-r>*', { remap = true });

How to add an array of fields as a ProtoField in Lua Dissector

I'm writing a Lua Dissector for Wireshark. The packets I'm trying to dissect have the following format:
V_SPEED
N_ITERATION
SEG_LEN[N_ITERATION] --> This means there are N_ITERATION SEG_LEN in my packet
I succeed to add the basic fields (V_SPEED and N_ITERATION) as Wireshark Protofield and I can filter based on those. However I'm struggling for the array of SEG_LEN. I want to be able to use filter like "SEG_LEN[1] == XYZ". How can I achieve that?
For now, I have the following ProtoFields:
myproto = Proto("MyProto", "My Protocol")
myproto.fields.v_speed = ProtoField.uint16("myproto.v_speed", "v_speed", base.DEC)
myproto.fields.n_iteration = ProtoField.uint16("myproto.n_iteration", "n_iteration", base.DEC)
I tried to define a ProtoField for each possible SEG_LEN like so
myproto.fields.seg_len_1 = ProtoField.uint16("myproto.seg_len_1", "seg_len_1", base.DEC)
myproto.fields.seg_len_2 = ProtoField.uint16("myproto.seg_len_2", "seg_len_2", base.DEC)
...
myproto.fields.seg_len_255 = ProtoField.uint16("myproto.seg_len_255", "seg_len_255", base.DEC)
And so I have the following piece of code in my dissector function:
for i0 = 1, N_ITERATION do
seg_len_tmp = extract_variable(buffer, bit_offset, 16)
bit_offset = bit_offset + 16
tree:add(_G["myproto.fields.seg_len"..i0], seg_len_tmp)
end
That way, I guess I would be able to use filter like "SEG_LEN_1 == XYZ".
But wireshark gives me an error saying I'm trying to add a NIL value.
Also, I don't feel like it's a good approach.
I know I can also define a single ProtoField for my seg_len, and add all my seg_len to the tree using the same Protofield, but this will prevent me from filtering with an index.
(English is not my native language, excuse me for the syntax errors)
Something like this?
local myproto = Proto("MyProto", "My Protocol")
local N_ITERATION = 3
-- All the segment lengths in one table
local seg_len = {
[1] = ProtoField.uint16("myproto.seg_len_1", "seg_len_1", base.DEC),
[2] = ProtoField.uint16("myproto.seg_len_2", "seg_len_2", base.DEC),
[3] = ProtoField.uint16("myproto.seg_len_3", "seg_len_3", base.DEC)
}
-- All other fields in a generic pf (protocol fields) table
local pf = {
v_speed = ProtoField.uint16("myproto.v_speed", "v_speed", base.DEC),
n_iteration = ProtoField.uint16("myproto.n_iteration", "n_iteration", base.DEC)
}
-- https://stackoverflow.com/questions/1410862/concatenation-of-tables-in-lua
local function TableConcat(t1, t2)
local i
for i = 1, #t2 do
t1[#t1 + 1] = t2[i]
end
return t1
end
myproto.fields = TableConcat(pf, seg_len)
function myproto.dissector(tvbuf, pinfo, tree)
local offset = 0
myproto_tree = tree:add(myproto, tvbuf(0, -1))
for i = 1, N_ITERATION do
myproto_tree:add(seg_len[i], tvbuf(offset, 2))
offset = offset + 2
end
myproto_tree:add(pf.v_speed, tvbuf(offset, 2))
myproto_tree:add(pf.n_iteration, tvbuf(offset + 2, 2))
end

/Lua/ How to do this (idk how to call that lol)

I need to make a trolleybus number, which won't repeat for game. For example, there is a number "101" and there musn't be more "101". How to do that? I have a code, but I know, he won't work and I won't test it lol
function giveNumber()
local number = math.random(100, 199)
local takedNumbers = {}
local i = 0
local massiv = i+1
script.Parent.pered.SurfaceGui.TextLabel.Text = number
script.Parent.zad.SurfaceGui.TextLabel.Text = number
script.Parent.levo.SurfaceGui.TextLabel.Text = number
script.Parent.pravo.SurfaceGui.TextLabel.Text = number
takedNumbers[massiv] = {number}
end
script.Parent.Script:giveNumber() // what I wrote here? idk...
if number == takedNumbers[massiv] then
giveNumber()
end
i didn't test it, because I think it won't work because this code is something bad
I think this will serve your needs.
In the function generateUniqueNumber, the script loops until it found a number that is not yet in the array. (in other words, that it hasn't given out yet)
Once it found that number, it will insert it into the table to remember that it has given it out, and then it will return the number.
Then on the bottom of the script we just give the numbers to the buses :-)
--[[
Goal: Give all buses a unique number
]]
-- Variables
local takenNumbers = {};
-- This function returns a random number in the range [100, 199] that has not been taken yet
function generateUniqueNumber()
local foundNumber = false;
while not foundNumber do
randomNumber = math.random(100, 199);
if not table.find(takenNumbers, randomNumber) then
table.insert(takenNumbers, randomNumber);
return randomNumber;
end
end
end
-- This function sets the number of the bus
script.Parent.pered.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
script.Parent.zad.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
script.Parent.levo.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
script.Parent.pravo.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
2 things:
I didn't test this code as Roblox is not installed on the pc I'm currently on.
Please try formatting your code nicely next time. It greatly improves the readability! For example, you can use this website:
https://codebeautify.org/lua-beautifier
Simpler
Fill a table with free numbers...
local freenumbers = {}
for i = 1, 99 do freenumbers[i] = i + 100 end
...for every new takennumbers use table.remove() on freenumbers
local takennumbers = {}
if #freenumbers > 0 then
takennumbers[#takennumbers + 1] = table.remove(freenumbers, math.random(1, #freenumbers))
end

LUA: Looking for a specific table by its variable

I'm currently starting work on a text adventure game in Lua--no addons, just pure Lua for my first project. In essence, here is my problem; I'm trying to find out how I can do a "reverse lookup" of a table using one of its variables. Here's an example of what I've tried to do:
print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
table.insert(bag,gold)
print("You took the " .. gold.name .. ".")
end
Obviously, writing a line like this with every single object in the game would be very... exhausting--especially since I think I'll be able to use this solution for not just taking items but movement from room to room using a reverse lookup with each room's (x,y) coordinates. Anyone have any ideas on how to make a more flexible system that can find a table by the player typing in one of its variables? Thanks in advance!
-blockchainporter
This doesn't directly answer your question as you asked it, but I think it would serve the purpose of what you are trying to do. I create a table called 'loot' which can hold many objects, and the player can place any of these in their 'bag' by typing the name.
bag = {}
loot = {
{name="Gold", qty=3},
{name="Axe", qty=1},
}
print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
if (x == loot[i].name) then
table.insert(bag, table.remove(loot,i))
else
i = i + 1
end
end
For bonus points, you could check 'bag' to see if the player has some of that item already and then just update the quantity...
while loot[i] do
if (x == loot[i].name) then
j, found = 1, nil
while bag[j] do
if (x == bag[j].name) then
found = true
bag[j].qty = bag[j].qty + loot[i].qty
table.remove(loot,i)
end
j = j + 1
end
if (not found) then
table.insert(bag, table.remove(loot,i))
end
else
i = i + 1
end
end
Again, this isn't a 'reverse lookup' solution like you asked for... but I think it is closer to what you are trying to do by letting a user choose to loot something.
My disclaimer is that I don't use IO functions in my own lua usage, so I have to assume that your x = io.read("*l") is correct.
PS. If you only ever want objects to have a name and qty, and never any other properties (like condition, enchantment, or whatever) then you could also simplify my solution by using key/val pairs:
bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }
print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
if x == name then
bag.name = (bag.name or 0) + qty
loot.name = nil
end
end
I have a few notes to start before I specifically address your question. (I just want to do this before I forget, so please bear with me!)
I recommend printing to the terminal using stderr instead of stdout--the Lua function print uses the latter. When I am writing a Lua script, I often create a C-style function called eprintf to print formatted output to stderr. I implement it like this:
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
Just be aware that, unlike print, this function does not automatically append a newline character to the output string; to do so, remember to put \n at the end of your fmt string.
Next, it may be useful to define a helper function that calls io.read("*l") to get an entire line of input. In writing some example code to help answer your question, I called my function getline--like the C++ function that has similar behavior--and defined it like this:
local function getline()
local read = tostring(io.read("*l"))
return read
end
If I correctly understand what it is you are trying to do, the player will have an inventory--which you have called bag--and he can put items into it by entering item names into stdin. So, for instance, if the player found a treasure chest with gold, a sword, and a potion in it and he wanted to take the gold, he would type Gold into stdin and it would be placed in his inventory.
Based on what you have so far, it looks like you are using Lua tables to create these items: each table has a name index and another called ap; and, if a player's text input matches an item's name, the player picks that up item.
I would recommend creating an Item class, which you could abstract nicely by placing it in its own script and then loading it as needed with require. This is a very basic Item class module I wrote:
----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item
-- __newindex metamethod.
function Item.__newindex(self, k, v)
local err = string.format(
"type `Item` does not have member `%s`",
tostring(k)
)
return error(err, 2)
end
-- Item constructor
function Item.new(name_in, ap_in)
assert((name_in ~= nil) and (ap_in ~= nil))
local self = {
name = name_in,
ap = ap_in
}
return setmetatable(self, Item)
end
return Item
From there, I wrote a main driver to encapsulate some of the behavior you described in your question. (Yes, I know my Lua code looks more like C.)
#!/usr/bin/lua
-------------
-- Modules --
-------------
local Item = assert(require("Item"))
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
local function printf(fmt, ...)
io.stdout:write(string.format(fmt, ...))
return
end
local function getline()
local read = tostring(io.read("*l"))
return read
end
local function main(argc, argv)
local gold = Item.new("Gold", 3)
printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
return 0
end
main(#arg, arg)
Now, as for the reverse search which you described, at this point all you should have to do is check the user's input against an Item's name. Here it is in the main function:
local function main(argc, argv)
local gold = Item.new("Gold", 3)
local bag = {}
eprintf("What are you trying to take? ")
local input = getline()
if (input == gold.name) then
table.insert(bag, gold)
eprintf("You took the %s.\n", gold.name)
else
eprintf("Unrecognized item `%s`.\n", input)
end
return 0
end
I hope this helps!

How to use Lua field extractor in Wireshark?

I have a protocol like this
"Packet" - A sequence of messages
{Head}{Content}{Head}{Content}...
"Head" - 1 byte
bit 1-7 : msg length
bit 8 : true msg or not
It is a udp communication, I have to use that bit 8 to determine if I need to skip the message.
Following is my toy parser, the Problem I am facing is how to extract the bool value helping me to make the decision.
TOY_proto = Proto("TOY", "TOY Protocol")
local isSkip = ProtoField.new("Is Skip?", "mytoy.isSkip", ftypes.BOOLEAN, {"Yes", "No"}, 8, 0x01)
local msgLen = ProroField.new("Message Length", "mytoy.msgLen", ftypes.UINT8, nil, base.DEC, 0xFE)
TOY_proto.fields = {isSkip, msgLen}
local isSkip_Field = Field.new("mytoy.isSkip")
local function getIsSkip()
return isSkip_Field()()
end
local msgLen_Field = Field.new("mytoy.msgLen")
local function getMsgLen()
return msgLen_Field()()
end
function TOY_proto.dissector(tvbuf, pktinfo, root)
pktinfo.cols.protocol = "TOY"
local pktlen = tvbuf:reported_length_remaining()
local pos = 0
while pos < pktlen do
local headTree = tree:add("Head")
headTree:add_le(isSkip, tvbuf:range(pos,1))
headTree:add_le(msgLen, tvbuf:range(pos,1))
if getIsSkip() then
pos = pos + getMsgLen()
else
-- do something else
end
end
end
udp_table = DissectorTable.get("udp.port")
udp_table:add(6628, TOY_proto)
The Problem is that in the first loop, every variable is doing right, but after the first loop, the value returned from getIsSkip() and getMsgLen() are always unchanged.
When you do this:
return isSkip_Field()()
What you're really doing is logically equivalent to this:
-- extract the FieldInfo object using the Field object "isSkip_Field"
local tempFieldInfo = isSkip_Field()
-- get the Lua boolean value of the FieldInfo object
local tempValue = tempFieldInfo()
-- return it
return tempValue
I mention the above to explain why you're getting what you're getting later in this answer...
When you invoke a field extractor (i.e., you call a Field object to get a FieldInfo object), you actually get back every FieldInfo object of that Field's type that exists in that packet at the time the extractor is invoked. Your packet contains multiple "messages" of your protocol, so in each loop you get back the previous loops' FieldInfo objects as well as the current one, for the same packet.
In other words, when your script executed this:
return isSkip_Field()()
...the first time for a packet, it got back one FieldInfo object, called that, and got the boolean. When it ran the second time, the call to isSkip_Field() actually returned two FieldInfo objects, but it discarded the second one because the code is logically equivalent to the code I wrote at the top of this answer, and instead only called the first instance, which of course rteturns the same boolean value as the first loop iteration; and when it ran a third time for the same packet it returned three FieldInfo objects, discarded the second two, called the first one, etc.
So what you really want to do is select the correct FieldInfo object each loop iteration - namely the most recent (last) one. You can do that one of two ways: (1) using the Lua select() function, or (2) put the returned FieldInfo objects into a table and retrieve the last entry.
For example, do this:
local isSkip_Field = Field.new("mytoy.isSkip")
local function getIsSkip(num)
return select(num, isSkip_Field())()
end
local msgLen_Field = Field.new("mytoy.msgLen")
local function getMsgLen(num)
return select(num, msgLen_Field())()
end
function TOY_proto.dissector(tvbuf, pktinfo, root)
pktinfo.cols.protocol = "TOY"
local pktlen = tvbuf:reported_length_remaining()
local pos = 0
local num = 1
while pos < pktlen do
local headTree = tree:add("Head")
headTree:add_le(isSkip, tvbuf:range(pos,1))
headTree:add_le(msgLen, tvbuf:range(pos,1))
if getIsSkip(num) then
pos = pos + getMsgLen(num)
else
-- do something else
end
num = num + 1
end
end
...or this:
local isSkip_Field = Field.new("mytoy.isSkip")
local function getIsSkip()
local tbl = { isSkip_Field() }
return tbl[#tbl]()
end
local msgLen_Field = Field.new("mytoy.msgLen")
local function getMsgLen()
local tbl = { msgLen_Field() }
return tbl[#tbl]()
end
function TOY_proto.dissector(tvbuf, pktinfo, root)
pktinfo.cols.protocol = "TOY"
local pktlen = tvbuf:reported_length_remaining()
local pos = 0
while pos < pktlen do
local headTree = tree:add("Head")
headTree:add_le(isSkip, tvbuf:range(pos,1))
headTree:add_le(msgLen, tvbuf:range(pos,1))
if getIsSkip() then
pos = pos + getMsgLen()
else
-- do something else
end
end
end
...or if there are going to be lots of Fields, this might be nicer:
local isSkip_Field = Field.new("mytoy.isSkip")
local msgLen_Field = Field.new("mytoy.msgLen")
local function getFieldValue(field)
local tbl = { field() }
return tbl[#tbl]()
end
function TOY_proto.dissector(tvbuf, pktinfo, root)
pktinfo.cols.protocol = "TOY"
local pktlen = tvbuf:reported_length_remaining()
local pos = 0
while pos < pktlen do
local headTree = tree:add("Head")
headTree:add_le(isSkip, tvbuf:range(pos,1))
headTree:add_le(msgLen, tvbuf:range(pos,1))
if getFieldValue(isSkip_Field) then
pos = pos + getFieldValue(msgLen_Field)
else
-- do something else
end
end
end

Resources