Design patterns for Game menu / shop subsystem

I’m trying to decide how to do the UI system for a game I’m working on. The first question I’m running into is just whether to do it on the client or the server. I know what you’re thinking. “OMG of course you do UI on the client!” But is that really the only way?

Consider this scenario: You want a block that when you touch that block, a shop opens. Now, when I go over to the block in Explorer, I can either add a LocalScript or a Script. If I add a LocalScript though, it doesn’t run. If I add a Server Script, it does. So to do this on the server, all I need to do is add a Server Script, connect a Touched event, and in the Touched event, Clone the part and parent it to the PlayerGui of whoever touched the part.

Also consider that I might want arbitrarily many shops throughout the game that each sell different things or have different interactions associated with them. It seems cleaner and simpler if the server just looks at where you are in the world and clones the right shop into your PlayerGui.

Doing this on the client seems clunky. The server script still has the Touched event on the part, but now it fires a RemoteEvent to the client to open the shop, then the shop fires a RemoteEvent back when it makes an interaction, server then validates and responds with whether the transaction succeeded. Minimum of 3 RemoteEvents per shop.

Another idea would be for me to even do the Touched event on the client, so basically UI is 100% on the client, except for making a purchase, which is validated on the server. Now I’m down to 2 RemoteEvents per shop (or maybe 1 RemoteFunction), but getting code to run on the client is annoyingly difficult and high maintenance since LocalScripts don’t automatically run like server scripts do.

I could have one giant InitializeShopTriggers() script under StarterPlayerScripts that just goes through my Workspace world and connects Touched events to everything, but maybe all shop locations are not even cloned into the Workspace on startup, so I’m looking for advice on how to effectively manage all of this.

Hopefully this all makes sense.

Not the only way, but it’s best to

Like you said, “Another idea would be for me to even do the Touched event on the client, so basically UI is 100% on the client, except for making a purchase, which is validated on the server.”, that’s a good idea.

True, but limit calculations on the server(for non-user-data purposes only) because the client can handle so much more than the server

Refer to the answer on the above, with that you just need to use one remote event

1 Like

The biggest thing I’ve been struggling with is how to set this all up on the client. On the server you just add your Script under the part that triggers it, and in the script you connect a Touched event. Then you run your game and boom, you step on the part and your code runs. This isn’t really possible with a LocalScript because the code doesn’t run when it’s under a Part, it has to be under StarterPlayerScripts (which I find extremely frustrating btw).

So say I dynamically clone my shops into the game based on some condition. None of the Touched events are set up on the client when the newly created object is touched, and there’s no easy way to set them up either.

However, I think I just figured out a solution. I put a folder called RunLocal under my part, and under this folder I put as many ModuleScripts as I want, and call them anything.

In ReplicatedFirst, I make a LocalScript with only this code:

game.Workspace.DescendantAdded:Connect(function(Descendant)
	if Descendant.Parent.Name == "RunLocal" and Descendant.Parent:IsA("Folder") and Descendant:IsA("ModuleScript") then
		require(Descendant)
	end
end)

now I just put a ModuleScript under my shop trigger part, have it set up the Touched events when it runs, and everything works. Running code locally works exactly like it does on the server.

Is there a better way?

Actually, it should be more frustrating to so it server sided, because then you would have to find that player who touched it and find the frame you would have to open it, then open it, taking way more computing power than if it were to be done on the client.

I recommend doing the opening on the client like I’ve said before. Have different shops in different screen guis and have a script for each of them detecting if the corresponding part was touched or not.

Refer to the answer above, if you want to, I can explain furthermore.