Client and Module Script Communication Help

Hello! This is kinda a lot and I really don’t expect anyone to solve my issue here but I am using Tags and basically I have 2 Milkshake glasses but with different :GetFullName() (workspace paths), but I don’t want to have to double my code when I could just send the item path to the module.

If this doesn’t make sense lol here’s my question, how would I use the correct ItemPath in the moudle script

Client:

for _, MilkshakeGlass in game:GetService("CollectionService"):GetTagged("MilkshakeGlass") do
	local ClickDetector = MilkshakeGlass.MilkshakeGlassClickDetector
	spawn(function()
		while wait() do
			MilkshakeGlass.Capacity.Overhead.Main.Image.Rotation = MilkshakeGlass.Capacity.Overhead.Main.Image.Rotation + 5
		end
	end)
	ClickDetector.MouseClick:Connect(function()
		if LocalPlayer:GetRankInGroup(GameDataModule.GroupID) >= RankDataModule.JuniorBarista then
			GetItemEvent:InvokeServer("MilkshakeGlass")
			CorrectItemPath:FireServer(MilkshakeGlass:GetFullName())
		end
	end)
end

Server Script:

local CorrectItemPath = game.ReplicatedStorage.Events.RemoteEvents.CorrectItemPath
local ActualItemPath

CorrectItemPath.OnServerEvent:Connect(function(ItemPath)
	ActualItemPath = ItemPath
end)

local function ClickEvent(Player, ItemType)
	if Player:GetRankInGroup(GameDataModule.GroupID) >= RankDataModule.JuniorBarista then
		if ItemType == "MilkshakeGlass" then
			GetItemModule.MilkshakeGlass(Player)
		end
	else
		Player:Kick(KickMessageModule.GetItemHandler)
	end
end

GetItemEvent.OnServerInvoke = ClickEvent

Module Script:

local CorrectItemPath = game.ReplicatedStorage.Events.RemoteEvents.CorrectItemPath
local ActualItemPath

CorrectItemPath.OnServerEvent:Connect(function(ItemPath)
	ActualItemPath = ItemPath
end)

function GetItem.MilkshakeGlass(Player)
	local ItemPath = ActualItemPath
	local ProgressBar = ItemPath.Capacity.Overhead.Main.Bar.Progress
	local RemainingText = ItemPath.Capacity.Overhead.Main.Remaining
	local Remaining = ItemPath:GetAttribute("Remaining")
	local Active = ItemPath:GetAttribute("Active")
	
	if Active == true then
		if Remaining == 1 then
			local CopiedItem = MilkshakeGlass:Clone()
			ItemPath:SetAttribute("Remaining", Remaining - 1)
			ItemPath:SetAttribute("Active", false)
			ItemPath:SetAttribute("CanBeRestocked", true)
			ItemPath.Hitbox.GetItem:Play()
			
			TweenService:Create(ProgressBar, TweenInformation, {Size = UDim2.new(0, 0, 1, 0)}):Play()
			RemainingText.Text = ItemPath:GetAttribute("Remaining")
			CopiedItem.Parent = Player.Backpack
			
			wait(NextPossibleGetItemTime)
			
			ItemPath.Capacity.Overhead.Main.Image.Visible = true
			ItemPath.Capacity.Overhead.Main.Message.Visible = true
			ItemPath.Capacity.Overhead.Main.Bar.Visible = false
			ItemPath.Capacity.Overhead.Main.Remaining.Visible = false
			ItemPath.Capacity.Overhead.Main.Header.Text = "Milkshake Glasses"
		elseif Remaining >= 2 then
			local CopiedItem = MilkshakeGlass:Clone()
			ItemPath:SetAttribute("Remaining", Remaining - 1)
			ItemPath:SetAttribute("Active", false)
			ItemPath.Hitbox.GetItem:Play()
			
			TweenService:Create(ProgressBar, TweenInformation, {Size = ProgressBar.Size - UDim2.fromScale(0.05, 0)}):Play()
			RemainingText.Text = ItemPath:GetAttribute("Remaining")
			CopiedItem.Parent = Player.Backpack
			
			wait(NextPossibleGetItemTime)
			
			ItemPath:SetAttribute("Active", true)
		end
	end
end
1 Like

I decided to do this because I realized that when I would click on either of the Milkshake glasses only one of them would update the value and do other stuff so I want it to work on the correct one so I tried using a RemoteEvent and it isn’t working.

1 Like

Try this :point_down::point_down::point_down:

CorrectItemPath.OnServerEvent:Connect(function(Item) -- Item is a string with the name of the milkshake that got clicked
if Item == "Milkshake1" then
-- Update the value for the first milkshake
elseif Item == "Milkshake2" then
-- Update the value for the second milkshake
end
end)
3 Likes

See, the issue im having is in the module script, I can clone as many Milkshake glasses as I want but each Milkshake glass has a BillboardGui that displays how many are left before it has to be restocked

1 Like

Well in that case you could use loadstring() since GetFullName() returns a string. First, you must enable it. ServerScriptStorage has a property called LoadStringEnabled which you must enable in order for loadstring() to work. Once you have it enabled, here’s how you use loadstring().

CorrectItemPath.OnServerEvent:Connect(function(ItemPath)
	ActualItemPath = loadstring(ItemPath)
end)

However, you must be careful when you use it or else your game can be exposed to exploits.

2 Likes

This goes in the module script and replaces this :point_down: right?

How so?

1 Like

There’s quite a bit going on here. Can you elaborate on what you’re looking to do? Are you just trying to find an item in the workspace by its full name?

CollectionService:GetTagged already returns a table of tagged instances, is there a reason you need to use :GetFullName to find the instance instead of just using the table of instances?

2 Likes

Yes, this :point_down::point_down::point_down:

CorrectItemPath.OnServerEvent:Connect(function(ItemPath)
	ActualItemPath = loadstring(ItemPath)
end)

Replaces this :point_down::point_down::point_down:

CorrectItemPath.OnServerEvent:Connect(function(ItemPath)
	ActualItemPath = ItemPath
end)

And the reason your game might be exposed to exploits is because in some situations exploiters can use it to run malicious code. Example :point_down::point_down::point_down:

Your code:

local code = "print('Hi')"

loadstring(code)

The exploiter:

local code = "workspace:ClearAllChildren()"

In this example what ends up happening is that everything in the workspace gets deleted.

1 Like

you should never use loadstring, under ANY circumstances

plus that wouldn’t help as hes trying to pass in a certain path

4 Likes

I would advise against using loadstring whenever possible, there are essentially no reasons to use loadstring for non-malicious purposes, it disables Luau optimizations and is overall not secure, especially if you don’t know what you’re doing. There are a few posts on this topic but this one sums it up pretty well:

It wouldn’t work syntactically either, you’re basically just putting the following into a function, so it’s going to error when you call it:

workspace.some.path.to.item
2 Likes

Oh, I didn’t know it didn’t work with functions. Thanks for letting me know. Also, I agree with you guys, loadstring() should try to be avoided. I was just giving it as an option for him to consider.

3 Likes

Yeah sorry there is a lot but basically I have 2 Milkshake Glasses and their tagged with MilkshakeGlass and each of the Glasses have a BillBoardGUI on them displaying how many glasses are left and i’m trying to get the correct workspace path

1 Like

Couldn’t you just iterate through the table CollectionService:GetTagged returns then?

Eg.

local milkshakeGlasses = collectionService:GetTagged('MilkshakeGlass')
for i, milkshakeGlass in ipairs(milkshakeGlasses) do 
    -- update milkshake glass billboard gui
end

If you need to look in the workspace though, you can split the string up using . as a separator:

local path = milkshakeGlass:GetFullName()
-- so if path is workspace.someModel.MilkshakeGlass, you can split it up using "." as separator
local splitPath = path:split('.')
-- so now splitPath would be a table: {"Workspace", "someModel", "MilkshakeGlass"}
local last = game
for i, childName in ipairs(splitPath) do
    last = last:WaitForChild(childName) -- so it would do game:WaitForChild('Workspace') (you can probably create an exception when i == 1 to use getservice instead of waitforchild but just for example purposes) -> workspace:WaitForChild('SomeModel') and so on to the end of the table
end
-- now, last should be equal to the milkshake glass
print(last) -- should be MilkshakeGlass
2 Likes

Before I found out about this issue in the past this user to be local ItemPath = game.workspace.TheRestOfThePath but that doesn’t work because each Milkshake Glass displays a Billboard GUI

1 Like

Is this in the LocalScript? If so how would this update in the module?

Here’s what’s going on.
https://gyazo.com/f450759fcc52eda2fc394ad1cb5ed04c

1 Like

Just wondering if anyone know’s how I could do this :smiley:

loadstring() can’t be exploited unless there is a back door in your game. This is because it can only be used on the server, hence the property being located in ServerScriptService.

@PostVivic

Oops I meant to reply but guess I forgot. My guess is that this is happening because you have more than one glass with the same name in the workspace. Couldn’t you just pass the actual object in the workspace to the server instead of its path? Then you know for sure that you’re passing the correct object instead of going by its name, which is a nonunique identifier.

Yeah I have more then one, how would I pass the object to the server though?

Just pass it as you’d normally pass any argument (eg. CorrectItemPath:FireServer(MilkshakeGlass))