ItemModule - Create tools with ease

Introduction

Tools are a pain to use, and it is an even bigger pain to have to duplicate them and change their appearance and a few bits of code to then realize there is a bug in all of them. You then fix the bug and copy and paste the new source from one tool to the other.

If only there was a simpler way to do all of this… That simpler way now exists, and I’ll show you how to use it.

Get it here!

How do I use it?

First, let’s require the module.

local item = require(script.Item) -- or wherever it is

Excellent, now we can use our item module!

Let’s now create an item and give it to the player when their character spawns.

local Players = game:GetService('Players')
local item = require(script.Item) -- or wherever it is

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function()
		wait(3)
		local newItem = item.new()
		newItem:SetParent(player.Backpack)
	end)
end)

When we playtest, we get this error:

22:38:46.174  ServerScriptService.Script.Item:9: You must provide an object!  -  Server  -  Item:9
22:38:46.174  Stack Begin  -  Studio
22:38:46.174  Script 'ServerScriptService.Script.Item', Line 9  -  Studio  -  Item:9
22:38:46.174  Script 'ServerScriptService.Script.Item.OOPWrapper', Line 33  -  Studio  -  OOPWrapper:33
22:38:46.175  Script 'ServerScriptService.Script', Line 12  -  Studio  -  Script:12
22:38:46.175  Stack End  -  Studio

We need to pass a Model as the first parameter to item.new(). Otherwise, the item won’t have any appearance. We can achieve this via code, but you can do it directly in Studio if you want.

local Players = game:GetService('Players')
local item = require(script.Item) -- or wherever it is

local model = Instance.new("Model")
local part = Instance.new("Part")
part.Parent = model
model.PrimaryPart = part -- very important!

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function()
		wait(3)
		local newItem = item.new(model)
		newItem:SetParent(player.Backpack)
	end)
end)

Now we get this error:

22:45:42.702  ServerScriptService.Script.Item:10: You must provide a Server Module!  -  Server  -  Item:10
22:45:42.702  Stack Begin  -  Studio
22:45:42.702  Script 'ServerScriptService.Script.Item', Line 10  -  Studio  -  Item:10
22:45:42.702  Script 'ServerScriptService.Script.Item.OOPWrapper', Line 33  -  Studio  -  OOPWrapper:33
22:45:42.702  Script 'ServerScriptService.Script', Line 31  -  Studio  -  Script:31
22:45:42.703  Stack End  -  Studio

We need to create a server module and a client module for the tool to do stuff. Create two ModuleScripts inside of your script called ServerModule and ClientModule(you can name them anything you want)

In our ServerModule and our ClientModule, let’s put the boilerplate code for a class:

local module = {}
module.__index = module

function module.new(item)
	local self = setmetatable({}, module)
	
	return self
end

return module

Don’t forget to include them in the original script!

local Players = game:GetService('Players')
local item = require(script.Item) -- or wherever it is

local serverModule = script.ServerModule
local clientModule = script.ClientModule

local model = Instance.new("Model")
local part = Instance.new("Part")
part.Parent = model

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function()
		wait(3)
		local newItem = item.new(model, serverModule, clientModule)
		newItem:SetParent(player.Backpack)
	end)
end)

Now if we playtest, we get this error:

22:54:47.990  ServerScriptService.Script.Item:25: Client module must be accessible from client! Make sure it isn't parented to ServerScriptService or ServerStorage.  -  Server  -  Item:25
22:54:47.991  Stack Begin  -  Studio
22:54:47.991  Script 'ServerScriptService.Script.Item', Line 25  -  Studio  -  Item:25
22:54:47.991  Script 'ServerScriptService.Script.Item.OOPWrapper', Line 33  -  Studio  -  OOPWrapper:33
22:54:47.991  Script 'ServerScriptService.Script', Line 35  -  Studio  -  Script:35
22:54:47.991  Stack End  -  Studio

This is pretty self explanatory, the client module needs to be in a place where the client can access it. I’ll let you figure out how to fix the issue.

If you managed to fix the issue, you should now have a basic tool! It doesn’t do anything yet though.

Let’s make our tool change color every time we click with it equipped.

Set the server module code to this:

local module = {}
module.__index = module

function module.new(item)
	local self = setmetatable({}, module)
	
	self.OnClickEvent = Instance.new("RemoteEvent")
	self.OnClickEvent.Parent = item:GetTool()
	
	self.clickConnection = self.OnClickEvent.OnServerEvent:Connect(function()
		item:GetObject().PrimaryPart.BrickColor = BrickColor.Random()
	end)
	
	return self
end

function module:Destroy()
	self.clickConnection:Disconnect()
end
return module

and the client module code to this:

local player = game:GetService('Players').LocalPlayer
local mouse = player:GetMouse()

local module = {}
module.__index = module

function module.new(tool)
	local self = setmetatable({}, module)
	
	self.OnClickEvent = tool:WaitForChild('RemoteEvent')
	
	self.clickConnection = mouse.Button1Down:Connect(function()
		if tool.Parent:IsA('Model') then
			self.OnClickEvent:FireServer()
		end
	end)
	
	return self
end

function module:Destroy()
	self.clickConnection:Disconnect()
end
return module

End result:

Of course you can do much more with this module, like swords, food, etc. For example, you can have your sword classes inherit one base sword class which is why this module is better than tools when it comes to scripting games with a load of weapons/other items.

If you would like to play with the place file, you can get it here: itemTest.rbxl (27.8 KB)

Documentation

Item Module.new(Model object, ModuleScript serverModule, ModuleScript clientModule, Boolean doNotAutoWeld) Creates an item.

The client module must be parented to places accessible from the client, meaning anywhere other than ServerScriptService and ServerStorage.

void Item:SetGrip(CFrame grip) Sets the item's grip.
void Item:SetParent(Instance parent) Sets the item's parent.
void Item:Destroy() Destroys the item.
Tool Item:GetTool() Returns the tool object associated to the item.
Model Item:GetObject() Returns the model object associated to the item.

Fin

This module is far from complete and the documentation is pretty poor, so if you see any bugs/things I should add, please reply/DM me! Have a nice day.

13 Likes

Why should we use this over regular tools and basically doing the same thing but without requireing your module which seems to me like it just clones a tool then returns it just with extra steps

Cloning the same tool via code/regular tool and changing the appearance(regular tools) works I suppose, but then if you want to change how the tool works slightly you’ll have to duplicate it and rewrite the code. Then you fall into the same problem that I have stated in the introduction, you need to change a small thing and then you find yourself having to apply the same changes to every script.

With my module, you can use inheritance and only change one script to affect them all instead of doing the same thing over and over.


The reason why I created this module was because I was working on another game where I needed a modular system for swords, and didn’t want to waste my time copying and pasting. If I would have just used regular tools, it would’ve been messier and more confusing.

2 Likes