Going to bombard you with the text in the modulescript I have describing it:
--[[
Framework:
--]]
--[[
Organization:
Modules are separated into 3 categories:
- Client: Stuff only the client uses (game.StarterPlayer.StarterPlayerScripts)
- Shared: Stuff both the client and server use (game.ReplicatedStorage)
- Server: Stuff only the server uses (game.ServerStorage)
Each of these 3 categories is further divided into 3 parts:
- Classes: Abstract(ish) modules that are often reused and should only require other classes, never data nor handlers, furthermore, classes should not have any Init functions
- Data: Should be purely for data storage (generally constants)
- Handlers: Anything else, can interact with the classes and data
Objects are separated into 3 categories:
- Client: Stuff only the client can use (Client.Objects)
- Shared: Stuff both the client and server can use (Shared.Objects)
- Server: Stuff only the server can use (Server.Objects)
Objects should be treated as constants and remain unchanged
--]]
--[[
Module rules:
Classes and handlers should have no children but data can only have modulescripts that hold data (like block data for a blocks data module)
All objects must be stored in the two object folders
No type of module must ever yield in its basic environment, but can yield in Init and other functions - therefore you must never Init other modules from the base environment
All modules must return a table but having the Init function is optional
--]]
--[[
Accessing the shared state:
If a module would like to use the shared environment between all other modules, it must add this line in its headers:
local RB = require(game.RB)
Modules can then interact with each other like so:
local otherModule = RB.OtherModule
To Init another module, simply do:
otherModule.Init()
There is no sanity check on init so if your code calls it multiple times, it will be called multiple times.
You can store anything you want in RB
RB.Objects is a union folder of the local (Client/Server) and the shared objects
--]]
--[[
Loading order:
It is required to have a Handler module called "Main" with an Init function - it should start the loading chain
Modules can (and should, because only Main will be loaded by the framework) load each other
--]]
--[[
Circular dependencies:
What are they?
Circular dependies are when there is a loop in the require graph
What do they do?
Normally they will permanently hault the thread they are running on, but since this code is cool, the .__index metamethod for RB will throw an error and you can easily figure out where the circular dependency is
How can I avoid them?
You can avoid circular dependencies by:
A. Checking your code to make sure no circular dependencies occur
B. Try putting the circular dependencies in the Init function
C. Literally just put your entire module in a coroutine.wrap (still return a table though!)
Why do B and C work?
- B works because the Init function will be called at a later time after the module has been required and cached
- C works because it is running on a different thread
--]]
--[[
A template for how modules should be structured:
--[[
TemplateModule
--]]
-- Constants
-- efficiency variables
local RB = require(game.RB)
-- local variables
local Module = {}
function Module.Init()
end
return Module
--]]
Some basic questions:
- Am I doing something completely wrong/is there a better way to do something?
- Is there any situation this would fail/make something very difficult?
- Is there ANYTHING you would change about it? (no matter how basic/small)