World stores all game data like planets and the current date.
Helper changes that data (like advancing the date).
Framework connects everything and gives access to things like planet classes.
-- World.lua
local Helper = require(script.Parent.Helper)
local Manager = require(script.Parent.Manager)
local World = {
Date = DateTime.fromUniversalTime(2025, 7, 1),
Planets = { "Earth", "Mars", "Venus" },
}
function World:GetDate()
return Helper.GetCurrentDate(self)
end
function World:Tick()
print("World tick:", self:GetDate())
Manager.Update(self)
end
return World
-- Helper.lua
local Helper = {}
function Helper.GetCurrentDate(world)
return world.Date
end
function Helper.AdvanceDate(world, days)
world.Date += days
end
return Helper
-- Manager.lua
local Helper = require(script.Parent.Helper)
local Manager = {}
function Manager.Update(world)
Helper.AdvanceDate(world, 1)
print("Manager advanced to:", Helper.GetCurrentDate(world))
end
return Manager
-- TestScript.lua
local World = require(game.ServerScriptService.Modules.World)
World:Tick()
World needs Framework → Framework includes Helper → Helper needs World.
That loop creates a cyclic dependency, meaning the modules load in a circle and break.
local toRequire = PATH.toRequire -- only get the object, not the require.
-- ... when you actually need the require
local newRequire = require(toRequire)
Can’t. World holds the state because the amount of data involved in this game, having both getters and setters would be a ten thousand line pile of mess. So all these modules, as a result, have to be split up to avoid this.
All necessary modules would have require(sharedModule), and then they can communicate with each other by giving references to themselves or their functions through the sharedModule
move the table variable of world into a separate modulescript and require it into any script/module that needs to edit or read it’s values, there’s no cycle dependency and needs minimal editing, you also wouldn’t need to pass it down the functions keeping things simpler
no i mean the variable and just the variable, not the modulescript, you can access variables from modulescripts just like functions by doing module. worldvar={stuffhere}
That’s what I’m doing currently yet it still requires cyclically.
Framework → holds a table of required module Helper
Helper → requires World (to view and access game state data like Planets array of planets in-game)
World → requires Framework
They constantly require eachother here, and dependency injection is a last resort because it forces the project to go from 100-200 lines of code to 300 on the lower end for all modules.
The variable is of type Planet though. Do you mean the Planets array? Because the type has to be specified as Planet class, and that requires the Framework to do so.
I’m a little confused now since I’m only going by what you’ve posted so far, but anyways for cycle dependencies you move the offending thing into another modulescript that is then required by the scripts causing the cycle, you keep doing this until it’s solved.
from what i can see since you’re accessing Date and Planets from multiple modulescripts it would be easier to just make it a global variable by putting it into it’s own modulescript that gets required by anything that needs to change or read it’s values.
you can use draw.io or paper and pencil to plan out your layout of modulescripts by making them into boxes and connecting them with lines, it makes it far easier to visualize and plan things out and fix cycle dependencies
Shared → holds a table to store modules and a getter method
Framework → requires shared, Shared.Framework = Framework
Helper → requires shared, Shared.Helper = Helper
World → requires shared, Shared.World = World
Then, replace require with just accessing from shared
Helper–> requires World requires Shared, World = Shared.Require(World)
and it should be the same amount of code since you only replace how the require works