Duelers table getting completely cleared randomly?

I’ve tried printing in multiple different spots, but the problem area is the HandleDuel function. After the first wait(1) the table becomes empty. The creation of a new Duel object only occurs once, and I have verified that by printing in the script that creates new Duel objects.

The problem is that the duelers table becomes empty after HandleDuelers is called, causing the round to be over and the duelers never get respawned.

If anyone has a clue as to why this is happening it would be greatly appreciated.

local DuelService = {}
DuelService.__index = DuelService
DuelService.Settings = {
	DuelTime = 60
}

function DuelService:ReadyDuelers()
	local Spawns = self.Arena.Spawns:GetChildren()

	for Index, Dueler in pairs(self.Duelers) do
		local Character = Dueler.Character
		local Humanoid = Character and Character:FindFirstChildOfClass('Humanoid')
		
		if Humanoid then
			Humanoid.Died:Connect(function()
				table.remove(self.Duelers, Index)
			end)
			
			Character:SetPrimaryPartCFrame(Spawns[Index].CFrame)
			
			Sword:Clone().Parent = Dueler.Backpack
		else
			table.remove(self.Duelers, Index)
		end
	end
end

function DuelService:HandleDuel()
	local DuelTimer = self.Settings.DuelTime
	
	while DuelTimer > 0 and #self.Duelers == 2 do
		wait(1)
		
		DuelTimer -= 1
	end
	
	self:End()
end

function DuelService:Begin()
	self.Arena:SetAttribute('Active', true)
	
	self:ReadyDuelers()
	self:HandleDuel()
end

function DuelService:End()
	self.Arena:SetAttribute('Active', false)
	
	for _, Dueler in pairs(self.Duelers) do
		if Dueler then
			Dueler:LoadCharacter()
		end
	end
end

function DuelService.New(Arena, Duelers)
	local NewDuel = setmetatable({}, DuelService)
	NewDuel.Arena = Arena
	NewDuel.Duelers = Duelers
	
	return NewDuel
end

return DuelService

I have never seen this type of syntax

local Humanoid = Character and Character:FindFirstChildOfClass('Humanoid')`

but print the humanoid to double check that it is returning the right thing

print(Humanoid)

if it doesnt print what you want, try something like this

		local Character = Dueler.Character
		if not Character then table.remove(self.Duelers, Index) continue end
		local Humanoid = Character:FindFirstChildOfClass('Humanoid')
		
		if Humanoid then
			Humanoid.Died:Connect(function()
				table.remove(self.Duelers, Index)
			end)
			
			Character:SetPrimaryPartCFrame(Spawns[Index].CFrame)
			
			Sword:Clone().Parent = Dueler.Backpack
		else
			table.remove(self.Duelers, Index)
		end

It’s a ternary statement, it basically sets Humanoid to nil if either Character or Character:FindFirstChildOfClass('Humanoid') are nil.

yes but is it returning the Humanoid and not the Character? or is it returning something like true because they both exist

It returns the Humanoid object if it’s not nil.

I don’t know what could be causing the clear table other than this

But in this function the way you detect when everyone is dead is by clearing the table from the duelers, are you trying to only load the character of the survivior?

No, I’m just looping through all players in the case that time runs out and both survive.

I also printed inside the died event and the else and neither print so they aren’t getting removed.

Im guessing the module initializer script goes something like

local Dual = DualModule.New(Info, Info)
Dual:Begin()

do you touch the dual object with any outside scripts? Im guessing not but still good to check…

Nah, it’s a baseplate with just 2 scripts (the initializer and the module).

It is initialized like this:

DuelService.New(Arena, Duelers):Begin()

I’m not the best person to try and help you since I’m still sort of a novice and I am sure you did this but when you printed the DuelTimer and self.Duelers in the loop, what did you get in the output?

First prints 60 then 59 after it breaks out of the while loop. self.Duelers printed 2 at the beginning of the while loop and 0 after the wait(1).

I’m assuming you’re calling your function as so:

local duel = DuelService.New(Arena, Duelers):Begin()
duel:HandleDuel()

This is wrong, because you’re not getting the return of the constructor function (the metatable) but the return of Begin which returns nil. The proper way to do this is:

local duel = DuelService.New(Arena, Duelers)
duel:Begin()
duel:HandleDuel()

So I can’t call HandleDuel through the Begin function?

you make a very VERY good point that can be overlooked really easily, but he is calling it inside of the begin function, where it will still be valid, plus if he did it this way it would error

If you don’t mind, Can I have the place file to see if the issue is elsewhere?

One problem that I’ve faced, especially when making rounds like this is sending tables into an object or function. If at any point, the table is changed by some other script, it would end up changing the table in the object/function. This is because you’re sending a shallow copy. What I’m assuming is happening is that somewhere after creation, the original ‘Duelers’ table is being modified. Check that original table and see if that’s the case. If it isn’t, you’re set and we can begin looking for other issues (because from here, I can’t see any other place a dueler would be removed randomly). If it is being modified, either change up your code to make sure it isn’t being modified when a duel is occurring OR create a deep copy method.

local function deep_copy(original)
	local copy = {}
	for k, v in pairs(original) do
		if type(v) == "table" then
			v = deep_copy(v)
		end
		copy[k] = v
	end
	return copy
end

function DuelService.New(Arena, Duelers)
	local NewDuel = setmetatable({}, DuelService)
	NewDuel.Arena = Arena
	NewDuel.Duelers = deep_copy(Duelers)
	
	return NewDuel
end
1 Like

Thanks, the issue ended up being in an event I had in the script that was initializing the new duels that was removing players from the table for this very reason.

1 Like