Working on something big for chickynoid that I plan to release to the public which will facilitate a lot the developement for games on chickynoid.
Its Custom Tools for chickynoid, Chickynoid does not support roblox tools for obvious reasons, so I am writing a mod called InventoryMod, which allows chickynoids to have custom inventories that can hold different objects, It also already comes bundled with an object class called CTool (CitrusTool).
Citrus Tools imitate as much as possible the behavior of roblox tools via chickynoid and are split into different components to make its modification as easy as possible so you can adjust them to work into your game, I also plan to make them work instead of via input events via using a :ProcessCommand() function locally and on ServerSide so they work similar to the already existing weapons mod, and they also support rollback functions the user can code in, In case whatever you are coding desyncs from the server or needs to be controlled from the server, Such as unequipping an users tool.
Heres the way the Client sided components are built, keep in mind they are a rewrite of an older system I made so rn im just kinda rebuilding it and then modifying to work with chickynoid, Networking has not been done yet because I need to add a lot of things.
ClientInventoryMod
local module = {}
module.Objects = {}
module.InventoryRecords = {}
function module:Setup(client)
-- Get all of our different Objects
for i,v in pairs(script:GetChildren()) do
if v:IsA("ModuleScript") then
-- Setup and add our objects to the module's table
local Contents = require(v)
Contents:Setup()
self.Objects[v.Name] = v
end
end
end
function module:Step(client, _deltaTime)
end
return module
CTool
-- Custom tools (CTool) mod!
local CTool = {}
-- Services
local Players = game:GetService("Players")
local StarterGui = game:GetService("StarterGui")
local ReplicatedFirst = game:GetService("ReplicatedFirst")
local LocalPlayer = Players.LocalPlayer
local FastSignal = require(ReplicatedFirst.Packages.Chickynoid.Vendor.FastSignal)
CTool.__index = CTool
CTool.ClassName = "CTool"
CTool.Classes = {}
CTool.IsSetup = false
CTool.ToolIDCounter = 0
CTool.InventoryRecords = {}
CTool.InventoryRecords.Server = {}
-- Events
CTool.OnCToolOwnershipToLocalPlayer = FastSignal.new()
CTool.OnCToolRemovedFromLocalPlayer = FastSignal.new()
CTool.OnCToolEquipped = FastSignal.new()
CTool.OnCToolUnequipped = FastSignal.new()
-- Client Only thing
CTool.InputHandler = nil
-- Constructor function for CTool Object
function CTool.new()
local self = setmetatable({
ID = CTool.ToolIDCounter,
Owner = nil,
IsEquipped = false,
ClassName = CTool.ClassName,
Origin = "Client",
-- Change this when making a new class
CToolClass = CTool.ClassName,
}, CTool)
-- Store our Object inside the Records so we can find it
CTool.InventoryRecords[self.ID] = self
-- Update the ID counter
CTool.InventoryRecords += 1
return self
end
-- Sets a CTool's Owner to the given Player
function CTool:SetOwner(Player)
if CTool.InventoryRecords[Player.UserId] then
self.Owner = Player
CTool.InventoryRecords[Player.UserId].Backpack[self.ID] = self
-- Run exclusive code to the Local Player
if Player == LocalPlayer then
CTool.OnCToolOwnershipToLocalPlayer:Fire(self)
end
else
warn("Inventory not found")
end
end
-- Unequips tool and runs class code
function CTool:Unequip()
if self.IsEquipped == true then
local Inventory = CTool.InventoryRecord[self.Owner.UserId]
local ClassFunctions = require(script[self.ClassName])
-- run it's class code
self:UnequipClass()
self.IsEquipped = false
Inventory.Hand = nil
-- Fire the local events for the input handler
CTool.OnCToolUnequipped:Fire(self)
end
end
-- Equip tool and runs class code
function CTool:Equip()
if self.IsEquipped == false then
local Inventory = CTool.InventoryRecord[self.Owner.UserId]
local ClassFunctions = require(script[self.ClassName])
-- Check if tool is already equipped and unequip if so
if Inventory.Hand then
Inventory.Hand:Unequip()
end
self:EquipClass()
self.IsEquipped = true
Inventory.Hand = self
-- Fire the local events for the input handler
CTool.OnCToolEquipped:Fire(self)
end
end
-- Removes all traces of CTool object
function CTool:Destroy()
-- Check if it has an owner to remove it from backpack and hand
if self.Owner then
local Inventory = CTool.InventoryRecords[self.Owner.UserId]
if self.IsEquipped == true then
self:Unequip()
end
Inventory.Backpack[self.ID] = nil
end
-- Fire local events for the input handler
CTool.OnCToolRemovedFromLocalPlayer:Fire(self)
self = nil
return self
end
-- Sets up all the necesary code to make the object class fully work
function CTool:Setup()
print("RAN")
if CTool.IsSetup == false then
-- Hide roblox's deffault inventory Gui
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
-- Setup all other Classes of CTool
for i,v in pairs(script:GetChildren()) do
if v:IsA("ModuleScript") then
local Class = require(v)
Class:Setup()
-- Detect if this is the Module in charge of controlling CTools, if it is then its not a class
if Class.InputHandler then
CTool.InputHandler = Class
else
print(v.Name)
CTool.Classes[Class.ClassName] = Class
end
end
end
end
end
return CTool
InputHandler component
local InputHandler = {}
-- Services
local ContextActionService = game:GetService("ContextActionService")
local Players = game:GetService("Players")
local CTool = require(script.Parent)
local LocalPlayer = Players.LocalPlayer
InputHandler.InputHandler = true
-- idk load things
InputHandler.Assets = script.Assets
InputHandler.Hotbar = {}
InputHandler.HotbarSlotsInUse = 0
-- Settings
InputHandler.Settings = {}
InputHandler.Settings.Keybinds = {
[1] = Enum.KeyCode.One,
[2] = Enum.KeyCode.Two,
[3] = Enum.KeyCode.Three,
[4] = Enum.KeyCode.Four,
[5] = Enum.KeyCode.Five,
[6] = Enum.KeyCode.Six,
[7] = Enum.KeyCode.Seven,
[8] = Enum.KeyCode.Eight,
[9] = Enum.KeyCode.Nine,
[10] = Enum.KeyCode.Zero
}
InputHandler.Settings.MaxHotbarSlots = 10 -- This value should not be higher than 10
InputHandler.GUI = nil
-- Setup everything so we can start controlling the CTools
function InputHandler:Setup()
-- Load the Gui
self.GUI = self.Assets.ToolBar:Clone()
self.GUI.Parent = LocalPlayer.PlayerGui
-- Create the function in charge of handling all of our keypresses
local function ActionHandler(Action,InputState,InputObject)
if InputState == Enum.UserInputState.Begin then
local ID = tonumber(Action)
local CToolSelected = CTool.InventoryRecords[LocalPlayer.UserId].Backpack[ID]
if CToolSelected.IsEquipped == true then
CToolSelected:Unequip()
else
CToolSelected:Equip()
end
end
end
-- Connect events
CTool.OnCToolOwnershipToLocalPlayer:Connect(function(OwnedCTool)
-- Create our GUI for the Toolbar
local NewToolFrame = self.GUI.ToolFrame:Clone()
NewToolFrame.Name = OwnedCTool.ID
NewToolFrame.NameLabel.Text = OwnedCTool.Name
NewToolFrame.Visible = true
-- Set up CTool inside a local hotbar slot
if self.HotbarSlotsInUse <= self.Settings.MaxHotbarSlots then
self.HotbarSlotsInUse += 1
NewToolFrame.Parent = self.GUI.Hotbar
for Slot = 1, self.MaxHotbarSlots,1 do
if not self.Hotbar[Slot] then
self.Hotbar[Slot] = OwnedCTool.ID
NewToolFrame.NumberLabel.Text = Slot
ContextActionService:BindAction(OwnedCTool.ID, ActionHandler,false, self.Keybinds[Slot])
break
end
end
else
NewToolFrame.Parent = self.GUI.InventoryMenu
end
end)
CTool.OnCToolRemovedFromLocalPlayer:Connect(function(CToolID)
-- Removes the GUI Frame for the CTool, from the hotbar/Toolbar GUI
self.GUI.HotBar[tostring(CToolID)]:Destroy()
-- Clears the hotbar slot which references the CTool ID
for Slot = 1, self.Settings.MaxHotBarSlots,1 do
if self.HotBar[Slot] then
ContextActionService:UnbindAction(CToolID)
self.HotBar[Slot] = nil
end
end
end)
CTool.OnCToolEquipped:Connect(function(EquippedCTool)
-- Show the GUI effects
self.GUI.HotBar[EquippedCTool.ID].Outline.Visible = true
end)
CTool.OnCToolUnequipped:Connect(function(EquippedCTool)
-- Show the GUI effects
self.GUI.HotBar[EquippedCTool.ID].Outline.Visible = false
end)
end
return InputHandler
Ill publish it as a resource once its fully ready, Let me know what you guys think!