Feed back on 2 script

so i made 2 module to load food item and melee item.
id like to know what you guys things of them and how they could be improved or change
and if you see anything that could potentially break
the script invoking the module already make sure the tool cant be loaded on double
and it call clear when the player die to reset the module.

--(melee module)
--!strict

--// Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ContextActionService = game:GetService("ContextActionService")

--// Remote
local MeleeEvent = ReplicatedStorage:WaitForChild("MeleeEvent")

--// Player
local LocalPlayer = Players.LocalPlayer
local Character = workspace:WaitForChild(LocalPlayer.Name, 5)
local Humanoid = Character and Character:WaitForChild("Humanoid", 5)
local Animator = Humanoid and Humanoid:WaitForChild("Animator") :: Animator

--// Folder
local Client = ReplicatedStorage:WaitForChild("Client")
local Animations = Client:WaitForChild("Animations")
local Sound = Client:WaitForChild("Sound")

--// Tool
local CurrentTool : Tool = nil
local Blade : BasePart = nil

--// Table
local Module = {}
local ToolData: { [string]: { CanDamage: boolean, Debounce: boolean, TouchCon: RBXScriptConnection } } = {}
local SaveAnim: { [string]: AnimationTrack } = {}
local Connections: { RBXScriptConnection } = {}

--// General functions \--
local function LoadAnim(AnimationName)
	if not SaveAnim[AnimationName] then 
		SaveAnim[AnimationName] = Humanoid:LoadAnimation(Animations:FindFirstChild(AnimationName))
	end
	return SaveAnim[AnimationName]
end

--// Function to handle Blade.Touched event (kept separate)
local function HandleTouch()
	local ToolInfo = ToolData[CurrentTool.Name]
	ToolInfo.TouchCon = Blade.Touched:Connect(function(Part)
		if ToolInfo.CanDamage then
			local Model = Part:FindFirstAncestorOfClass("Model")
			local Target = Players:GetPlayerFromCharacter(Model)

			if Model and Target then
				ToolInfo.CanDamage = false
				if LocalPlayer.Team ~= Target.Team then
					MeleeEvent:FireServer(Target, CurrentTool)
				end
			elseif CurrentTool.Name == "Hammer" and Part.Parent.Name == "Toilet" and Model then
				ToolInfo.CanDamage = false
				print("Hit Toilet")
			end
		end
	end)
end

--// Function to handle Attack
local function MeleeAttack(ActionName, InputState, InputObject)
	local ToolInfo = CurrentTool and ToolData[CurrentTool.Name]
	if InputState == Enum.UserInputState.Begin and not ToolInfo.Debounce then	
		ToolInfo.Debounce = true
		
		local SlashAnim = LoadAnim(CurrentTool:GetAttribute("Animation"))
		SlashAnim:Play()

		if SlashAnim then
			SlashAnim.KeyframeReached:Connect(function(Keyframe)
				if Keyframe == "swing" then
					ToolInfo.CanDamage = true
					HandleTouch()
				end
			end)
			task.wait(SlashAnim.Length+1)
		end

		ToolInfo.CanDamage = false
		ToolInfo.Debounce = false
	end
end

--// Reset function to disconnect all connections
function Module.Reset()
	for _, ToolInfo in pairs(ToolData) do
		if ToolInfo.TouchCon then
			ToolInfo.TouchCon:Disconnect()
		end
	end
	table.clear(Connections)
	table.clear(SaveAnim)
	table.clear(ToolData)
end

Module.Initialise = function(Tool: Tool)

	--// LocalPlayer update
	Character = workspace:WaitForChild(LocalPlayer.Name)
	Humanoid = Character and Character:WaitForChild("Humanoid") :: Humanoid
	Animator = Humanoid and Humanoid:WaitForChild("Animator") :: Animator

	local ActionName = Tool.Name.."_Action"

	if not ToolData[Tool.Name] then
		ToolData[Tool.Name] = {
			CanDamage = false,
			Debounce = false,
			TouchCon = nil,
		}
	end

	Tool.Equipped:Connect(function()
		CurrentTool = Tool
		Blade = Tool:FindFirstChild("Blade") :: BasePart
		ContextActionService:BindAction(ActionName, MeleeAttack, false, Enum.UserInputType.MouseButton1, Enum.KeyCode.ButtonL3)
	end)

	Tool.Unequipped:Connect(function()
		local ToolInfo = ToolData[Tool.Name]
		ToolInfo.CanDamage = false
		if ToolInfo.TouchCon then
			ToolInfo.TouchCon:Disconnect()
		end
		CurrentTool = nil
		Blade = nil
		ContextActionService:UnbindAction(ActionName)
	end)
end

return Module

\ ------------------------------------------------ /

--!strict
--(food module)
--// Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ContextActionService = game:GetService("ContextActionService")
local Debris = game:GetService("Debris")

--// Player
local LocalPlayer = Players.LocalPlayer
local Character = LocalPlayer.Character or workspace:WaitForChild(LocalPlayer.Name, 5)
local Humanoid = Character and Character:FindFirstChildOfClass("Humanoid")
local Animator = Humanoid and Humanoid:FindFirstChildOfClass("Animator")

--// Assets
local Client = ReplicatedStorage:WaitForChild("Client")
local Animations = Client:WaitForChild("Animations")
local Sounds = Client:WaitForChild("Sound")

--// Tool 
local CurrentTool : Tool = nil

--// Module
local Module = {}
local ToolData: { [string]: { ConsumptionCount: number, Debounce: boolean } } = {}
local SaveAnim: { [string]: AnimationTrack } = {}
local Connections: { RBXScriptConnection } = {}

--// General functions \--
local function LoadAnim(AnimationName: string): AnimationTrack?
	if not SaveAnim[AnimationName] and Humanoid then
		local AnimObj = Animations:FindFirstChild(AnimationName) :: Animation
		if AnimObj then
			SaveAnim[AnimationName] = Humanoid:LoadAnimation(AnimObj)
		end
	end
	return SaveAnim[AnimationName]
end

local function PlaySound(Tool: Tool, SoundName: string)
	local SoundObj = Sounds:FindFirstChild(SoundName) :: Sound
	if SoundObj and Tool:FindFirstChild("Handle") then
		local Copy = SoundObj:Clone()
		Copy.Parent = Tool.Handle
		Copy:Play()
		Debris:AddItem(Copy, 2)
	end
end

local function ConsumeItem(ActionName: string, InputState: Enum.UserInputState)
	local ToolInfo = CurrentTool and ToolData[CurrentTool.Name]
	if not ToolInfo or InputState ~= Enum.UserInputState.Begin or ToolInfo.Debounce then return end

	ToolInfo.Debounce = true
	LoadAnim(CurrentTool:GetAttribute("Animation")):Play()
	PlaySound(CurrentTool, CurrentTool:GetAttribute("Sound"))

	task.wait(5)
	ToolInfo.Debounce = false
	ToolInfo.ConsumptionCount += 1

	if ToolInfo.ConsumptionCount >= 3 then
		CurrentTool:Destroy()
		ToolData[ActionName] = nil
	end
end

--// Reset function to disconnect all connections
function Module.Reset()
	for _, Connection in pairs(Connections) do
		Connection:Disconnect()
	end
	table.clear(Connections)
	table.clear(SaveAnim)
	table.clear(ToolData)
end

function Module.Initialise(Tool: Tool)
	
	--// LocalPlayer update
	Character = workspace:WaitForChild(LocalPlayer.Name)
	Humanoid = Character and Character:WaitForChild("Humanoid") :: Humanoid
	Animator = Humanoid and Humanoid:WaitForChild("Animator") :: Animator
	
	local ActionName = Tool.Name.."_Action"

	ToolData[Tool.Name] = {
		ConsumptionCount = 0,
		Debounce = false,
	}

	table.insert(Connections, Tool.Equipped:Connect(function()
		CurrentTool = Tool
		ContextActionService:BindAction(ActionName, ConsumeItem, false, Enum.UserInputType.MouseButton1, Enum.KeyCode.ButtonL3)
	end))

	table.insert(Connections, Tool.Unequipped:Connect(function()
		CurrentTool = nil
		ContextActionService:UnbindAction(ActionName)
	end))
end


return Module

i dont have any suggestions for improvement, but this looks awesome. very good code organization.

1 Like