Explorer
KNOW-PAT-086

FiveM - Casino Game Loop Server-Side : mélange Fisher-Yates et callbacks d'argent

Domaine
fivem
Type
pattern
Priorité
P2

Parent : [[INDEX-FIVEM-GAMEPLAY]]

FiveM - Casino Game Loop Server-Side : mélange Fisher-Yates et callbacks d'argent

Problème

Un jeu de casino (blackjack) doit être entièrement server-authoritative pour éviter le cheating (carte peeking, modification du deck). Le mélange, la distribution, et la gestion de l'argent doivent être contrôlés par le serveur.

Solution

Mélange Fisher-Yates server-side, gestion de table multi-joueurs, callbacks d'argent externes via exports pour découpler la logique de jeu de la logique économique.

local deck = {}
local suits = {'hearts', 'diamonds', 'clubs', 'spades'}
local ranks = {'2','3','4','5','6','7','8','9','10','J','Q','K','A'}

function NewDeck()
    deck = {}
    for _, suit in ipairs(suits) do
        for _, rank in ipairs(ranks) do
            table.insert(deck, {suit = suit, rank = rank, value = CardValue(rank)})
        end
    end
end

function ShuffleDeck()
    for i = #deck, 2, -1 do
        local j = math.random(i)
        deck[i], deck[j] = deck[j], deck[i]
    end
end

function DealCard()
    return table.remove(deck)
end

-- Callbacks d'argent découplés via exports (à implémenter par l'intégrateur)
local getChipsCallback, takeChipsCallback, giveChipsCallback

exports("SetGetChipsCallback", function(cb) getChipsCallback = cb end)
exports("SetTakeChipsCallback", function(cb) takeChipsCallback = cb end)
exports("SetGiveChipsCallback", function(cb) giveChipsCallback = cb end)

function GetPlayerChips(source)
    if getChipsCallback then return getChipsCallback(source) else return 0 end
end

Pourquoi

  • Fisher-Yates garantit une distribution uniforme (pas de biais)
  • Server-side empêche le peeking de deck côté client
  • Callbacks externes permettent d'intégrer n'importe quel système économique (ESX, QBCore, ox_inventory)

Quand l'utiliser

  • Jeux de cartes, roulette, machines à sous
  • Tout système de jeu avec aléatoire server-authoritative

Quand NE PAS l'utiliser

  • Jeux PvP compétitifs (le hasard du deck est une mécanique de casino, pas d'esport)
  • Si les callbacks d'argent ne sont pas implémentés → argent free (voir anti-pattern associé)

Exemples

Correct

-- Mélange + distribution + scoring entièrement server-side
RegisterNetEvent('blackjack:placeBet')
AddEventHandler('blackjack:placeBet', function(betAmount)
    local src = source
    local chips = GetPlayerChips(src)
    if chips < betAmount then return end
    TakeChips(src, betAmount)
    local hand = {DealCard(), DealCard()}
    local dealer = {DealCard(), DealCard()}
    TriggerClientEvent('blackjack:showHand', src, hand, dealer[1])
end)

Incorrect

-- Le client demande les cartes → trust abuse possible
RegisterNetEvent('blackjack:hit')
AddEventHandler('blackjack:hit', function()
    local card = DealCard() -- Serveur distribue
    -- MAIS le client peut envoyer l'event sans être à la table
    TriggerClientEvent('blackjack:receiveCard', source, card)
end)

Références

  • kgv-blackjack/server.lua L1-200
  • kgv-blackjack/client.lua L12-30