Hello, I was wondering if anyone had the time to do a code review and take a glance at the structure, what could be improved, I dropped the code and stopped working on it as I just wasn’t satisfied, I felt like it was messy but I don’t know why? Maybe someone can give me a better insight
I’m not exactly the most experienced coder, this was my first attempt at an inventory system
-- INVENTORY UI SCRIPT (CLIENT), Creates and makes UI functional
--//Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local SoundService = game:GetService("SoundService")
--//Variables
local sharedModules = ReplicatedStorage:WaitForChild("Shared")
local uiFolder = script.Parent
-- players
local player = Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
-- tweens/sounds
local uiSound = SoundService:WaitForChild("UiSound")
local tweenClick = TweenInfo.new(0.15, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, true)
local tweenHover = TweenInfo.new(0.15,Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
-- gui variables
local gui = playerGui:WaitForChild("MainUI")
local inventory = gui:WaitForChild("Inventory")
local main = inventory:WaitForChild("Main")
local inventories = main:WaitForChild("Inv")
local template = main:WaitForChild("TemplateButton"):WaitForChild("Template")
local categories = main:WaitForChild("Categories")
local sideBtns = main:WaitForChild("SideButtons")
local searchBox = categories:WaitForChild("Search"):WaitForChild("TextBox")
--//Requires
local Data = require(script.Parent.Parent:WaitForChild("DataHandler"))
local Types = require(sharedModules:WaitForChild("Types"))
local ItemData = require(sharedModules:WaitForChild("ItemData"))
local Networking = require(sharedModules:WaitForChild("Networking"))
local UIWeights = require(script:WaitForChild("UIWeights"))
local UIManger = require(uiFolder:WaitForChild("UIManager"))
-- module
local InventoryUI = {}
InventoryUI.EquipDebounce = false
InventoryUI.CurrentTab = "Weapons"
InventoryUI.CurrentCategory = "All"
-- Startup function
function InventoryUI.Init()
-- Wait for inventory
while not Data.Inventory do task.wait() return end
-- Inventory updated
Networking:Connect("InventoryChanged", InventoryUI.UpdateInventory)
-- Create buttons
InventoryUI.CreateButtons()
-- When searching through UI
searchBox:GetPropertyChangedSignal("Text"):Connect(InventoryUI.FilterSearch)
-- When selecting a side button tab
for _,tab in pairs(sideBtns:GetChildren()) do
if tab:IsA("ImageButton") then
tab.Activated:Connect(function()
InventoryUI.SelectTab(tab)
end)
end
end
-- Category Selection
for _,btn in pairs(categories:GetChildren()) do
if btn:IsA("ImageButton") then
btn.Activated:Connect(function()
InventoryUI.SelectCategory(btn.Name)
end)
end
end
end
-- Search through inventory
function InventoryUI.FilterSearch()
-- Eventually switch the UI to filtering only the current category rather than everything :)
-- Play typing SFX
local sound = Instance.new("Sound")
sound.Name = "Typing"
sound.SoundId = "rbxassetid://9116156872"
sound.Volume = 0.1
sound.Parent = SoundService
sound:Play()
sound.Ended:Connect(function() sound:Destroy() end)
local function match_strings(string1, string2)
local matches = 0
for i = 1, #string1 do
if string.sub(string1, i, i) == string.sub(string2, i, i) then
matches = matches + 1
end
end
return matches == #string1
end
local function SortBySearch()
local search_text = string.lower(searchBox.Text)
for _, frame in pairs(inventories[InventoryUI.CurrentTab]:GetChildren()) do
if frame:IsA("Frame") then
local item_Name = string.lower(frame.Name)
local isMatch = match_strings(search_text, item_Name)
frame.Visible = (search_text == "" or isMatch)
end
end
end
SortBySearch()
end
-- Inventory tab switching
function InventoryUI.SelectTab(tab)
local selectedTab = tab.Name
if selectedTab == InventoryUI.CurrentTab then return end
-- Inventory frame tabs
local newInvTab = inventories:FindFirstChild(selectedTab)
local oldInvTab = inventories:FindFirstChild(InventoryUI.CurrentTab)
-- Side button Tabs
local newSideBtn = sideBtns:FindFirstChild(selectedTab)
local oldSideBtn = sideBtns:FindFirstChild(InventoryUI.CurrentTab)
-- Setting search box empty
searchBox.Text = ""
-- Setting new tab
InventoryUI.CurrentTab = selectedTab
-- Setting visiblity
newInvTab.Visible = true
oldInvTab.Visible = false
-- Setting images
newSideBtn.Image = "rbxassetid://86775568773093"
oldSideBtn.Image = "rbxassetid://119900627073534"
InventoryUI.SelectCategory("All")
end
-- Inventory category selection
function InventoryUI.SelectCategory(newCategory)
-- Debounce
if newCategory == InventoryUI.CurrentCategory then return end
local inv : Types.Inventory = Data.Inventory
local oldCategory = InventoryUI.CurrentCategory
-- Sort by all
if newCategory == "All" then
for _, cat in pairs(inventories:GetChildren()) do
for _, frame in pairs(cat:GetChildren()) do
if frame:IsA("Frame") then
frame.Visible = true
end
end
end
end
-- Sort by favorites
if newCategory == "Favorites" then
for name, data in inv.Owned[InventoryUI.CurrentTab] do
if not data.Favorited then
local frame = inventories[InventoryUI.CurrentTab][name]
frame.Visible = false
end
end
end
-- Sort by classic tag
if newCategory == "Classic" then
end
-- Sort by season
if newCategory == "Season" then
end
-- Setting images and category
categories[oldCategory].Image = "rbxassetid://98232073756262"
categories[newCategory].Image = "rbxassetid://102068221649021"
InventoryUI.CurrentCategory = newCategory
end
-- Update a specific frame
function InventoryUI.UpdateInventory(toUpdate, category, itemType)
-- Inventory
local inv : Types.Inventory = Data.Inventory
-- Data information
local itemInfo = inv.Owned[category][toUpdate]
local staticData : Types.ItemData = ItemData[category][toUpdate]
local itemF = inventories[category][toUpdate]
local button = itemF[toUpdate]
local favorite = button.Favorite
-- Update equipped
if inv.Equipped[itemType] == toUpdate then
if itemType == "Knife" then
itemF.LayoutOrder = 1
elseif itemType == "Gun" then
itemF.LayoutOrder = 2
else
itemF.LayoutOrder = 1 - UIWeights[staticData.Rarity].Weight
end
button.Image = UIWeights[staticData.Rarity].Equipped
elseif typeof(inv.Equipped[itemType]) == "table" and table.find(inv.Equipped[itemType], toUpdate) then
itemF.LayoutOrder = 1 - UIWeights[staticData.Rarity].Weight
button.Image = UIWeights[staticData.Rarity].Equipped
-- Update owned
elseif inv.Owned[category][toUpdate] then
itemF.LayoutOrder = UIWeights[staticData.Rarity].Weight
button.Image = UIWeights[staticData.Rarity].Unequipped
end
-- Set favorited
if itemInfo.Favorited then favorite.Image = "rbxassetid://76138845253841" else favorite.Image = "rbxassetid://91616516080222" end
end
-- Create the inventory frame buttons on launch
function InventoryUI.CreateButtons()
-- Inventory
local inv : Types.Inventory = Data.Inventory
-- Loop through inventory
for category, group in pairs(inv.Owned) do
for name, data in pairs(group) do
-- Static item data
local staticData : Types.ItemData = ItemData[category][name]
local itemType = staticData.ItemType
local equipped = inv.Equipped[itemType]
-- Creating button/frames
local itemF = template:Clone()
local button = itemF:WaitForChild("Template")
local favorite = button:WaitForChild("Favorite")
local image = button:WaitForChild("Image")
local rarity = button:WaitForChild("RarityTxt")
local btnname = button:WaitForChild("NameTxt")
-- Button/Frame setup
btnname.Text = staticData.Name
rarity.TextColor3 = UIWeights[staticData.Rarity].Color
button.Name = staticData.Name
rarity.Text = staticData.Rarity
image.Image = staticData.ImageId
itemF.Name = staticData.Name
itemF.Parent = inventories[category]
itemF.Visible = true
-- Favorite image
if data.Favorited then favorite.Image = "rbxassetid://76138845253841" end
-- Equip order / rarity bg
if equipped == name or typeof(equipped) == "table" and table.find(equipped, name) then
if itemType == "Knife" then
itemF.LayoutOrder = 1
elseif itemType == "Gun" then
itemF.LayoutOrder = 2
else
itemF.LayoutOrder = 1 - UIWeights[staticData.Rarity].Weight
end
button.Image = UIWeights[staticData.Rarity].Equipped
else
button.Image = UIWeights[staticData.Rarity].Unequipped
itemF.LayoutOrder = UIWeights[staticData.Rarity].Weight
end
-- Visual equip attempt
button.MouseButton1Down:Connect(function()
-- Set debounce, prevent unequipping knives/guns
if InventoryUI.EquipDebounce then return end
if inv.Equipped[itemType] == name and itemType == "Knife" or inv.Equipped[itemType] == name and itemType == "Gun" then
return
end
-- Debounce start
InventoryUI.EquipDebounce = true
-- Create sound instance
local sound = Instance.new("Sound")
sound.Name = "Click"
sound.SoundId = "rbxassetid://10066936758"
sound.Parent = SoundService
sound:Play()
sound.Ended:Connect(function() sound:Destroy() end)
-- Fire event to server
Networking:FireServer("UpdateInventory", category, name)
--Tween
local tween = TweenService:Create(button, tweenClick, {Size = button.Size + UDim2.new(0.07,0,0.07,0)})
tween:Play()
tween.Completed:Wait()
-- Debounce end
InventoryUI.EquipDebounce = false
end)
-- favorite attempt
favorite.MouseButton1Down:Connect(function()
-- Sounds
local sound = Instance.new("Sound")
sound.Name = "Favorite"
sound.Parent = SoundService
sound.SoundId = "rbxassetid://10066942189"
sound.Volume = 0.3
sound:Play()
sound.Ended:Connect(function() sound:Destroy() end)
-- Fire to server
Networking:FireServer("FavoriteAttempt", category, name)
end)
-- Mouse hover over buttons
button.MouseEnter:Connect(function()
local tween = TweenService:Create(button, tweenHover, {Size = UDim2.new(1.03,0,1.03,0)})
tween:Play()
end)
-- Mouse leave hover buttons
button.MouseLeave:Connect(function()
local tween = TweenService:Create(button, tweenHover, {Size = UDim2.new(1,0,1,0)})
tween:Play()
end)
end
end
end
-- returning
return InventoryUI
-- DATA HANDLER (CLIENT), receives a client version of the inventory and makes changes based on it
--//Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
--//Variables
local sharedModules = ReplicatedStorage:WaitForChild("Shared")
--//Requires
local Networking = require(sharedModules.Networking)
local ItemData = require(sharedModules.ItemData)
local Types = require(sharedModules.Types)
-- module
local DataHandler = {}
DataHandler.Inventory = nil
function DataHandler.Init()
-- Get and set inventory data for local player
local data = Networking:InvokeServer("GetInventoryData")
DataHandler.Inventory = data
-- When the inventory gets update request from server
Networking:BindEvent("UpdateInventory", DataHandler.UpdateInventory)
end
function DataHandler.UpdateInventory(changedData)
-- Update inventory here
local inv : Types.Inventory = DataHandler.Inventory
-- Preform correct updates
if changedData.Action == "Equip" then
-- Unequip item from local table
if changedData.Unequip then
local change = inv.Equipped[changedData.ItemType]
if typeof(change) == "string" or change == nil then
inv.Equipped[changedData.ItemType] = nil
elseif typeof(change) == "table" then
local index = table.find(change, changedData.Unequip)
if index then
table.remove(inv.Equipped[changedData.ItemType], index)
end
end
Networking:Fire("InventoryChanged", changedData.Unequip, changedData.Category, changedData.ItemType)
end
-- Equip item to table
if changedData.Equip then
local change = inv.Equipped[changedData.ItemType]
if typeof(change) == "string" or change == nil then
inv.Equipped[changedData.ItemType] = changedData.Equip
elseif typeof(change) == "table" then
table.insert(inv.Equipped[changedData.ItemType], changedData.Equip)
end
Networking:Fire("InventoryChanged", changedData.Equip, changedData.Category, changedData.ItemType)
end
end
if changedData.Action == "Favorite" then
local item = inv.Owned[changedData.Category][changedData.ToFavorite]
item.Favorited = not item.Favorited
Networking:Fire("InventoryChanged", changedData.ToFavorite, changedData.Category, changedData.ItemType)
end
end
-- returning
return DataHandler
