<commit_before>TOOL.Category = "Wire - Tools"
TOOL.Name     = "Wire Improved" -- TODO: rename
TOOL.Tab      = "Wire"

if CLIENT then
	language.Add( "Tool_wire_improved_name", "Improved Wiring Tool" ) -- TODO: rename
	language.Add( "Tool_wire_improved_desc", "Used to connect wirable props." )
	language.Add( "Tool_wire_improved_0", "Primary: Attach to selected input, Secondary: Next input, Reload: Unlink selected input, Wheel: Select input." )
	language.Add( "Tool_wire_improved_1", "Primary: Attach to output, Secondary: Attach but continue, Reload: Cancel." )
	language.Add( "Tool_wire_improved_2", "Primary: Confirm attach to output, Secondary: Next output, Reload: Cancel, Wheel: Select output." )
end

TOOL.ClientConVar = {
	width = 2,
	material = "cable/cable2",
	r = 255,
	g = 255,
	b = 255,
}

local function dummytrace(ent)
	local pos = ent:GetPos()
	return {
		FractionLeftSolid = 0,
		HitNonWorld       = true,
		Fraction          = 0,
		Entity            = ent,
		HitPos            = pos,
		HitNormal         = Vector(0,0,0),
		HitBox            = 0,
		Normal            = Vector(1,0,0),
		Hit               = true,
		HitGroup          = 0,
		MatType           = 0,
		StartPos          = pos,
		PhysicsBone       = 0,
		WorldToLocal      = Vector(0,0,0),
	}
end

util.PrecacheSound("weapons/pistol/pistol_empty.wav")

local function get_tool(ply, tool)
	-- find toolgun
	local gmod_tool = ply:GetWeapon("gmod_tool")
	if not ValidEntity(gmod_tool) then return end

	-- find tool
	local tool = gmod_tool:GetToolObject(tool)

	return tool
end

local function get_active_tool(ply, tool)
	-- find toolgun
	local activeWep = ply:GetActiveWeapon()
	if not ValidEntity(activeWep) then return end

	-- checks...
	if activeWep:GetClass() ~= "gmod_tool" then return end
	if activeWep:GetMode() ~= tool then return end

	-- find tool
	local tool = activeWep:GetToolObject(tool)

	return tool
end

if SERVER then
	function TOOL:RightClick(trace)
		if self:GetStage() == 1 then
			local ent = trace.Entity
			Wire_Link_Node(self:GetOwner():UniqueID(), ent, ent:WorldToLocal(trace.HitPos+trace.HitNormal))
		end

		return false
	end

	function TOOL:Reload(trace)
		if self:GetStage() ~= 0 then
			self:Holster()
		end
		return true
	end

	function TOOL:Holster()
		Wire_Link_Cancel(self:GetOwner():UniqueID())
		self:SetStage(0)
	end

	function TOOL:Receive(mode, entid, portname, x, y, z)
		if mode == "i" then -- select input and target entity
			if self:GetStage() ~= 0 then return end

			local target = Entity(tonumber(entid))
			if not target:IsValid() then return end
			if not gamemode.Call("CanTool", self:GetOwner(), dummytrace(target), "wire_improved") then return end

			local material = self:GetClientInfo("material")
			local width    = self:GetClientNumber("width")
			local color    = Color(self:GetClientNumber("r"), self:GetClientNumber("g"), self:GetClientNumber("b"))

			local lpos = Vector(tonumber(x), tonumber(y), tonumber(z))

			if Wire_Link_Start(self:GetOwner():UniqueID(), target, lpos, portname, material, color, width) then
				self:SetStage(1)
				self.target = target
				self.input = portname
			end

		elseif mode == "s" then -- select source entity
			if self:GetStage() ~= 1 then return end

			local source = Entity(tonumber(entid))
			if not source:IsValid() then return end
			if not gamemode.Call("CanTool", self:GetOwner(), dummytrace(source), "wire_improved") then return end

			local outputs = source.Outputs
			local input_type = self.target.Inputs[self.input].Type
			if not outputs or not next(outputs) then
				-- the entity has no outputs
				if input_type == "WIRELINK" then
					-- for wirelink, fake a "link" output.
					outputs = { link = true }
					-- TODO: check if wirelink makes sense (props etc)

				elseif input_type == "ENTITY" then
					-- for entities, trigger the input with that entity and cancel the link.
					self:SetStage(0)

					Wire_Link_Cancel(self:GetOwner():UniqueID())
					WireLib.TriggerInput(self.target, self.input, source)
					WireLib.AddNotify(self:GetOwner(), "Triggered entity input '"..self.input.."' with '"..tostring(source).."'.", NOTIFY_GENERIC, 7)
					return

				else
					-- for all other types, display an error.
					WireLib.AddNotify(self:GetOwner(), "The selected entity has no outputs. Please select a different entity.", NOTIFY_GENERIC, 7)
					return
				end
			end

			self.source = source
			self.lpos = Vector(tonumber(x), tonumber(y), tonumber(z))

			self:SetStage(2)

			-- only one port? skip stage 2 and finish the link right away.
			local firstport = next(outputs)
			if not next(outputs, firstport) then return self:Receive("o", "0", firstport) end

		elseif mode == "o" then -- select output
			if self:GetStage() ~= 2 then return end

			if not gamemode.Call("CanTool", self:GetOwner(), dummytrace(self.source), "wire_improved") then return end -- actually useless

			self.output = portname

			Wire_Link_End(self:GetOwner():UniqueID(), self.source, self.lpos, self.output, self:GetOwner())

			self:SetStage(0)

		elseif mode == "c" then -- clear link
			if self:GetStage() ~= 0 then return end

			local target = Entity(tonumber(entid))
			if not target:IsValid() then return end
			if not gamemode.Call("CanTool", self:GetOwner(), dummytrace(target), "wire_improved") then return end
<commit_msg>[wire_improved] Fixed creating wirelinks on GPU and other entities with a single output.<commit_after>TOOL.Category = "Wire - Tools"
TOOL.Name     = "Wire Improved" -- TODO: rename
TOOL.Tab      = "Wire"

if CLIENT then
	language.Add( "Tool_wire_improved_name", "Improved Wiring Tool" ) -- TODO: rename
	language.Add( "Tool_wire_improved_desc", "Used to connect wirable props." )
	language.Add( "Tool_wire_improved_0", "Primary: Attach to selected input, Secondary: Next input, Reload: Unlink selected input, Wheel: Select input." )
	language.Add( "Tool_wire_improved_1", "Primary: Attach to output, Secondary: Attach but continue, Reload: Cancel." )
	language.Add( "Tool_wire_improved_2", "Primary: Confirm attach to output, Secondary: Next output, Reload: Cancel, Wheel: Select output." )
end

TOOL.ClientConVar = {
	width = 2,
	material = "cable/cable2",
	r = 255,
	g = 255,
	b = 255,
}

local function dummytrace(ent)
	local pos = ent:GetPos()
	return {
		FractionLeftSolid = 0,
		HitNonWorld       = true,
		Fraction          = 0,
		Entity            = ent,
		HitPos            = pos,
		HitNormal         = Vector(0,0,0),
		HitBox            = 0,
		Normal            = Vector(1,0,0),
		Hit               = true,
		HitGroup          = 0,
		MatType           = 0,
		StartPos          = pos,
		PhysicsBone       = 0,
		WorldToLocal      = Vector(0,0,0),
	}
end

util.PrecacheSound("weapons/pistol/pistol_empty.wav")

local function get_tool(ply, tool)
	-- find toolgun
	local gmod_tool = ply:GetWeapon("gmod_tool")
	if not ValidEntity(gmod_tool) then return end

	-- find tool
	local tool = gmod_tool:GetToolObject(tool)

	return tool
end

local function get_active_tool(ply, tool)
	-- find toolgun
	local activeWep = ply:GetActiveWeapon()
	if not ValidEntity(activeWep) then return end

	-- checks...
	if activeWep:GetClass() ~= "gmod_tool" then return end
	if activeWep:GetMode() ~= tool then return end

	-- find tool
	local tool = activeWep:GetToolObject(tool)

	return tool
end

if SERVER then
	function TOOL:RightClick(trace)
		if self:GetStage() == 1 then
			local ent = trace.Entity
			Wire_Link_Node(self:GetOwner():UniqueID(), ent, ent:WorldToLocal(trace.HitPos+trace.HitNormal))
		end

		return false
	end

	function TOOL:Reload(trace)
		if self:GetStage() ~= 0 then
			self:Holster()
		end
		return true
	end

	function TOOL:Holster()
		Wire_Link_Cancel(self:GetOwner():UniqueID())
		self:SetStage(0)
	end

	function TOOL:Receive(mode, entid, portname, x, y, z)
		if mode == "i" then -- select input and target entity
			if self:GetStage() ~= 0 then return end

			local target = Entity(tonumber(entid))
			if not target:IsValid() then return end
			if not gamemode.Call("CanTool", self:GetOwner(), dummytrace(target), "wire_improved") then return end

			local material = self:GetClientInfo("material")
			local width    = self:GetClientNumber("width")
			local color    = Color(self:GetClientNumber("r"), self:GetClientNumber("g"), self:GetClientNumber("b"))

			local lpos = Vector(tonumber(x), tonumber(y), tonumber(z))

			if Wire_Link_Start(self:GetOwner():UniqueID(), target, lpos, portname, material, color, width) then
				self:SetStage(1)
				self.target = target
				self.input = portname
			end

		elseif mode == "s" then -- select source entity
			if self:GetStage() ~= 1 then return end

			local source = Entity(tonumber(entid))
			if not source:IsValid() then return end
			if not gamemode.Call("CanTool", self:GetOwner(), dummytrace(source), "wire_improved") then return end

			local outputs = source.Outputs
			local input_type = self.target.Inputs[self.input].Type
			if not outputs or not next(outputs) then
				-- the entity has no outputs
				if input_type == "WIRELINK" then
					-- for wirelink, fake a "link" output.
					outputs = { link = { Type = "WIRELINK" } }
					-- TODO: check if wirelink makes sense (props etc)

				elseif input_type == "ENTITY" then
					-- for entities, trigger the input with that entity and cancel the link.
					self:SetStage(0)

					Wire_Link_Cancel(self:GetOwner():UniqueID())
					WireLib.TriggerInput(self.target, self.input, source)
					WireLib.AddNotify(self:GetOwner(), "Triggered entity input '"..self.input.."' with '"..tostring(source).."'.", NOTIFY_GENERIC, 7)
					return

				else
					-- for all other types, display an error.
					WireLib.AddNotify(self:GetOwner(), "The selected entity has no outputs. Please select a different entity.", NOTIFY_GENERIC, 7)
					return
				end
			end

			self.source = source
			self.lpos = Vector(tonumber(x), tonumber(y), tonumber(z))

			self:SetStage(2)

			-- only one port? skip stage 2 and finish the link right away.
			local firstportname,firstport = next(outputs)
			if not next(outputs, firstportname) and (input_type ~= "WIRELINK" or firstport.Type == "WIRELINK") then return self:Receive("o", "0", firstportname) end

		elseif mode == "o" then -- select output
			if self:GetStage() ~= 2 then return end

			if not gamemode.Call("CanTool", self:GetOwner(), dummytrace(self.source), "wire_improved") then return end -- actually useless

			self.output = portname

			Wire_Link_End(self:GetOwner():UniqueID(), self.source, self.lpos, self.output, self:GetOwner())

			self:SetStage(0)

		elseif mode == "c" then -- clear link
			if self:GetStage() ~= 0 then return end

			local target = Entity(tonumber(entid))
			if not target:IsValid() then return end
			if not gamemode.Call("CanTool", self:GetOwner(), dummytrace(target), "wire_improved") then return end

{'fraction_non_alphanumeric': 0.11839792803625937, 'fraction_numerical': 0.008139857552492831, 'mean_word_length': 3.6383526383526386, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6638347', 'n_tokens_mistral': 3993, 'n_tokens_neox': 3486, 'n_words': 1027}