Change an objectvalue's value inside an image button in a remote event

Hi! So like the title says, I’d like to know how I can change an objectvalue inside an imagebutton’s value in a script that connects to a remoteevent. Like for example, I fire the event from a localscript and the arguments are: plr, value, object, then the remote changes the value of the object to the value argument.
Thanks in advance.

1 Like

As I understand it arguments to remote event handlers are passed by value not reference. This means in your case that the object you want to change is a copy of the object so any changes are not reflected in the local script on the client. A RemoteFunction is probably more suited to your scenario as they allow you to return a value, which the client will wait for. I assume because you are using a RemoteEvent there is some server side logic being applied based on the object and/or value. An alternative approach would be to apply the change in the local script then use the RemoteEvent as a notification to the server so it can respond to the change, but that may not be appropriate if you need the local script to wait for the logic to complete, in that scenario the RemoteFunction is the better option.

I have tried remotefunctions but to my knowledge I can’t seem to make it work or know how to make it work with them.
How would I turn this into a remotefunction?

Remote Script
local plr = game:GetService("Players").LocalPlayer or game.Players.PlayerAdded:Wait()

local replicated = game:GetService("ReplicatedStorage")
local remotes = replicated.RemoteEvents
local inventoryremotes = remotes.Inventory
local backpack = plr

inventoryremotes.EquipItem.OnServerEvent:Connect(function(plr, item, condition, itemtype, object)
	if condition == "Equipped" then
		if itemtype == "Weapon" then
			local selecteditem = replicated.Item.Weapons[item]:Clone()
			selecteditem.Parent = plr.Backpack
			object.Value = selecteditem
			print("Equipped Weapon: " .. item)
		elseif itemtype == "Fruit" then
			local selecteditem = replicated.Item.Fruits.Fruit[item]:Clone()
			selecteditem.Parent = plr.Backpack
			selecteditem["Owner"].Value = plr
			object.Value = selecteditem
			print("Equipped Fruit: " .. item)
		end
	elseif condition == "Unequipped" then
		for index, equipped in pairs(plr.Backpack:GetChildren()) do
			if equipped.Name == item then
				local lol = plr.Backpack[item]
				lol:Destroy()
			end
		end
		for index, chrlo in pairs(plr.Character:GetChildren()) do
			if chrlo:IsA("Tool") and chrlo.Name == item then
				chrlo:Destroy()
			end
		end
	end
end)

inventoryremotes.DeleteItem.OnServerEvent:Connect(function(plr, item)
	if plr.Data.Inventory:FindFirstChild(item) then
		local deletethisitem = plr.Data.Inventory[item]
		deletethisitem:Destroy()
		print("Deleted Item (1): " .. item)
	end
end)

Local Script
local plr = game:GetService("Players").LocalPlayer or game.Players.PlayerAdded:Wait()

local main = script.Parent.Parent.Parent.InventoryFrame
local replicated = game:GetService("ReplicatedStorage")
local remotes = replicated.RemoteEvents
local inventoryremotes = remotes.Inventory

local cooldown = false

for index, child in pairs(script.Parent:GetChildren()) do
	if child:IsA("TextButton") then
		child.MouseButton1Click:Connect(function()
			if child.Name == "Equip" then
				if child.Text == "Equip" then
					for index, items in pairs(main:GetChildren()) do
						if items:IsA("ImageButton") and cooldown == false then
							if script.Parent.ItemDisplayed.Value == items and items.Equipped.Value == false then
								if script.Parent.ItemDisplayed.Type.Value == "Weapon" then
									script.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Click:Play()
									items.Equipped.Value = true
									inventoryremotes.EquipItem:FireServer(items.name, "Equipped", "Weapon", items.Tool)
									print("Activated Remote 1")
									child.Text = "Unequip"
									cooldown = true
									wait(0.5)
									cooldown = false
								elseif script.Parent.ItemDisplayed.Type.Value == "Fruit" then
									script.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Click:Play()
									items.Equipped.Value = true
									inventoryremotes.EquipItem:FireServer(items.name, "Equipped", "Fruit", items.Tool)
									print("Activated Remote 1")
									child.Text = "Unequip"
									cooldown = true
									wait(0.5)
									cooldown = false
								end
							end
						end
					end
				elseif child.Text == "Unequip" then
					for index, items in pairs(main:GetChildren()) do
						if items:IsA("ImageButton") and cooldown == false then
							if script.Parent.ItemDisplayed.Value == items and items.Equipped.Value == true then
								if script.Parent.ItemDisplayed.Type.Value == "Weapon" then
								    script.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Click:Play()
								    items.Equipped.Value = false
								    inventoryremotes.EquipItem:FireServer(items.name, "Unequipped", "Weapon", items.Tool)
								    print("Activated Remote 2")
								    child.Text = "Equip"
								    cooldown = true
								    wait(0.5)
									cooldown = false
								elseif script.Parent.ItemDisplayed.Type.Value == "Fruit" then
									script.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Click:Play()
									items.Equipped.Value = false
									inventoryremotes.EquipItem:FireServer(items.name, "Unequipped", "Fruit", items.Tool)
									print("Activated Remote 2")
									child.Text = "Equip"
									cooldown = true
									wait(0.5)
									cooldown = false
								end
							end
						end
					end
				end
			end
		end)
	end
end

With RemoteFunctions

inventoryremotes.EquipItem:FireServer(items.name, "Unequipped", "Weapon", items.Tool)

would become

items.Tool.Value = inventoryremotes.EquipItem:InvokeServer(items.name, "Unequipped", "Weapon")

and on the server instead of multiple cases like this

object.Value = selectedItem

you would just put

return selectedItem

at the end of the function

With all due respect though your approach is quite ugly. As a professional software developer I would do it very different. In software development we have a principle “a function should do only one thing” it makes code much cleaner and re-usable. In your approach both the client and server code is bundling everything into one function, which is doing many things via nested if…else statements. In both scripts you clearly know the names associated to items or item containers so instead of having one massive if block with conditions based on these names your code would be much cleaner and easier to maintain later if you separated the many conditions into multiple functions and had multiple events like EquipWeapon, EquipFruit, EnequipWeapon and UnequipFruit. This would allow you to consilidate some of your repeated code into helper functions. Happy to provide alternative versions of the two scripts written in Clean Code style.

1 Like