Through my testing, this has seemed to work pretty consistently, and I haven’t had any problems with stuff not being returned. Basically the client has 30 seconds to make a move, if they dont then I’ll get a random move generated. However, I don’t know how exploits work, so I’m unsure if this system could be ‘rigged’
I am aware of exploiters being able never return the InvokeClient, but the delay function seems to remedy that problem. I just wanna make sure this code is as efficient as can be as this seems a lot more linear than using remote events and waiting for an event to be fired back.
local Result
coroutine.wrap(function()
Result = PlacePiece:InvokeClient(PlacingPlayer) -- Get player to place piece
end)()
WaitTurn:FireClient(WaitingPlayer) -- Make player wait turn
delay(Timer, function() -- Prevents nothing being returned from client
if not Result then
Result = true -- Get randomized default result
end
end)
-- Wait for a result
repeat
wait()
until Result
if Result then
print("WE GOT SOMETHING FROM", PlacingPlayer)
Board.Turn = Board.Turn == 1 and 2 or 1
end
If InvokeClient has no timeout of its own it’s likely that you will end up leaking memory from this. It’s also possible that an error could show part of the server stack trace if those still behave like that, which could expose information for reverse engineers.
Relying on callbacks in this case seems messier than with events. Have you considered a pattern where only 1 connection is made like this?
local active, inactive = player1, player2
local timeout = os.clock() + 30
local function on_player_place(player, result)
if player ~= active then return end
active, inactive = inactive, active
timeout = os.clock() + 30
-- do something with the result
end
PlacePiece.OnServerEvent:Connect(on_player_place)
while game_running do
if os.clock() > timeout then
-- handle inactivity
timeout = os.clock() + 30
end
wait(1)
end
I was worried about using a remove event due to my games being set up in a for loop, with while loop inside as well, and possibility of other games affecting the wrong game
for _, board in pairs(CollectionService:GetTagged("Connect4")) do
if board.PrimaryPart then
local Board = GenerateGame(board) -- Generate board
-- Go through all seats
for _, seat in pairs(board:GetDescendants()) do
if seat:IsA("Seat") then
seat.Changed:Connect(function()
if seat.Occupant then -- Player has sat down
local Character = seat.Occupant.Parent
local Player = Players:GetPlayerFromCharacter(Character)
if not Player then return end
if not Board then return end -- Game doesn't exist
Board[seat.Parent.Name] = Player
if Board.Seat1 and Board.Seat2 then
Board.InProgress = true -- Start game
StartMinigame:FireClient(Board.Seat1, "Connect4", seat, Board.Seat2)
StartMinigame:FireClient(Board.Seat2, "Connect4", seat, Board.Seat1)
board.InProgress.Value = true
board.Billboard.Enabled = false
else -- Only 1 player
board.Billboard.Enabled = true
end
if not Board.InProgress then return end -- No game
while Board.InProgress do
local PlacingPlayer = Board["Seat" .. Board.Turn]
local WaitingPlayer = Board["Seat" .. (Board.Turn == 1 and 2 or 1)]
-- Etc....
end
end
end
end
end
end
end
And if whether or not I should be do the listen for OnServerEvent within the while loop, or outside everything, memory leaks being created due to multiple listens of OnServerEvent, etc.