More efficient way to handle events?

local GameFunc = {}
local players = game:GetService("Players")
local UI = script:WaitForChild("ChoiceTemplate")

local GoodChoices = {
	--// Health //--
	["IncreaseHP"] = { -- This will be the ID of the event.
		Display = "Gain %d max HP.", --> Format with amount of HP gained. (Randomized), appears in the GUI
		Rarity = 1  -- How rare the event is, the lower the rarer.
	},

	--// DAMAGE //--
	["IncreaseDMG"] = {
		Display = "Deal %d more damage.",
		Rarity = 1 
	},

	--// JUMPHEIGHT //--
	["IncreaseJP"] = {
		Display = "Jump %d studs higher.",
		Rarity = 1 
	},

	--// WALKSPEED //--
	["IncreaseWS"] = {
		Display = "Walk %d studs/s faster.",
		Rarity = 1 
	},
}
local BadChoices = {
	["DecreaseHP"] = {
		Display = "Lose %d max HP", --> Format with amount of HP lost. (Randomized)
		Rarity = 1 
	},
	["DecreaseDMG"] = {
		Display = "Gain %d more damage.",
		Rarity = 1 
	},
	["DecreaseJP"] = {
		Display = "Jump %d studs lower.",
		Rarity = 1,
	},
	["DecreaseWS"] = {
		Display = "Walk %d studs/s slower.",
		Rarity = 1 
	},
}

GameFunc.GoodChoices = GoodChoices
GameFunc.BadChoices = BadChoices

--//// RARITY / WEIGHT CALCULATIONS \\\\--
function GameFunc:SelectChoice(choices)
	local TotalWeight = 0
	for _, choice in pairs(choices) do
		TotalWeight = TotalWeight + (1 / choice.Rarity)
	end
	
	local RandomWeight = math.random() * TotalWeight
	local CumulativeWeight = 0
	
	for INDEX, choice in pairs(choices) do
		CumulativeWeight = CumulativeWeight + (1 / choice.Rarity)
		if RandomWeight <= CumulativeWeight then
			return INDEX, choices[INDEX]
		end
	end
end

function GameFunc:SendChoice()
	local currentParticipants = players:GetPlayers()
	
	for _, player in pairs(currentParticipants) do
		if  player:IsA("Player") and player.Team == game:GetService("Teams").Participating then
			if player.Character:FindFirstChild("Humanoid").Health > 0 then
				local UiClone = UI:Clone()
				local choice1 = UiClone:WaitForChild("ChoiceFrame1")
				local choice2 = UiClone:WaitForChild("ChoiceFrame2")
				
				local indexGoodResult1, choiceGood1 = GameFunc:SelectChoice(GoodChoices)
				local indexGoodResult2, choiceGood2 = GameFunc:SelectChoice(GoodChoices)
				
				local indexBadResult1, choiceBad1 = GameFunc:SelectChoice(BadChoices)
				local indexBadResult2, choiceBad2 = GameFunc:SelectChoice(BadChoices)
				
				choice1.Effect1.Text = GameFunc:SelectChoice(GoodChoices)
				
			end
		end
	end
end

return GameFunc

I’m making a sort of would you rather game to say the least. Here’s the thing, I don’t know how to handle it properly. I don’t want to handle things on the client for obvious reasons, but I don’t know how I’d handle things on the server.
For instance, the INDEX is what is considered the ID of the result, so I’d need to move it to the server and check the INDEX to see what type of event it is. Then, simply do the thing.

I’d like a little insight on how to do what I want.
This is the hierarchy of the GUI:
image

2 Likes

Fire an event to all clients with what event has started. Then fire an event from client stating the players choice. Don’t clone the uis to the players on server just have it on client.

You could use a remote event to send a signal to the server that the player made then do all the calculations on the server.

Local Script

Button.MouseButton1Click:Connect(function()
   game.ReplicatedStorage:FireServer(choice) --tell the server the choice that was made
end)

Server Script

game.ReplicatedStorage.choiceEvent.OnServerEvent:Connect(function(plr, choice)
   --do the calculations here

  game.ReplicatedStorage.choiceEvent:FireClient(plr, result) --if you want to send the result back to the client you can do this
end)
1 Like
  1. Create a remote event, which the client will fire to and the server will do something when it’s fired.
  2. Create a module with your choices.
  3. Require the module on the server.
  4. When the player picks a choice, fire the remote event and pass the ID as a parameter.
  5. Server listens to the fired event of the remote, searches the module using the ID.
  6. Server applies it.

Client

local ChooseOptionRemote = game.ReplicatedStorage.ChooseOption

local function OptionChosen(option_ID)
	ChooseOptionRemote:FireServer(option_ID)
end

Server

local ChooseOptionRemote = game.ReplicatedStorage.ChooseOption
local Modifiers = game.ReplicatedStorage.Modifiers

ChooseOptionRemote.OnServerEvent:Connect(function(player, ID)
	local event = Modifiers[ID]
	-- Apply event
end)

Module

local module = {
	['Choice1']= {},
	['Choice2']={}
}

return module
1 Like

@bytesleuth @goldenty34 @ExercitusMortem
I am afraid neither of your replies are what I am exactly looking for, in that I do not want to rewrite my module. To clarify: I want to use a module to run any function needed for the game, the game functions as a PVP game with Would you Rather elements. An example provided below:
image

What I am going for:
I want to:

  1. Clone a gui to every player.
  2. Somehow make sure the bad and good effects apply when a normal script handles it once a choice is made by the player.

I believe I know a way but I am unsure if it is efficient and advised, e.g:
image
store the IDs of both events inside of a StringValue, then fire the values via a remote event into the server event.

Please tell me if this clarifies things, or if more details are needed.

1 Like

So, you want to store the IDs of both events inside a StringValue and then fire from the client a RemoteEvent?

1 Like

Once the button is clicked, yes.

1 Like

I haven’t double checked cause I can’t access Studio where I am rn but from what I know, the value of a StringValue can be modified by the client and if fired as a parameter to the server, the client could manipulate the value to get the IDs of the events and modify them.

1 Like

Then what should I do?
(max chars)

1 Like

It feels like you are overcomplicating this.
Say you have a round system like this

while true do
	-- Start Round
	task.wait(10)
end

where a new round is every 10 seconds.
In the start round part of the code you want to pick 2 downsides and 2 upsides.
We should boil down the choices to choice 1 and choice 2.
The server should tell the clients what the sides are. Do that using a remote event.

StartRound:FireAllClients(Choice.ExplodeHead, Choice.InfiniteBacon, Choice.NoBacon, Choice.DontExplodeHead)

I would have a module with choice enums that both server and client can access.
Structured like so:

local Choice = {
	ExplodeHead = 1,
	InfiniteBacon = 2,
	NoBacon = 3,
	DontExplodeHead = 4,
}

return Choice

First param is first choice upside, second param is first choice downside and you get the idea.
On the client you display the choices. Have a dictionary representing what each choice enum means in text.

local text = {
	[Choice.ExplodeHead] = "Your head explodes!!"
}

When the player clicks one of the buttons you send their choice.
In this case the player picks choice 1.
The server already knows what that is so we don’t send the enums.

SendChoice:FireServer(1)

Then we connect on server.
We have a dictionary corresponding enums to functions. I’m sending player as an argument if we need it.
Set the choiceEnums when a round starts. In this example I’ve just set it to demonstrate.

local choiceFunctions = {
	[Choice.ExplodeHead] = function(player)
		- - Explode players head
	end,
}

local choiceEnums = {
	{
		Choice.ExplodeHead,
		Choice.InfiniteBacon,
	},
	{
		Choice.NoBacon,
		Choice.DontExplodeHead,
	},
}

SendChoice.OnServerEvent:Connect(function(player, choiceNumber)
	for _, enum in choiceEnums[choiceNumber] do
		choiceFunctions[enum](player)
	end
end)
1 Like

My comment contains a simple system for client-server communication. You can implement it with your module, too. But I’m not going to do it for you.

1 Like