How can I change my code so that these these modules don't need to require each other?

As I was writing my code I ran into an issue where one of my modules needs to require a module that already required this module which will cause an error. I’m not entirely sure how I can rewrite my code to get around this problem.

I have my main server script which is in charge of setting things up and handling events from the client

local function playerConnected(player)
	print("Player Connected")
	local playerObject = Server:addConnection(player)
end

local function playerDisconnected(player)	
	print("Player Disconnected")
end

local function update(deltaTime)
	Combat:update()
end

function Server:addConnection(player)
	print("Adding Connections")
	local playerObject = Player.new(player)

	playerObjects[player] = playerObject

	return playerObject
end

function Server:GetPlayerByInstance(player)
	return playerObjects[player]
end

function Server.initialize()
	local eventHandler = {}
	
	Players.PlayerAdded:Connect(playerConnected)
	Players.PlayerRemoving:Connect(playerDisconnected)
	RunService.Heartbeat:Connect(update)
	ProximityPromptService.PromptTriggered:Connect(onPromptTriggered)
	
	eventHandler[eventType.inputData] = function(event, player)
		Combat:handleAction(Server:GetPlayerByInstance(player), action)
	end
	
	remoteEvent.OnServerEvent:Connect(function(player, event)
		local func = eventHandler[event.t]
		if func ~= nil then
			func(event, player)
		end
	end)
end

I then have my combat script which needs to make use of GetPlayerByInstance for the target/defender, but I can’t use it since I can’t require the server script.

function Combat:checkCollision(hitbox)
	local hitboxCFrame = hitbox.cframe
	local hitboxSize = hitbox.size
	local result = workspace:GetPartBoundsInBox(hitboxCFrame, hitboxSize, overlapParams)

	if #result <= 1 then return end

	for _, part in ipairs(result) do
		local target = part.Parent
		local humanoid = target:FindFirstChild("Humanoid")

		if target == hitbox.owner.character then continue end
		if not humanoid then continue end
		if hitbox.hits[humanoid] then continue end

		hitbox.hits[humanoid] = true
		
        -- Server:GetPlayerByInstance(Players:GetPlayerFromCharacter(target))
		self:onHit(hitbox.owner, target)
	end
end
1 Like

I don’t see any cyclic dependencies here?
As a matter of fact i see 0 require statements.

1 Like

Because I didn’t include the full code, but the server code requires the combat code, so now my combat code can’t require the server code.

1 Like

Are you sure it doesn’t work? I don’t think it should break.

1 Like

Yeah, I’m sure. If moduleA is requiring moduleB, moduleB can’t require moduleA they will just end up requiring each other infinitely causing the error Requested module was required recursively.

1 Like

Ok then make the two modules the same. Just fuse em together into one module. You could make the combat class a seperate group of functions under the main class of server.

1 Like

You can use dependency injection, require both modules in one place, and inject the reference of the cyclic module.

Problem:

Module A

local ModuleB = require(ModuleB)
local Module = {}


return Module

Module B

local ModuleA = require(ModuleA) -- cyclic dep
local Module = {}



return Module

Solution:

Module A

local Module = {}


return Module

Module B

local Module = {}



return Module
local ModA
local ModB

ModA.ModB = ModB
ModB.ModA = ModA

You shouldn’t ever do this but this would elevate the problem.

2 Likes

One approach is to make the playerObjects table and any logic tied solely to that table into a module that can be required independently of the primary server module. The primary downside to this is that the logic controlling the playerObjects table may not be directly in the module responsible for it, but it’ll still work.

You could also change the primary server module such that it does not require any of the sub-modules and instead exposes methods for registering callbacks to be invoked when server events happen. The modules that define the callbacks would be able to require the main server module, and the main server module would still accomplish its tasks without needing to require the sub-modules.

3 Likes

But I already said that? Your thing is the same as my idea to fuse the parts needed.

You just use fancy vocab.

1 Like