-
Notifications
You must be signed in to change notification settings - Fork 8
/
Sync.lua
375 lines (345 loc) · 10.9 KB
/
Sync.lua
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
local HttpService = game:GetService("HttpService")
local backend_url = "http://localhost:13032"
local function ends_with(str, ending)
return ending == "" or str:sub(-#ending) == ending
end
local function is_blox_script(filename)
return ends_with(filename, ".blox")
end
local max_depth = 3
function RecursiveListEverything(children: Array, instance: Instance, depth: number, path: string)
if depth > max_depth then
return
end
for _, child: Instance in ipairs(instance:GetChildren()) do
if child.ClassName == "StringValue" then
continue
end
if depth == max_depth and child.ClassName ~= "Script" and child.ClassName ~= "LocalScript" then
continue
end
local child_node = {
text=child.Name,
type=child.ClassName,
path=path .. "/" .. child.Name
}
local grand_children = child:GetChildren()
if #grand_children > 0 then
child_node.children = {}
RecursiveListEverything(child_node.children, child, depth + 1, path .. "/" .. child.Name)
end
table.insert(children, child_node)
end
end
function ListEverything()
local everything = {}
local workspace_children = {}
RecursiveListEverything(workspace_children, game.Workspace, 1, "Workspace")
table.insert(everything, {
text="Workspace",
type=game.Workspace.ClassName,
children=workspace_children,
path="Workspace"
})
local starter_player_children = {}
local starter_player = game:GetService("StarterPlayer")
RecursiveListEverything(starter_player_children, starter_player, 1, "StarterPlayer")
table.insert(everything, {
text="StarterPlayer",
type=starter_player.ClassName,
children=starter_player_children,
path="StarterPlayer"
})
local starter_pack_children = {}
local starter_pack = game:GetService("StarterPack")
RecursiveListEverything(starter_pack_children, starter_pack, 1, "StarterPack")
table.insert(everything, {
text="StarterPack",
type=starter_pack.ClassName,
children=starter_pack_children,
path="StarterPack"
})
local server_storage = game:GetService("ServerStorage")
local server_storage_children = {}
RecursiveListEverything(server_storage_children, server_storage, 1, "ServerStorage")
table.insert(everything, {
text="ServerStorage",
type=server_storage.ClassName,
children=server_storage_children,
path="ServerStorage"
})
local server_script_service = game:GetService("ServerScriptService")
local server_script_service_children = {}
RecursiveListEverything(server_script_service_children, server_script_service, 1, "ServerScriptService")
table.insert(everything, {
text="ServerScriptService",
type=server_script_service.ClassName,
children=server_script_service_children,
path="ServerScriptService"
})
local starter_gui = game:GetService("StarterGui")
local starter_gui_children = {}
RecursiveListEverything(starter_gui_children, starter_gui, 1, "StarterGui")
table.insert(everything, {
text="StarterGui",
type=starter_gui.ClassName,
children=starter_gui_children,
path="StarterGui"
})
return {
items=everything
}
end
function PopPath(path: string): (string, string)
local i = path:find("/")
if not i then
return path, ""
end
return path:sub(0, i - 1), path:sub(i + 1)
end
function RecursiveFindInstance(path: string, instance: Instance): Instance
if path == "" then
return instance
end
local child_name, child_path = PopPath(path)
local child = instance:FindFirstChild(child_name)
if child then
return RecursiveFindInstance(child_path, child)
end
end
function FindInstance(path: string): Instance
local root_container, sub_path = PopPath(path)
if root_container == "Workspace" then
return RecursiveFindInstance(sub_path, game.Workspace)
else
local service = game:GetService(root_container)
return RecursiveFindInstance(sub_path, service)
end
end
function SaveBloxScript(name: string, value: string, path: string)
if is_blox_script(name) then
local container = FindInstance(path)
local script = container:FindFirstChild(name)
if not script then
script = Instance.new("StringValue", container)
script.Name = name
elseif not script:IsA("StringValue") then
script:Destroy()
script = Instance.new("StringValue", container)
end
script.Value = value
end
end
function SaveLocalScript(name: string, value: string, path: string)
if not is_blox_script(name) then
local container = FindInstance(path)
local script = container:FindFirstChild(name)
if not script then
script = Instance.new("LocalScript", container)
script.Name = name
SendMessage("bloxcode", "LocalScriptCreated", {
name=name,
path=path
})
elseif not script:IsA("LocalScript") then
script:Destroy()
script = Instance.new("LocalScript", container)
script.Name = name
SendMessage("bloxcode", "LocalScriptCreated", {
name=name,
path=path
})
end
script.Source = value
end
end
function SaveScript(name: string, value: string, path: string)
if not is_blox_script(name) then
local container = FindInstance(path)
local script = container:FindFirstChild(name)
if not script then
script = Instance.new("Script", container)
script.Name = name
SendMessage("bloxcode", "ScriptCreated", {
name=name,
path=path
})
elseif not script:IsA("Script") then
script:Destroy()
script = Instance.new("Script", container)
script.Name = name
SendMessage("bloxcode", "ScriptCreated", {
name=name,
path=path
})
end
script.Source = value
end
end
function GetBloxScript(name: string, path: string)
local result = ""
if is_blox_script(name) then
local container = FindInstance(path)
local script = container:FindFirstChild(name)
if script:IsA("StringValue") then
result = script.Value
end
end
return {
result=result,
name=name,
path=path
}
end
function DeleteBloxScript(name: string, path: string)
if not is_blox_script(name) then
return
end
local container = FindInstance(path)
local blox_script = container:FindFirstChild(name)
blox_script:Destroy()
SendMessage("bloxcode", "BloxScriptDeleted", {name=name, path=path})
end
function DeleteLuaScript(name: string, path: string)
if is_blox_script(name) then
return
end
local container = FindInstance(path)
local lua_script = container:FindFirstChild(name)
lua_script:Destroy()
SendMessage("bloxcode", "LuaScriptDeleted", {name=name, path=path})
end
function SendMessage(queueName: string, event_type: string, event_data: any)
local url = backend_url .. "/messages/" .. queueName
HttpService:PostAsync(url, HttpService:JSONEncode({
event_type=event_type,
event_data=event_data,
}), "ApplicationJson", false)
end
function GetMessages(queueName: string)
local url = backend_url .. "/messages/" .. queueName
local response = HttpService:GetAsync(url, false)
return HttpService:JSONDecode(response)
end
function killPreviousPlugin()
local lastBloxUpdate = GetLastBloxUpdate()
if os.time() - lastBloxUpdate > 50 then
return true
end
local success = false
pcall(function ()
SendMessage("studio","kill")
success = true
end)
if not success then
return success
end
wait(5)
-- drain the queue if no previous plugin was running
local resp = GetMessages("studio")
return success
end
function GetLastBloxUpdate()
local serverStorage = game:GetService("ReplicatedStorage")
local lastUpdateValue: NumberValue = serverStorage:FindFirstChild("lastBloxUpdate")
if lastUpdateValue == nil then
return 0
end
return lastUpdateValue.Value
end
-- accepts optional number
function SaveLastBloxUpdate(time: number)
local replicatedStorage = game:GetService("ReplicatedStorage")
local lastUpdateValue: NumberValue = replicatedStorage:FindFirstChild("lastBloxUpdate")
if lastUpdateValue == nil then
lastUpdateValue = Instance.new("NumberValue", replicatedStorage)
lastUpdateValue.Name = "lastBloxUpdate"
end
if time == nil then
time = os.time()
end
lastUpdateValue.Value = time
end
function ClearLastBloxUpdate()
local replicatedStorage = game:GetService("ReplicatedStorage")
local lastUpdateValue: NumberValue = replicatedStorage:FindFirstChild("lastBloxUpdate")
if lastUpdateValue == nil then
lastUpdateValue = Instance.new("NumberValue", replicatedStorage)
lastUpdateValue.Name = "lastBloxUpdate"
end
lastUpdateValue.Value = 0
end
function Sync()
print("Bloxcode sync script starting up")
-- If we are starting back up after starting or stopping test,
-- we can reuse the connection info. Check last update time from
-- bloxcode studio to see if a new connection should be made.
local lastBloxUpdate = GetLastBloxUpdate()
local running = 1
while running
do
-- local response
local data
local success, err = pcall(function ()
data = GetMessages("studio")
for _, message in ipairs(data.messages) do
if lastBloxUpdate == 0 then
print("Bloxcode connected")
end
lastBloxUpdate = os.time()
SaveLastBloxUpdate(lastBloxUpdate)
local success, err = pcall(function()
print("Received " .. message.event_type)
if message.event_type == "ping" then
SendMessage("bloxcode", "pong", nil)
elseif message.event_type == "kill" then
print("Bloxcode sync script shutting down")
running = 0
elseif message.event_type == "GetBloxScript" then
if message.event_data and message.event_data.name and message.event_data.path then
local resp = GetBloxScript(message.event_data.name, message.event_data.path)
SendMessage("bloxcode", "BloxScriptResult", resp)
end
elseif message.event_type == "SaveBloxScript" then
if message.event_data and message.event_data.name and message.event_data.value and message.event_data.path then
SaveBloxScript(message.event_data.name, message.event_data.value, message.event_data.path)
end
elseif message.event_type == "SaveScript" then
if message.event_data and message.event_data.name and message.event_data.path then
SaveScript(message.event_data.name, message.event_data.value or "", message.event_data.path)
end
elseif message.event_type == "SaveLocalScript" then
if message.event_data and message.event_data.name and message.event_data.path then
SaveLocalScript(message.event_data.name, message.event_data.value or "", message.event_data.path)
end
elseif message.event_type == "DeleteBloxScript" then
if message.event_data and message.event_data.name and message.event_data.path then
DeleteBloxScript(message.event_data.name, message.event_data.path)
end
elseif message.event_type == "DeleteLuaScript" then
if message.event_data and message.event_data.name and message.event_data.path then
DeleteLuaScript(message.event_data.name, message.event_data.path)
end
elseif message.event_type == "ListEverything" then
local result = ListEverything()
SendMessage("bloxcode", "ListEverythingResult", result)
end
end)
if not success then
print(err)
end
end
end)
if not success then
if lastBloxUpdate ~= 0 then
print("Bloxcode disconnected")
lastBloxUpdate = 0
end
SaveLastBloxUpdate(lastBloxUpdate)
end
task.wait(1)
end
end
if killPreviousPlugin() then
task.spawn(Sync)
end