· 5 years ago · Jul 25, 2020, 04:36 PM
1--[[
2
3 -------
4 Voidage
5 -------
6
7]]--
8
9local HttpService = game:GetService("HttpService");
10
11local IsServer = game:GetService("RunService"):IsServer();
12
13local ForgedFolder;
14
15if not IsServer then
16 ForgedFolder = game.Players.LocalPlayer.PlayerScripts:WaitForChild("Forged");
17else
18 ForgedFolder = game:GetService("ServerScriptService"):WaitForChild("Forged");
19end
20
21-- Roblox locations (folders)
22local Locations = {};
23if not IsServer then
24 Locations.Controllers = ForgedFolder:WaitForChild("Controllers");
25 Locations.Services = {};
26else
27 Locations.Services = ForgedFolder:WaitForChild("Services");
28end
29Locations.Objects = ForgedFolder:WaitForChild("Objects");
30Locations.Modules = ForgedFolder:WaitForChild("Modules");
31
32-- Shared Roblox locations.
33Locations.Shared = game:GetService("ReplicatedStorage"):WaitForChild("Forged"):WaitForChild("Shared");
34Locations.Shared_Objects = Locations.Shared:WaitForChild("Objects");
35Locations.Shared_Modules = Locations.Shared:WaitForChild("Modules");
36
37if IsServer then
38 Locations.Remotes = Instance.new("Folder", Locations.Shared);
39 Locations.Remotes.Name = "Remotes";
40else
41 Locations.Remotes = Locations.Shared:WaitForChild("Remotes");
42end
43
44-- Modules to be used by Forged Loader.
45local Maid = require(Locations.Shared_Modules:WaitForChild("Maid"));
46local Event = require(Locations.Shared_Modules:WaitForChild("Event"));
47local Thread = require(Locations.Shared_Modules:WaitForChild("Thread"));
48local StringUtil = require(Locations.Shared_Modules:WaitForChild("StringUtil"));
49
50-- The table that is indexed by wrapped modules.
51local Forged = {};
52Forged.Controllers = {};
53Forged.Objects = {};
54Forged.Modules = {};
55Forged.Services = {};
56
57Forged.Globals = {}; -- Globally registered variables.
58Forged.Registry = {};
59
60-- Shared modules
61Forged.Shared = {};
62Forged.Shared.Objects = {};
63Forged.Shared.Modules = {};
64
65Forged.ObjectCreated = Event.new();
66
67local ObjectCreatedServer;
68
69-- Local variables
70if not IsServer then
71 Forged.Player = game.Players.LocalPlayer;
72end
73
74Forged.Total_Loaded = {};
75Forged.Waiting_Start = {};
76Forged.Waiting_Init = {};
77
78-- Booleans that keep track of what has been loaded,
79Forged.Modules_Loaded = false;
80Forged.Controllers_Loaded = false;
81Forged.Objects_Loaded = false;
82Forged.Services_Loaded = false;
83
84local function index(t, index)
85 if rawget(t, index) then
86 return rawget(t, index);
87 elseif Forged[index] then
88 return rawget(Forged, index);
89 elseif rawget(t, "_Is_Object") then
90 --if rawget(t.Values, index) then return rawget(t.Values, index) end;
91 for i,v in pairs(t._Components) do -- First check components...
92 if rawget(v, index) then
93 return rawget(v, index);
94 end
95 end
96 if rawget(t, index) then return rawget(t, index) end;
97 if rawget(t, "Wrapped") ~= nil then -- Maybe its a part method or property?
98 local result;
99 local success;
100 success, result = pcall(function()
101 result = t.Wrapped[index];
102 end)
103 if success then
104 if typeof(t.Wrapped[index]) ~= "function" then
105 return t.Wrapped[index];
106 else
107 return function()
108 t.Wrapped[index](t.Wrapped);
109 end
110 end
111 end
112 end
113 return nil;
114 end
115end
116
117Forged.__index = index;
118
119local function newindex(a,b,c)
120 if rawget(a, "Wrapped") ~= nil then
121 local result;
122 local success;
123 success, result = pcall(function()
124 result = a.Wrapped[b];
125 end)
126 if success then
127 a.Wrapped[b] = c;
128 return;
129 end
130 end
131 if a._Properties then
132 if a._Properties[b] ~= nil then -- If this is a registered property, then change it and fire event.
133 if a._Clamps[b] then
134 if c < a._Clamps[b][1] then
135 c = a._Clamps[b][1];
136 end
137 if c > a._Clamps[b][2] then
138 c = a._Clamps[b][2];
139 end
140 end
141 a._PropertyEvents[b]:Fire(c, a._Properties[b]);
142 rawset(a._Properties, b, c);
143 return;
144 end
145 end
146 if rawget(a, "_Is_Object") == true then
147 a.Changed:Fire(b, c, a[b]);
148 end
149 rawset(a,b,c);
150end
151
152Forged.__newindex = newindex;
153
154function Forged:Log(...)
155 local str = "";
156 for i,v in pairs({...}) do
157 str = str .. v;
158 end
159 print(str);
160end
161
162function Forged:GetService(ServiceName)
163 if typeof(ServiceName) == "string" then
164 warn("Deprecated - use self.Services." .. ServiceName);
165 end
166 return nil;
167end
168
169-- Allows a module (table) to work with Forged Framework
170function Forged:WrapModule(t, modulescript, skipInit)
171 t._PropertyEvents = {};
172 t._Properties = {};
173 t._Clamps = {};
174 setmetatable(t, Forged);
175 if skipInit == nil then
176 skipInit = false;
177 end
178 if skipInit == false then
179 if t.Init then
180 t:Init();
181 end
182 end
183 return t;
184end
185
186-- Register a global variable which other scripts can access.
187function Forged:RegisterGlobal(PropertyName)
188 if self[PropertyName] then
189 Forged.Globals[PropertyName] = self[PropertyName];
190 end
191end
192
193-- Register a property which fires an event when change.
194function Forged:RegisterProperty(PropertyName)
195 self._Properties[PropertyName] = false;
196 self._PropertyEvents[PropertyName] = Event.new();
197 return {
198 Clamp = function(_, min, max)
199 self._Clamps[PropertyName] = {min, max};
200 end;
201 }
202end
203
204-- Get the event from a registered property.
205function Forged:GetPropertyChangedEvent(PropertyName)
206 if self._PropertyEvents[PropertyName] then
207 return self._PropertyEvents[PropertyName];
208 end
209end
210
211-- Create a new registry.
212function Forged:CreateRegistry(RegistryName)
213 if Forged.Registry[RegistryName] then warn("Registry " .. RegistryName .. " already exists.") return end;
214 Forged.Registry[RegistryName] = {};
215end
216
217-- Remove a registry
218function Forged:RemoteRegistry(RegistryName)
219 if Forged.Registry[RegistryName] then
220 Forged.Registry[RegistryName] = nil;
221 else
222 warn("Attempt to remove registry " .. RegistryName .. " that doesn't exist.");
223 end
224end
225
226-- Get a registry.
227function Forged:GetRegistry(RegistryName)
228 return Forged.Registry[RegistryName];
229end
230
231function Forged:AddTableToRegistry(Table, RegistryName)
232 local registry = Forged:GetRegistry(RegistryName);
233 table.insert(registry, Table);
234end
235
236-- Create add something to the registry.
237function Forged:AddToRegistry(RegistryName)
238 local registry = Forged:GetRegistry(RegistryName);
239 table.insert(registry, self);
240end
241
242
243local function SearchSplit(STR, Location)
244 local found;
245 local iteration;
246
247 local function Search(Location, splitTable, lastSplit, iter)
248 if splitTable[iter] == lastSplit then
249 found = Location[lastSplit];
250 return found;
251 end
252 local f = Location:FindFirstChild(splitTable[iter]);
253 if f then
254 iter = iter + 1;
255 Search(f, splitTable, lastSplit, iter);
256 end
257 end
258
259 local split = string.split(STR, "/");
260 local totalSplits = #split;
261 local lastSplit = split[#split];
262
263 Search(Location, split, lastSplit, 1);
264 return found;
265end
266
267function Forged:GetSharedResource(ResourceName)
268 local found = SearchSplit(ResourceName, Locations.Shared.Resources);
269 return found;
270end
271
272function Forged:GetResource(ResourceName)
273 local found = SearchSplit(ResourceName, ForgedFolder.Resources);
274 return found;
275end
276
277-- Remove from registry
278function Forged:RemoveFromRegistry(RegistryName)
279 local registry = Forged:GetRegistry(RegistryName);
280 if registry then
281 for i,v in pairs(registry) do
282 if v._ID == self._ID then
283 table.remove(registry, i);
284 end
285 end
286 else
287 warn("Attempt to remove object from registry " .. RegistryName .. " that doesn't exist.");
288 end
289end
290
291
292-- Server: Create a new event for the client to connect to.
293function Forged:RegisterClientEvent(EventName)
294 local newclientevent = Instance.new("RemoteEvent");
295 local servicefolder = Locations.Remotes:FindFirstChild(self._Name);
296 if not servicefolder then
297 servicefolder = Instance.new("Folder", Locations.Remotes);
298 servicefolder.Name = self._Name;
299 end
300 local newclientevent = Instance.new("RemoteEvent", servicefolder);
301 newclientevent.Name = "ForgedEvent_" .. EventName;
302end
303
304-- Server: Fire a client event
305function Forged:FireClientEvent(EventName, Player, ...)
306 if Locations.Remotes[self._Name]:FindFirstChild("ForgedEvent_" .. EventName) then
307 Locations.Remotes[self._Name]["ForgedEvent_" .. EventName]:FireClient(Player, table.unpack{...});
308 end
309end
310
311-- Server: Fire a client event for ALL clients
312function Forged:FireAllClientsEvent(EventName, ...)
313 --local callingscriptname = getfenv(2).script.Name;
314 if Locations.Remotes[self._Name]:FindFirstChild("ForgedEvent_" .. EventName) then
315 Locations.Remotes[self._Name]["ForgedEvent_" .. EventName]:FireAllClients(table.unpack({...}))
316 end
317end
318
319
320-- Create a new remote.
321local function NewRemote(ServiceName, RemoteName)
322 local servicefolder = Locations.Remotes:FindFirstChild(ServiceName)
323 if not servicefolder then
324 servicefolder = Instance.new("Folder", Locations.Remotes);
325 servicefolder.Name = ServiceName;
326 end
327 local newremote = Instance.new("RemoteFunction");
328 newremote.Name = RemoteName;
329 newremote.Parent = servicefolder;
330 return newremote;
331end
332
333
334local function SetupNetworking(ServiceName, Table)
335 if IsServer then -- Create a metable for the .Client table on the service.
336 if Table.Client then
337 for i,v in pairs(Table.Client) do
338 if typeof(v) == "function" then
339 local newnetworkremote = NewRemote(ServiceName, i);
340 function newnetworkremote.OnServerInvoke(...)
341 local args = {...}
342 local player = args[1];
343 local res = v(player, ...);
344 return res;
345 end
346 end
347 end
348 end
349 end
350end
351
352local function LoadControllersAndServicesToTable(Location, Table)
353 for i,v in pairs(Location:GetChildren()) do
354 if v:IsA("ModuleScript") then
355 local req = require(v);
356 if IsServer then SetupNetworking(v.Name, req) end; -- Setup .Client for Networking.
357 req._Is_Object = false;
358 Table[v.Name] = req;
359 if req.Init then
360 Forged.Waiting_Init[v.Name] = req;
361 end
362 if req.Start then
363 Forged.Waiting_Start[v.Name] = req;
364 end
365 Forged:WrapModule(req, v, true);
366 req._Name = v.Name;
367 elseif v:IsA("Folder") then
368 Table[v.Name] = {};
369 LoadControllersAndServicesToTable(v, Table[v.Name]);
370 end
371 end
372end
373
374local function LoadModulesInLocationToTable(Location, Table)
375 setmetatable(Table, {__index = function(t, i)
376 if Location[i] then
377 local TargetObject = Location[i];
378 if TargetObject:IsA("ModuleScript") then
379 local req = require(TargetObject);
380 Forged:WrapModule(req, TargetObject, false);
381 req._Is_Object = false;
382 Table[TargetObject.Name] = req;
383 return req;
384 elseif TargetObject:IsA("Folder") then
385 Table[TargetObject.Name] = {};
386 LoadModulesInLocationToTable(TargetObject, Table[TargetObject.Name]);
387 return Table[TargetObject.Name];
388 end
389 end
390 end})
391end
392
393
394local function LoadObjectsInLocationToTable(Location, Table)
395 setmetatable(Table, {__index = function(t, i)
396 local mod = Location[i];
397 if Location[i] then
398 local TargetObject = Location[i];
399 if TargetObject:IsA("ModuleScript") then
400 local req = require(TargetObject);
401
402 Forged:WrapModule(req, TargetObject, true);
403
404 for i,v in pairs(TargetObject:GetChildren()) do
405 if v:IsA("ModuleScript") then
406 local childreq = require(v);
407 Forged:WrapModule(childreq, v, true);
408 req[v.Name] = childreq;
409 end
410 end
411
412 req._Components = {};
413 req._Interfaces = {};
414 req._Name = TargetObject.Name;
415
416 -- Add a class to this objects component list.
417 function req:Super(Class, ...)
418 table.insert(req._Components, Class);
419 --table.insert(req._Components, Class.new(...));
420 if #Class._Components >= 1 then
421 for i,v in pairs(Class._Components) do
422 req:Super(v);
423 end
424 end
425 end
426
427 -- Interfaces
428 function req:Implements(Class, ...)
429 if (Class.Interface) then
430 if (Class.Interface == true) then
431 table.insert(req._Interfaces, Class);
432 if (Class.Contract) then
433 for i,v in pairs(Class.Contract) do
434 if req[v] == nil then
435 error(req._Name .. " must define all methods or properties from any interfaces it implements.");
436 end
437 end
438 end
439 end
440 end
441 end
442
443 function req:Extends(Class, ...)
444 req:Super(Class, ...);
445 end
446
447
448 if req.Init then
449 req:Init();
450 end
451
452
453 -- A new instance of this Object.
454 function req.new(userArgs, ...)
455 local newobject = {};
456
457 setmetatable(newobject, Forged);
458
459 for i,v in pairs(req) do
460 newobject[i] = v;
461 end
462
463 newobject.__index = Forged.__index;
464 newobject.__newindex = Forged.__newindex;
465
466 newobject._Maid = Maid.new();
467
468 newobject.Loaded = Event.new();
469 newobject.Changed = Event.new();
470 newobject.ReplicationChanged = Event.new();
471
472 newobject._Name = TargetObject.Name;
473 newobject._ID = HttpService:GenerateGUID(false);
474 newobject._Created_Ran = false;
475 newobject._Is_Object = true;
476 newobject.Wrapped = nil;
477 newobject._Loaded = false;
478 newobject._Replicated = nil;
479
480 -- Everything the maid has will be cleaned on Object:Destroy()
481 function newobject:GiveMaid(Thing)
482 spawn(function()
483 newobject._Maid:GiveTask(Thing);
484 end)
485 end
486
487 -- Call maid cleaning on this object.
488 function newobject:Destroy()
489 newobject._Maid:DoCleaning();
490 end
491
492 -- Attach a ROBLOX instance to this object.
493 -- In the case this Instance is destroyed, the Object will be cleaned up.
494 -- If the Object is destroyed, the wrapped instance will also be destroyed.
495 function newobject:Wrap(RoInstance)
496 newobject.Wrapped = RoInstance;
497 newobject:GiveMaid(RoInstance);
498 -- Detect when this Roblox Instance is destroyed.
499 if RoInstance.Parent then
500 RoInstance.Parent.ChildRemoved:Connect(function(Child)
501 if Child == RoInstance then
502 newobject:Destroy();
503 end
504 end)
505 end
506 end
507
508 function newobject:Replicate(Player)
509 if IsServer then
510 if newobject._Replicated == nil then
511 ObjectCreatedServer:FireClient(Player, TargetObject.Parent, newobject._Name, newobject);
512 end
513 end
514 end
515
516 if newobject.Created then
517 if userArgs then
518 newobject:Created(table.unpack(userArgs));
519 end
520 end
521
522 -- If the object contains component classes,
523 -- then go through and fire the Supered function on them.
524 if #req._Components >= 1 then
525 for i,v in pairs(req._Components) do
526 if v.Supered then
527 v:Supered(newobject, ...);
528 end
529 end
530 end
531
532 newobject.Loaded:Fire();
533 newobject._Loaded = true;
534
535 --Forged.ObjectCreated:Fire(newobject);
536
537 return newobject;
538 end
539
540 return req; -- Return the object.
541 elseif TargetObject:IsA("Folder") then
542 Table[TargetObject.Name] = {};
543 LoadObjectsInLocationToTable(TargetObject, Table[TargetObject.Name]);
544 return Table[TargetObject.Name];
545 end
546 end
547 end})
548
549end
550
551-- Function that injects methods into the client .Services
552local function ClientLoadNetworking()
553 if not IsServer then
554 for i,v in pairs(Locations.Remotes:GetChildren()) do
555 Forged.Services[v.Name] = {};
556 for a,b in pairs(v:GetChildren()) do
557 if b:IsA("RemoteFunction") or b:IsA("RemoteEvent") then
558 if not StringUtil.StartsWith(b.Name, "ForgedEvent_") then
559 Forged.Services[v.Name][b.Name] = function(Player, ...)
560 local lol = b:InvokeServer(...);
561 return lol;
562 end;
563 else
564 local actualName = string.split(b.Name, "_");
565 actualName = actualName[2];
566 Forged.Services[v.Name][actualName] = Event.new();
567 b.OnClientEvent:Connect(function(...)
568 Forged.Services[v.Name][actualName]:Fire(...);
569 end)
570 end
571 end
572 end
573 end
574 end
575end
576
577local function InitServicesAndControllers()
578 for i,v in pairs(Forged.Waiting_Init) do
579 v:Init();
580 end
581end
582
583local function StartServicesAndControllers()
584 for i,v in pairs(Forged.Waiting_Start) do
585 Thread.Spawn(function()
586 v:Start();
587 end)
588 end
589end
590
591-- Create the Rap event to replicate objects from server to client.
592if IsServer then
593 --ObjectCreatedServer = NewRemote("Replication", "Rep");
594 ObjectCreatedServer = Instance.new("RemoteEvent");
595 ObjectCreatedServer.Name = "ObjectCreatedServer";
596 ObjectCreatedServer.Parent = game:GetService("ReplicatedStorage");
597else
598 ObjectCreatedServer = game:GetService("ReplicatedStorage"):WaitForChild("ObjectCreatedServer");
599 ObjectCreatedServer.OnClientEvent:Connect(function(objectPathParent, objectName, object)
600 local newobject = objectPathParent[objectName].new();
601 newobject.Loaded:Connect(function()
602 for i,v in pairs(object) do
603 if newobject[i] then
604 print'updating value';
605 newobject[i] = v;
606 end
607 end
608 end)
609 end)
610end
611
612-- lazy load main Modules and Objects
613LoadModulesInLocationToTable(Locations.Modules, Forged.Modules);
614LoadObjectsInLocationToTable(Locations.Objects, Forged.Objects);
615
616-- lazy load shared Modules and Objects
617LoadModulesInLocationToTable(Locations.Shared_Modules, Forged.Shared.Modules);
618LoadObjectsInLocationToTable(Locations.Shared_Objects, Forged.Shared.Objects);
619
620-- Load Controllers/Services
621if not IsServer then
622 ClientLoadNetworking();
623 LoadControllersAndServicesToTable(Locations.Controllers, Forged.Controllers);
624else
625 LoadControllersAndServicesToTable(Locations.Services, Forged.Services);
626end
627
628-- Start/Init everything
629InitServicesAndControllers();
630StartServicesAndControllers();
631
632
633return true;