How to self-reference table during initialization - lua

Is there a shorter way to do this:
local thisismytable = {
non = sequitur
}
thisismytable.whatismytable = thisismytable
Any help would be appreciated.
I don't want to re-create pre-existing functionality.

No.
If you can stand the difference between these two expressions thisismytable:whatismytable() instead of thisismytable.whatismytable, you could do:
local thisismytable = {
non = sequitur,
whatismytable = function (self) return self end
}
Testing:
print(thisismytable)
print(thisismytable:whatismytable())
More usage:
print(thisismytable:whatismytable().non)

You can't. I use a helper function.
local function ref(t)
for k, v in next, t do
if v == ref then t[k] = t end
end
return t
end
local root = ref{left=ref, right=ref}
assert(root.left == root)

Related

Having trouble using multiple objects

question about OOP here.
Invader = {PosX = 5, PosY = 5, alive = true}
function Invader:new(x, y)
-- local InvaderImage = paintUtils.loadImage("")
self.__index = self
self.PosX = x
term.setCursorPos(self.PosX, self.PosY)
write("V")
function refreshInvader()
write("moved")
term.setCursorPos(self.PosX, self.PosY)
write(" ")
self.PosX = self.PosX + 3
term.setCursorPos(self.PosX, self.PosY)
write("V")
end
end
If i were to call refreshInvader, only the latest one i created would move. Is there anyway to move all?
You only have one Invader table. All your operations refer to self which is Invader
At no point in your code you create a second table that would serve as a "new object".
You would have to do something like this in order to get multiple objects:
Pet = {}
function Pet:new(name, sound)
self.__index = self
local newObject = setmetatable({}, self)
newObject.name = name or "unnamed"
return newObject
end
local a = Pet:new("Snuggles")
local b = Pet:new("Nibbles")

How to inherit method?

I want to inherit method "GetName" or other methods from "Create" for "CreateInherited" and i want save unique methods from "CreateInherited" (like "GetInheritName"), but i dont know how.
My test code:
local MainTbl = {}
function MainTbl:Create(name)
local tbl = {}
tbl.name = name or 'Null'
function tbl:GetName()
return self.name
end
setmetatable(tbl, self)
self.__index = self
return tbl
end
function MainTbl:CreateInherited(name)
local tbl = {}
tbl.name = name or 'Null'
function tbl:GetInheritName()
return self.name
end
setmetatable(tbl, self)
self.__index = self
return tbl
end
local Man = MainTbl:Create('Man')
local Woman = MainTbl:CreateInherited('Woman')
print(Man:GetName())
print(Woman:GetName())
print(Woman:GetInheritName())
If I understand you, you're trying to put two different constructors into a single class. Notice that Create does most of the work that CreateInherited needs to do, so you can save yourself a lot of repeated code by calling Create inside CreateInherited. Instead of starting with an empty table, you can start with a fully formed instance from Create and add a method to it.
function MainTbl:CreateInherited(name)
local tbl = self:Create(name)
function tbl:GetInheritName()
return self.name
end
return tbl
end

What are _UPVALUE0_ keywords in decompiled Lua?

I have decompiled a few lua codes, was able to understand most of them.
But there are these UPVALUE0, UPVALUE1, etc... keywords I see in the code that are not defined anywhere as far as I've looked.
Here's an example:
local L0_0
L0_0 = module
L0_0((...), package.seeall)
function L0_0(A0_1)
if A0_1 - math.floor(A0_1) > 0 then
error("trying to use bitwise operation on non-integer!")
end
end
bit = {
bxor = function(A0_17, A1_18)
local L2_19, L3_20, L4_21, L5_22
L2_19 = _UPVALUE0_
L3_20 = A0_17
L2_19 = L2_19(L3_20)
L3_20 = _UPVALUE0_
L4_21 = A1_18
L3_20 = L3_20(L4_21)
L4_21 = _UPVALUE1_
L5_22 = L2_19
L4_21(L5_22, L3_20)
L4_21 = {}
L5_22 = math
L5_22 = L5_22.max
L5_22 = L5_22(table.getn(L2_19), table.getn(L3_20))
for _FORV_9_ = 1, L5_22 do
if L2_19[_FORV_9_] ~= L3_20[_FORV_9_] then
L4_21[_FORV_9_] = 1
else
L4_21[_FORV_9_] = 0
end
end
return _UPVALUE2_(L4_21)
end
}
What do they mean?
From https://www.lua.org/pil/6.1.html:
.. is neither a global variable nor a local variable. We call it an
external local variable, or an upvalue. (The term "upvalue" is a
little misleading, because it is a variable, not a value. However,
this term has historical roots in Lua and it is shorter than "external
local variable".)
local i = 0
function inc()
i = i + 1
return i
end
Variable i in function inc is upvalue, as it is not local variable in this function and not global variable.

dictionary help/DataStore

The Issue is I have a dictionary that holds all my data and its supposed to be able to turn into a directorys in replicated storage with all the values being strings then turn back into a dictionary with all the keys when the player leave. However, I cant figure out how to turn into a dictionary(With keys).
ive sat for a few hours testing things but after the first layer of values I cant get figure out a way to get the deeper values and keys into the table
local DataTable =
{
["DontSave_Values"] =
{
["Stamina"] = 100;
};
["DontSave_Debounces"] =
{
};
["TestData"] = 1;
["Ship"] =
{
["Hull"] = "Large_Ship";
["Mast"] = "Iron_Tall";
["Crew"] =
{
["Joe One"] =
{
["Shirt"] = "Blue";
["Pants"] = "Green"
};
["Joe Two"] =
{
["Shirt"] = "Silver";
["Pants"] = "Brown";
["Kids"] =
{
["Joe Mama1"] =
{
["Age"] = 5
};
["Joe Mama2"]=
{
["Age"] = 6
};
}
};
}
};
["Level"] =
{
};
["Exp"] =
{
};
}
------Test to see if its an array
function isArray(Variable)
local Test = pcall(function()
local VarBreak = (Variable.." ")
end)
if Test == false then
return true
else
return false
end
end
------TURNS INTO FOLDERS
function CreateGameDirectory(Player, Data)
local mainFolder = Instance.new("Folder")
mainFolder.Parent = game.ReplicatedStorage
mainFolder.Name = Player.UserId
local function IterateDictionary(Array, mainFolder)
local CurrentDirectory = mainFolder
for i,v in pairs(Array) do
if isArray(v) then
CurrentDirectory = Instance.new("Folder", mainFolder)
CurrentDirectory.Name = i
for o,p in pairs(v) do
if isArray(p) then
local TemporaryDir = Instance.new("Folder", CurrentDirectory)
TemporaryDir.Name = o
IterateDictionary(p, TemporaryDir)
else
local NewValue = Instance.new("StringValue", CurrentDirectory)
NewValue.Name = o
NewValue.Value = p
end
end
else
local value = Instance.new("StringValue", mainFolder)
value.Name = i
value.Value = v
end
end
end
IterateDictionary(Data, mainFolder)
end
------To turn it back into a table
function CreateTable(Player)
local NewDataTable = {}
local Data = RS:FindFirstChild(Player.UserId)
local function DigDeep(newData, pData, ...)
local CurrentDir = newData
for i,v in pairs(pData:GetChildren()) do
if string.sub(v.Name,1,8) ~= "DontSave" then
end
end
end
DigDeep(NewDataTable, Data)
return NewDataTable
end
I expected to when the player leaves run createtable function and turn all the instances in replicated storage back into a dictionary with keys.
Why not just store extra information in your data table to help make it easy to convert back and forth. As an example, why not have your data look like this :
local ExampleData = {
-- hold onto your special "DON'T SAVE" values as simple keys in the table.
DONTSAVE_Values = {
Stamina = 0,
},
-- but every element under ReplicatedStorage will be used to represent an actual Instance.
ReplicatedStorage = {
-- store an array of Child elements rather than another map.
-- This is because Roblox allows you to have multiple children with the same name.
Name = "ReplicatedStorage",
Class = "ReplicatedStorage",
Properties = {},
Children = {
{
Name = "Level",
Class = "NumberValue",
Properties = {
Value = 0,
},
Children = {},
},
{
Name = "Ship",
Class = "Model",
Properties = {},
Children = {
{
-- add all of the other instances following the same pattern :
-- Name, Class, Properties, Children
},
},
},
}, -- end list of Children
}, -- end ReplicatedStorage element
};
You can create this table with a simple recursive function :
-- when given a Roblox instance, generate the dataTable for that element
local function getElementData(targetInstance)
local element = {
Name = targetInstance.Name,
Class = targetInstance.ClassName,
Properties = {},
Children = {},
}
-- add special case logic to pull out specific properties for certain classes
local c = targetInstance.ClassName
if c == "StringValue" then
element.Properties = { Value = targetInstance.Value }
-- elseif c == "ADD MORE CASES HERE" then
else
warn(string.format("Not sure how to parse information for %s", c))
end
-- iterate over the children and populate their data
for i, childInstance in ipairs(targetInstance:GetChildren()) do
table.insert( element.Children, getElementData(childInstance))
end
-- give the data back to the caller
return element
end
-- populate the table
local Data = {
ReplicatedStorage = getElementData(game.ReplicatedStorage)
}
Now Data.ReplicatedStorage.Children should have a data representation of the entire folder. You could even save this entire table as a string by passing it to HttpService:JSONEncode() if you wanted to.
When you're ready to convert these back into instances, use the data you've stored to give you enough information on how to recreate the elements :
local function recreateElement(tableData, parent)
-- special case ReplicatedStorage
if tableData.Class == "ReplicatedStorage" then
-- skip right to the children
for i, child in ipairs(tableData.Children) do
recreateElement(child, parent)
end
-- quick escape from this node
return
end
-- otherwise, just create elements from their data
local element = Instance.new(tableData.Class)
element.Name = tableData.Name
-- set all the saved properties
for k, v in pairs(tableData.Properties) do
element[k] = v
end
-- recreate all of the children of this element
for i, child in ipairs(tableData.Children) do
recreateElement(child, element)
end
-- put the element into the workspace
element.Parent = parent
end
-- populate the ReplicatedStorage from the stored data
recreateElement( Data.ReplicatedStorage, game.ReplicatedStorage)
You should be careful about how and when you choose to save this data. If you are playing a multiplayer game, you should be careful that this kind of logic only updates ReplicatedStorage for the first player to join the server. Otherwise, you run the risk of a player joining and overwriting everything that everyone else has been doing.
Since there isn't a way to iterate over properties of Roblox Instances, you'll have to manually update the getElementData function to properly store the information you care about for each type of object. Hopefully this helps!
If anyone else has this problem the solution I used was just to convert the instances strait into JSON format(I used the names as keys). so that way I can save it, and then when the player rejoins I just used JSONDecode to turn it into the dictionary I needed.
function DirToJSON(Player)
local NewData = RS:FindFirstChild(Player.UserId)
local JSONstring="{"
local function Recurse(Data)
for i, v in pairs(Data:GetChildren()) do
if v:IsA("Folder") then
if #v:GetChildren() < 1 then
if i == #Data:GetChildren()then
JSONstring=JSONstring..'"'..v.Name..'":[]'
else
JSONstring=JSONstring..'"'..v.Name..'":[],'
end
else
JSONstring=JSONstring..'"'..v.Name..'":{'
Recurse(v)
if i == #Data:GetChildren()then
JSONstring=JSONstring..'}'
else
JSONstring=JSONstring..'},'
end
end
else
if i == #Data:GetChildren()then
JSONstring=JSONstring..'"'..v.Name..'":"'..v.Value..'"'
else
JSONstring=JSONstring..'"'..v.Name..'":"'..v.Value..'",'
end
end
end
end
Recurse(NewData)
JSONstring = JSONstring.."}"
return(JSONstring)
end

I don't get Lua weak tables

Okay so I want to implement a cache generator, which returns a handle to me, but doesn't give me the actual data.
local module = {}
cache = {}
setmetatable(cache, { __mode = "k" })
function getItem(item)
local result = cache[item] or cacheItem(item)
return item
end
function cacheItem(item)
print("Caching item")
cache[item] = true
return cache[item]
end
function printCache()
for key, value in pairs(cache) do
print(key.name .. " and " .. value)
end
end
module.printCache = printCache
module.getItem = getItem
return module
But when I try to use it:
local module = require("./cache")
a = {
name = "Jimmie"
}
function foo()
local b = {
name = "Bobbie"
}
local h1 = module.getCachedItem(a)
module.getCachedItem(b)
local h3 = module.getCachedItem({ name = "Lenny" })
module.printCache()
end
foo()
module.printCache()
The first time around, I expect all names to be printed.
The second time around, I only expect "Jimmie" to be printed.
However all names are printed twice. lua -v returns 5.2.4.

Resources