Saving Colors
This is one example of how you could handle saving colors for your players so that they persist.
What's the point of allowing the players to change colors of an object if they don't save?
Some important things to note about this example:
- Enable
saving_enabled
on the Advanced_Color_Picker_Save_Load_Client
script. It is disabled by default.
- Your mesh root needs to be networked and have a networked property called
data
. See the example by looking at Mesh Root
.
Player Data has a limit of how much can be stored, so if you are letting the player color the world, expect to hit the limit.
For simple objects where it may be a hat, or some clothing, then this should be fine.
This example stores an object that is built up of the mesh ids and the color picked by the player. The data is sent to a server script which handles saving to Player Storage. When a player logs back in, we convert the data into a string and use a networked property so we can get it to the client.
See Storage for more information.
Client Script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 | local mesh_root = script:GetCustomProperty("mesh_root"):WaitForObject()
local enable_saving = script:GetCustomProperty("enable_saving")
-- If saving is enabled, then we broadcast to the server when a color is changed.
-- Ideally it would be nice not to have to broadcast every time, but if we try to send
-- all the colors and mesh ids to the server, we will hit either broadcast rate limits,
-- or data limits.
if(enable_saving) then
Events.Connect("on_color_picker_object_changed", function(id, color)
local a, j = string.find(id, ":")
Events.BroadcastToServer("on_color_picker_save", string.sub(id, 0, j - 1), color)
end)
end
-- Here we listen for a change on the networked property. We handle turning the
-- data back into a table so we can then apply the colors to the mesh.
mesh_root.networkedPropertyChangedEvent:Connect(function(obj, prop)
if(prop == "data") then
local data = unstringify_data(mesh_root:GetCustomProperty(prop))
local objs = get_objects(mesh_root, {})
for k, v in pairs(data) do
for o = 1, #objs do
local a, j = string.find(objs[o].id, ":")
local id = string.sub(objs[o].id, 0, j - 1)
if(id == k) then
objs[o]:SetColor(Color.New(v[1], v[2], v[3]))
end
end
end
end
end)
function get_objects(r, objs)
local children = r:GetChildren()
for c = 1, #children do
local child = children[c]
if(not child:GetCustomProperty("ignore_color_picker")) then
if(child:IsA("StaticMesh")) then
table.insert(objs, #objs + 1, child)
elseif(child:IsA("Folder")) then
objs = get_objects(child, objs)
end
end
end
return objs
end
function unstringify_data(str)
local obj = {}
local count = 1
local last_key = nil
for s in string.gmatch(str, "([^|]+)") do
if(s ~= "") then
if(count == 1) then
last_key = s
obj[s] = {}
end
if(count > 1) then
obj[last_key][count - 1] = s
end
count = count + 1
if(count > 4) then
count = 1
end
end
end
return obj
end
|
Server Script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | local mesh_root = script:GetCustomProperty("mesh_root"):WaitForObject()
local enable_loading = script:GetCustomProperty("enable_loading")
-- Turns a table of that was stored in the player storage into a string so we can
-- set the networked property value.
function stringify_data(data)
local str = {}
for k, v in pairs(data) do
table.insert(str, #str + 1, string.format("|%s|%.2f|%.2f|%.2f", k, v.r, v.g, v.b))
end
return table.concat(str)
end
-- When player joins the game, grab their data, turn it into a string, and send it to them
-- via a networked property.
Game.playerJoinedEvent:Connect(function(player)
local data = Storage.GetPlayerData(player) or {}
mesh_root:SetNetworkedCustomProperty("data", stringify_data(data))
end)
-- Handles saving the color to storage for the player.
Events.ConnectForPlayer("on_color_picker_save", function(player, id, color)
local data = Storage.GetPlayerData(player) or {}
data[id] = color
Storage.SetPlayerData(player, data)
end)
|