Tool manager singleton or package of tool scripts?

Cheers all.

TL;DR - What is better: to create one script handling all tools, or to create a package per type of tool script and put it in the tools matching my description (e.g. gun script package goes in gun tools)? What is the benefit of either?


I’m in the process of developing for a certain group right now and we’ve come across the issue of our tool scripts being nightmarishly horrendous to look at. As such, a refactor of all tools is evident but I’ve had some difficulties in deciding how to move forward.

Ideally, since all tools behave the same way except with different configurations, I was looking into attempting to decouple Tool instances and the codebase behind them. My best thought, starting from the client-side, would be to make a script in StarterPlayerScripts that handles tools. It’s like putting the LocalScript in a Tool but instead it’s in StarterPlayerScripts and handles all tools. This got me lost.

Next on my list was to revisit putting scripts in the actual tools but I still needed a way to update all of them quickly and ensure they were the same. So now I’m looking at packages. This would allow me to update all tool scripts at one go by editing the package. The ease of working with scripts in tool instances would come back as well.

So… should I look into decoupling tools from their scripts or just use packages? What is the benefit of either of them? If I should go with separated tools and scripts, what would be a good way to create a tool class to handle all my tools?

2 Likes

I would go with a one script because if all tools are behaving the same it doesn’t make any sense to just duplicate the scripts in all tools also we have to keep in mind that player max equipped tool is one so there is not going to be that many actions at the same time and even less if we use any waits inside of it. I would go with package only if you are planning to do different tools with different benefits in future and it might be easier to update them at this point. Also we all know that less scripts create less performance. I would use a ‘local’ module script if you are creating a tool because we need to run some functions only once in a while and send different configurations throught script in StarterPlayerScripts (as you said) straight to module script and back.

By using packages, I’m effectively still following a centralised point to control the behaviour of tools. They will both still achieve the streamlined behaviour that I’m looking for but a handler decoupled from the tools is significantly harder or complicated to work with than having the scripts readily available in the tool.

I’m not quite sure what you meant by “less scripts create less performance” or if you meant to reverse that statement, but the amount of scripts I’m using has no bearing on performance. What matters is the code I’m running and I know how to optimise systems well enough that impact is relatively negligible.

As I mentioned in the OP, if I required a different style of tools, I would create a separate package for that category and place said package into the tool. The likelihood of this is low though. For my specific case, it would be two packages: gun scripts and sword scripts.

And, for creating a handler via StarterPlayerScripts, I don’t know how to do that.

You will have to use BindActions when player character spawns and UnbindActions when character respawn/die here in my opinion, scroll down to bottom and you will see an example of handling a tool reload. Everything else is written on StarterPlayerScripts that it’s a good object for localscripts for defining additional inputs with ContextActionService.

I know how to hook up user input, but this doesn’t explain how to accomplish the actual tool manager singleton system. I have worked with singleton controllers in the past but I don’t know if the workflow for tools is the same and if so, how exactly I should be assembling things together so that they work and register as I need.

Binding actions per spawn is not necessary because I can easily set up an input check system that, when a key is pressed, identifies if any tool is equipped and if so, calls the appropriate bound action. This would need to be weaved into the system as well, especially if the tool manager is intended to support different categories of tools at once.

Nothing on these pages answers my question. I would not have made a topic if there were pages that were able to yield an answer for my questions because searching is the first resource I go to when I don’t understand something. I did ask a friend on Discord though and I’m still dissecting the information. This is what they replied with, verbatim:

if you wanted to handle them all through one ls wouldn’t it be pretty simple? just using childadded and childremoved events for the player’s backpack and then having a class created for each tool added that sets up the core functionality like what the behaviour should be like for equipping etc and then having the main ls listen for input events which allows for different events to fire depending on what the tool is; having whitelisted input for each tool with the tools functions for whatever input action was made returned

It probably is simple but I’m overcomplicating it. I have a habit of doing that with systems I don’t fully understand how to create from the beginning. I’m fine with the coding aspect of it: what I require help with is the assembling of the system and what kinds of patterns I should be adhering to.

It’s worth noting, anyhow, that my question on how to create a singleton system is only a smaller additional part of this thread if I’m recommended to (or should) pursue a singleton-based tool manager system. The grand question is singleton or packages and why.

So I just created an system which works correctly by using only one localscript in a StarterPlayerScripts and I used configurations inside of it. Here is how it looks like:


Explorer:

sdafdss

Here is my localscript:

local plr = game.Players.LocalPlayer
workspace:WaitForChild(plr.Name)

plr.Backpack.Tool.Equipped:Connect(function(tool)
	   workspace:FindFirstChild(plr.Name):WaitForChild("Tool"):FindFirstChild("Handle").Touched:Connect(function(hit)
	 if hit.Parent:FindFirstChild("Humanoid") then
		hit.Parent:FindFirstChild("Humanoid").Health = hit.Parent:FindFirstChild("Humanoid").Health - script.Configuration.DamageTool.Value
	  end
   end)
end)

plr.Backpack.Tool2.Equipped:Connect(function(tool)
	   workspace:FindFirstChild(plr.Name):WaitForChild("Tool2"):FindFirstChild("Handle").Touched:Connect(function(hit)
	 if hit.Parent:FindFirstChild("Humanoid") then
		hit.Parent:FindFirstChild("Humanoid").Health = hit.Parent:FindFirstChild("Humanoid").Health - script.Configuration.DamageTool2.Value
	  end
   end)
end)

Here is proof that we called a different cofiguration on different tool because when we use Tool it makes less damage to soldier as Tool2 which kills solider immediately (Configurations).



If that’s still not what you are looking for I don’t know really what you are looking for but I hope it’s kinda helpful and that you will receive your answer soon. :herb:

It looks relatively close to what I’m looking for but it doesn’t hit the mark conceptually. I need to be able to handle an arbitrary amount of tools without redundancy and it needs to be scalable.

The scalability I’m looking at is wherr the only thing I need to add to register new tools is the tool instance and a configuration set that gets loaded for all owned and new tools. Redundancy also needs to out itself so I can decouple the behaviour for a type of tool from hard coded processes. A tool manager singleton system should boast abstraction at large.

The contribution is appreciated but unfortunately it doesn’t lead me closer to understanding how to assemble the singleton nor if I should pursue the singleton or just package my code. The latter is easier but the former abstracts more and decouples code from tools.

Alright. I think I may have asked too strange of a question, so I will conducting this investigation personally and see which one is more fitting for my use case. I’m not too familiar with abstraction at large though so that may be difficult. I’ll be working with the information I got from Discord though.

I will be starting with packaged scripts, since that seems exponentially easier to work with. There’s less abstraction involved but that means I’m coupling my scripts and tool instances together. Anything that’s easier to work with, I’ll take. Once all my tool type packages are created, I’ll just drag and drop them into my tool instances to get them up and running.

Once I’ve got packages down, I’m going to take a deeper dive into the tool singleton system. I happened to find an old tool handler that does exactly what I need, albeit somewhat buggy, so I’ll try my luck with it and see what happens. Hopefully it does what I need when I use it as reference to create my own tool system. Tools are very important to my game.

Thanks to those who replied or looked at my question and possibly puzzled over ways to help out. I’ll still accept responses and a newer solution, but for now this is the path I’ll be choosing. It seems like both can be just as effective but I’ll have to do my own technical testing to see which one is better.

Not sure it it’s better to necro this thread, or just PM you.

I don’t think it was a strange question to ask, because I’ve been asking similar questions. The type of code I usually see in Roblox does not scale well with complexity and invites easily preventable bugs.

I’ve been flirting with Knit and EGF, but am still finding the right balance for my projects.

I’m literally about to tackle tools in a way I think will save me frustration down the road, but I’m curious what you learned about it with your approach in the year since you asked.