Best way to handle bunch of interactive objects across client and server

I have this control that handles when an item is given and removed from a player, to handle specific interactions. Basically, each item in game has this sort of module, and it’ll be a way to have each item have their own specific actions occur, without needing a massive script to handle every single item and its unique acitons.

local Control = {}

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

local Trove = require(ReplicatedStorage.Packages.Trove)

function Control:Init()
	self.Trove = Trove.new()

	if RunService:IsServer() then
		self.Trove:Connect(script.Parent.RemoteEvent.OnServerEvent, function(player)
			print("FIRED", player)
		end)
	else -- Client
		self.Trove:Connect(UserInputService.InputBegan, function(input, gameProcessedEvent)
			if gameProcessedEvent then
				return
			end

			if
				input.UserInputType ~= Enum.UserInputType.MouseButton1
				and input.UserInputType ~= Enum.UserInputType.Touch
			then
				return
			end

			script.Parent.RemoteEvent:FireServer()
		end)
	end
end

function Control:Destroy()
	self.Trove:Destroy()

	print("Disconnect handeling")
end

return Control

My question is, is this a good structure?
image
I require it on both client and server when an item with the Control script exists, and run destroy when that item is removed from the character, do any disconnects. Also curious if I need to worry about a player leaving with item in hand? if that’d cause memory leaks? as I’m sure how could check for that kinda stuff? as I’m storing the connection with the item as the key?

local Control = Clone:FindFirstChild("Control")
	if Control then
		self.ItemControls[Clone] = require(Control)
		self.ItemControls[Clone]:Init()
	end

Unsure if I just go with regular script/local script combination for server-client communication? As it’d be easier to handle, no need to require anything, pretty sure connections automatically disconnect when script is destroyed, so there’d be no issues + would mean all clients would automatically have the local side of the code going, wouldnt need to do some crazy requiring to get all the clients to require the tool. Problem tho is the object gets parented to the character, thus LocalScript wouldn’t run :confused: so unsure what to do there

The only other idea I have for organizing is what I do: as a rule I keep all my RemoteEvents in ReplicatedStorage because

  1. Its easier for me to keep track of
  2. I think having dynamically created RemoteEvents (and scripts) to be hard to keep track of and it could introduce weird bugs
  3. I generally keep scripts out of Workspace if I can
  4. I (over?) use ModuleScripts and OOP

Maybe one central script that creates the items could keep track without having the script actually moving or cloning (for example, the scripts could sit in ServerScriptService and clone the Models and do the connections)

And the LocalScript would be a single script that would send any needed inputs over, which would be processed and propagated to the items that need it.

Is this better, I don’t know, and frankly your code doesn’t seem unwieldy, so it could be better, but maybe something here can be of use. It sort of depends on how many different scripts you have to edit, I personally try to keep the number lower (or at least the different places I have to go to find the scripts, big scripts are bad too)

For the cleanup, checkout Instance.Destroying, you could use this to cleanup connections.

About the LocalScript not running, I don’t remember having trouble with LocalScripts and the character unless something has changed recently. Unfortunately I can’t test anything right now, but I do believe I have had LocalScripts in tools.

1 Like