I would like to combine two and more objects in the TabletopSimulator. Wenn I spawn the objects I can combine like this page https://kb.tabletopsimulator.com/host-guides/creating-states/. I would like this create with Lua. So I need help... I spawn the objects like here, but I didn`t get two objects with 2 states.
function SpawnLevel1(Obj1, ID)
CID = ID
spawnparamslvl = {
type = 'Custom_Assetbundle',
position = Obj1.getPosition(),
rotation = Obj1.getRotation(),
scale = {x=1, y=1, z=1},
}
paramslvl = {
assetbundle = data[CID].assetbundle,
type = 1,
material = 0,
}
Obj2 = spawnObject(spawnparamslvl)
obj_name = data[CID].display_name
Obj2.setDescription(obj_name)
Obj2.setName(obj_name)
Obj2.setCustomObject(paramslvl)
Obj1.addAttachment(Obj2).SetState(1)
end
function deploy(PID)
display_name = data[PID].display_name
spawnparams = {
type = 'Custom_Assetbundle',
position = self.getPosition(),
rotation = self.getRotation(),
scale = {x=1, y=1, z=1},
}
params = {
assetbundle = data[PID].assetbundle,
type = 0,
material = 0,
}
Spawning(spawnparams, params, display_name, PID)
end
function Spawning(spawnparams, params, display_name, PID)
Obj1 = spawnObject(spawnparamsmain)
ID = PID
Level1 = SpawnLevel1(Obj1, ID)
Obj1.setCustomObject(paramsmain)
Obj1.setName(display_name)
end
Thank you for your help
Radoan
You have to use spawnObjectData or spawnObjectJSON. The format of the "object data" follows the format of the save file.
Rather than hardcoding the large data structures needed to build an object, I'll use existing objects as templates. This is a common practice that's also reflected by the following common idiom for modifying an existing object:
local data = obj.getData()
-- Modify `data` here --
obj.destruct()
obj = spawnObjectData({ data = data })
The following are the relevant bits of "object data" for states:
{ -- Object data (current state)
-- ...
States = {
["1"] = { -- Object data (state 1)
--- ...
},
["3"] = { -- Object data (state 3)
-- ...
},
["4"] = { -- Object data (state 4)
-- ...
}
},
-- ...
}
So you could use this:
function combine_objects(base_obj, objs_to_add)
if not objs[1] then
return base_obj
end
local data = base_obj.getData()
if not data.States then
data.States = { }
end
local i = 1
while data.States[tostring(i)] do i = i + 1 end
i = i + 1 -- Skip current state.
while data.States[tostring(i)] do i = i + 1 end
for _, obj in ipairs(objs_to_add) do
data.States[tostring(i)] = obj.getData()
obj.destruct()
i = i + 1
end
base_obj.destruct()
return spawnObjectData({ data = data })
end
Related
I have been working on a survival game base on "Booga Booga" but i cant seem to find out how to load player data on the game. The data im trying to load is saved in the for loop that follows:
module.SaveData = function (player, DT)
local data_saved = {}
local setData = player.inventory.Inv:GetChildren()
for i, v in pairs(setData) do
table.insert(data_saved, {[v] = {
value = v.Value,
name = v.Name
}})
end
Data_Store:SetAsync(player.UserId, data_saved)
end
I've done multiple things to attempt to solve this problem
I've tried load with http service
I've already attempted loading the raw table
and I've tried to use a global data store instead
here is my code that loads the data as of now:
game.Players.PlayerAdded:Connect(function(plr)
CF.PlayerInventorySetup(plr) -- not relavent
p = plr -- not relavent
local PD =require(game.ServerScriptService.DataHandler)
local plrdata =PD.FetchData(plr)
for i, v in pairs(plrdata) do -- this is what im having trouble with
if not plr.inventory.Inv:FindFirstChild(v) then
local newint = Instance.new("NumberValue")
newint.Name = v.name -- the ouput says: string expected, got nil
newint.Value = v.value --
newint.Parent = plr.inventory.Inv
end
end
end)
I actually don't know wtf to do.
Before we talk about a solution, let's talk about what's happening when you save the data. Let's say for example, your inventory is a list of NumberValues like this :
Fish (value of 3)
Iron (value of 10)
Grass (value of 8)
Your FetchData function expects that the saved player data is formatted like this :
{
{ value = 3, name = "Fish" },
{ value = 10, name = "Iron" },
{ value = 8, name = "Grass" },
}
However, the result of the loop in the SaveData function would be this :
{
{ Fish(NumberValue) = { value=3, name="Fish" }},
{ Iron(NumberValue) = { value=10, name="Iron" }},
{ Grass(NumberValue) = { value=8, name="Grass" }},
}
On every step of the loop, you are pushing a new dictionary into the data_saved table.
The FetchData function expects that dictionary to have keys for "name" and "value". But, you've pushed that data one layer deeper, so those keys don't exist where the FetchData code expects them to and it throws errors.
So to fix your issue in the SetData function, remove the outer layer of that table, and just use the raw data.
table.insert(data_saved, {
value = v.Value,
name = v.Name
})
How do I get the full path to the required value in the table? I want to track changes in another table through a proxy table.
I understand that I need to use metatables and __index in it. But I haven't been able to come up with a tracker yet.
Sample table structure:
Objects = {
Panel = { layer = 1, x = 600, y = 328, w = 331, h = 491;
objects = {
label = { layer = 1, x = 0, y = 0, text = 'header' };
Window = { layer = 2, x = 400, y = 100, w = 100, h = 100;
objects = {
label = { layer = 1, x = 0, y = 0, text = 'lorem ipsum dorem' };
};
};
};
};
};
Path: Objects.Panel.objects.Window.objects.label.text
I tried to create a metatable for each of the tables and collect the result of each call to __index into a table in order to roughly understand which key and value were retrieved or changed in order to synchronize these values with other tables.
This will prove itself to be horrendously slow and memory inefficient. Anyway, you were right on the track: proxy and handle __index and __newindex metamethods to your liking. This being said you also need to track the state of the proxy somehow.
You can try to hide it with some closures and upvalues but the easy way is to store the information directly in the proxy tables:
function make_tracker (o, name)
local mt = {}
mt.__index = function (proxy, key)
local path = {unpack(rawget(proxy, "__path"))} -- Stupid shallow copy
local object = rawget(proxy, "__to")
table.insert(path, key)
if type(object[key]) == "table" then
return setmetatable({__to = object[key], __path = path}, mt)
else
return table.concat(path, ".") .. " = " .. tostring(object[key])
end
end
return setmetatable({__to = o, __path = {name}}, mt)
end
__to fields indicates what proxy should point to and __path is there to cover fields we have trespassed so far. It does a shallow copy, so that one can use subproxies with local variables. name parameter is there to initialize the name of the first table, as you just simply can't know that. You use it like this:
local tObjects = make_tracker(Objects, "Objects")
local subproxy = tObjects.Panel.objects.Window
print(subproxy.objects.label.text)
print(tObjects.Panel.objects.label.text)
print(subproxy.x)
-- prints:
-- Objects.Panel.objects.Window.objects.label.text = lorem ipsum dorem
-- Objects.Panel.objects.label.text = header
-- Objects.Panel.objects.Window.x = 400
Of course, I doubt that appending the path to the original value is what you want. Modify insides of else block:
return table.concat(path, ".") .. " = " .. tostring(object[key])
according to your needs, e.g:
register_tracked_path(table.concat(path, "."))
return object[key]
If you want to handle modification of values you need to extend the metatable with similar __newindex.
I have a table called "inventory", initialized like so:
inventory = {}
inventory[1] = { qty = 0 }
I want to add more data to this table, at the index 1, eg:
val = { id = "example" }
inventory[1] = inventory[1], val
Is there a way I can do this while preserving the data that is already in this table at this index?
The final result should be something like:
inventory[1] = { qty = 0, id = "example" }
But if I try to print the id after trying this code I get:
print(inventory[1].id) == Nil
inventory[1].id = "example"
or
inventory[1]["id"] = "example"
or
this other SO answer with first_table being inventory[1] and second_table being val.
FWIW, you'd need 2 variables on the left side of the expression for inventory[1] = inventory[1], val to work: a, b = x, y.
You need to take the first key in the table and use it:
local inventory = {}
inventory[1] = { qty = 0 }
local val = { id = "example" }
--
local KeyName = next(val)
inventory[1][KeyName] = val[KeyName]
print(inventory[1][KeyName])
-- or
print(inventory[1].id)
I'm trying to index a parent object by using its identifier, but it returns nil instead of the object, so it throws a error when executing the script.
local mapit = {
...
ground = function(x, y, w, h, data)
...
local id = 0
-- mapit is nil in this block
for i = 0, #mapit.data.ids do
if id ~= i then
id = id + 1
end
end
...
end,
data = {
ids = {}
}
...
}
local myRect = mapit.ground(400, 100, 600, 100)
In Lua, locals are not in scope on the right hand of their initializer, so your closure refers to a global named mapit instead.
Declare the local first, then assign to it.
local mapit
mapit = { ... }
I'm writing a program with lua. I have data that organized in the following way:
t= {
i1 = {
p1 = { value = "i1p1" },
p2 = { value = "i1p2" },
-- etc
pm = { value = "i1pm" }
},
i2 = {
p1 = { value = "i2p1" },
p2 = { value = "i2p2" },
-- etc
pm = { value = "i2pm" }
},
im = {
p1 = { value = "imp1" },
p2 = { value = "imp2" },
-- etc
pm = { value = "impm" }
}
} --(inner tables)
In another way each group of data is indexed by two variables i&p,I am sure that the data is kept correctly but I want a way to print the data from their tables because I won't know the values of i and p to iterate over them or even the numbers n & m any body know how to do this with lua?
If you know the depth of your nested (inner) tables, you can iterate explicitly to that depth:
for k1,v1 in pairs(t) do
for k2,v2 in pairs(v1) do
for k3, v3 in pairs(v2) do
print(k3, ":", v3)
end
end
end
Alternatively, you can recursively iterate into your nested structure:
function print_tbl(tbl)
if type(tbl) == "table" then
for _,v in pairs(tbl) do
print_tbl(v)
end
else
print(tbl)
end
end
print_tbl(t)
This is just an example. If your tables contain functions, contains userdata, or your nesting has cycles, you'll need a different approach. Take a look at table serialization on the Lua user wiki. Serialization requires sensible handling of tables with nesting, functions, cycles, etc. You may be able to use lessons learned on your data.