Toolgun stutter in multiplayer

I have a STOOL that links two entities (in this particular case, air tanks) together. It works fine in singleplayer, but for some reason it seems to almost stutter and run some of the code more than it should, causing console errors. The toolgun seems to do its job, at least in the first cycle, as the objects appear to be linked together and are sharing resources. In subsequent cycles it encounters errors and the toolgun no longer functions.

The following is the toolgun’s source, and following that the errors thrown in the console. Maybe a second set of eyes are all I really need…

[lua]
TOOL.Category = “Horizon”
TOOL.Name = “Link Tool”
TOOL.Command = nil
TOOL.ConfigName = “”

local timesFired = 0
local cycleComplete = false
local startPos
local endPos

function TOOL:LeftClick( tr )

if (!tr.Entity:IsValid(tr.Entity.linkable)) or (tr.Entity:IsPlayer()) then return end

	startPos = tr.HitPos
	if (timesFired == 0) then
	
	entA = tr.Entity
	print ("entA = " .. entA:GetClass())
	
	timesFired = 1
	
	if (CLIENT) then return true end
	
	end
	
	
	if (tr.Entity != entA) then
		
		if cycleComplete == false then
			entB = tr.Entity
			print ("entB = " .. entB:GetClass())
	
			if entA.networkID == nil and entB.networkID == nil then
		
				print( "neither entities are networked" )
								
				entA.networkID = GAMEMODE.nextNet
				print(entA.connections)
				table.insert(entA.connections, entB)
				
		
				entB.networkID = GAMEMODE.nextNet
				table.insert(entB.connections, entA)	
		
				newNetwork = {}
				newNetwork[1] = {}
				newNetwork[2] = entA
				newNetwork[3] = entB
					
				GAMEMODE.networks[GAMEMODE.nextNet] = newNetwork
		
		
				--Now, let's add any new resources to the network's resource list
				for _, ent in pairs( newNetwork ) do
					
					if ent.deviceType == "storage" then
						GAMEMODE:addToResourceList( ent )
					end
				end
		
				--Next, we need to get a count of all resources on the network
				GAMEMODE:updateResourceCount(GAMEMODE.nextNet)
		
				-- Increment to next available network ID
				GAMEMODE.nextNet = GAMEMODE.nextNet + 1			
				
				cycleComplete = true;
			end
		
		end
		
		if entA.networkID != nil and entB.networkID == nil then
		
			if cycleComplete == false then
				print( "one entity (entA) is networked" )
				
				--add each other to connections table
				table.insert(entA.connections, entB)					
				table.insert(entB.connections, entA)
				
				entB.networkID = entA.networkID
				
				table.insert(GAMEMODE.networks[entA.networkID], entB)
				
				if entB.deviceType == "storage" then
					GAMEMODE:addToResourceList( entB )
				end
				
				GAMEMODE:updateResourceCount( entA.networkID )
				
				cycleComplete = true
			end
		
		end
		
		if entB.networkID != nil and entA.networkID == nil then
			
			if cycleComplete == false then
				print( "one entity (entB) is networked" )
				--add each other to connections table
				table.insert(entA.connections, entB)					
				table.insert(entB.connections, entA)
				
				entA.networkID = entB.networkID
				
				table.insert(GAMEMODE.networks[entB.networkID], entA)
				
				if entA.deviceType == "storage" then
					GAMEMODE:addToResourceList( entA )
				end
				
				GAMEMODE:updateResourceCount( entB.networkID )
				
				cycleComplete = true
			end
		
		end
		
		if entA.networkID !=nil and entB.networkID != nil then
		
			if entA.networkID == entB.networkID  and cycleComplete == false then
				print("Entities are in the same network!")

				table.insert(entA.connections, entB)					
				table.insert(entB.connections, entA)
				
				
				cycleComplete = true
			end	
		
			if cycleComplete == false then								
				print( "both entities are networked" )
				
				table.insert(entA.connections, entB)					
				table.insert(entB.connections, entA)
				
				local oldNetA = GAMEMODE.networks[entA.networkID]
				local oldNetB = GAMEMODE.networks[entB.networkID]
									
				local NetworkA = GAMEMODE.networks[entA.networkID]
				local NetworkB = GAMEMODE.networks[entB.networkID]
				
				local newNetwork = {}
				newNetwork[1] = {}
				
				for _, ent in pairs( NetworkA ) do
				
					if ent.linkable == true then
						
						ent.networkID = GAMEMODE.nextNet
						table.insert(newNetwork, ent)
					
					end
				
				end
				
				for _, ent in pairs( NetworkB ) do
				
					if ent.linkable == true then
					
						ent.networkID = GAMEMODE.nextNet
						table.insert(newNetwork, ent)
					
					end
				
				end
				
				GAMEMODE.networks[oldNetA] = nil
				GAMEMODE.networks[oldNetB] = nil
				
				GAMEMODE.networks[GAMEMODE.nextNet] = newNetwork
				
				for _, ent in pairs( GAMEMODE.networks[GAMEMODE.nextNet]) do
				
					if ent.deviceType == "storage" then
					
						GAMEMODE:addToResourceList( ent )
					
					end
				
				end
				
				GAMEMODE:updateResourceCount( GAMEMODE.nextNet )
				
				GAMEMODE.nextNet = GAMEMODE.nextNet + 1
				
				
				cycleComplete = true
			end
		end
		
		 endPos = tr.HitPos
		
		// Get information we're about to use   
       
        
        local constraint, rope = constraint.Elastic( entA, entB, 0, 0, startPos, endPos, 0, 0, 0, "cable/cable2", 2, 0 )

		
		timesFired = 0
		cycleComplete = false
		
	end
	


if (CLIENT) then return true end

return true

end

function TOOL:Reload( tr )

if tr.Entity.linkable == true then

	if tr.Entity.networkID != nil then
		GAMEMODE:unlinkDevice(tr.Entity)
	end
	
	if (CLIENT) then return true end		

end

return true

end
[/lua]

Console output:



] ent_create test_tank
] ent_create test_tank
entA = test_tank
entA = test_tank
entB = test_tank
neither entities are networked
table: 2BDC3FC8
entB = test_tank
neither entities are networked
nil
[@weapons\gmod_tool\stools\link_tool.lua:40] bad argument #1 to 'insert' (table expected, got nil)
nilentB = test_tank

neither entities are networked
[@weapons\gmod_tool\stools\link_tool.lua:40] bad argument #1 to 'insert' (table expected, got nil)
entB = test_tank
neither entities are networked
nil
[@weapons\gmod_tool\stools\link_tool.lua:40] bad argument #1 to 'insert' (table expected, got nil)
entB = test_tank
neither entities are networked
nil
[@weapons\gmod_tool\stools\link_tool.lua:40] bad argument #1 to 'insert' (table expected, got nil)



One small suggestion to reduce the clutter, make a link function on the entity itself as it seems quite complicated. This way you don’t have to copy-paste it everywhere you need it.
As for the error: entA.connections is nil, make it equal to {} if its nil to fix it.

I’m not sure that would fix the problem- on the first run entA.connections isn’t nil. It should only run through this sequence once, which it does in singleplayer. As you can see in the console output, it’s running part of the sequence four additional times.

Anyone want to take a crack at it? Anyone at all…?

Is entA.connections a table or is entA a table :stuck_out_tongue:

It’s trying to add it to a table but that table doesn’t exist so

Theory wise

[lua]
local entAT = {}
local entBT = {}
table.insert(entAT, entB.connections)

table.insert(entBT, entA.connections)
[/lua]

entA.connections is a table that exists on the entity. When the entity is selected by the toolgun, entA(or entB for that matter) becomes valid and their connections table is accessible to the tool.

The problem I’m having is not the ‘Bad Argument’ error in the console. That’s only a symptom. The problem is the code running multiple times when it shouldn’t be.

The only analogy I can think of is a gun. In singleplayer, it behaves like a semi-automatic. the script executes once, does its job and readies itself to fire again. In multiplayer, the same script tries to go full auto, executing the first time as it should, but then fires again without a valid entity selected, effectively jamming up. That’s the point where it throws the console error.

I just want to know why this behavior would occur only in multiplayer?