Logo Pastebin.fr
Pastebin

Retrouvez, créez et partagez vos snippets en temps réel.

DonationManager_ServerScript

--!strict

-- ============================================
-- DONATION MANAGER - SERVER SCRIPT
-- Gère DataStore, ProcessReceipt et Leaderboard
-- ============================================
-- EMPLACEMENT: ServerScriptService > DonationSystem > DonationManager

-- Services
local DataStoreService = game:GetService("DataStoreService")
local MarketplaceService = game:GetService("MarketplaceService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

-- DataStore
local DATASTORE_NAME = "DonationData_v1"
local donationDataStore = DataStoreService:GetDataStore(DATASTORE_NAME)

-- Configuration des produits (REMPLACEZ PAR VOS VRAIS PRODUCT IDs!)
local DONATION_PRODUCTS = {
	[1234567890] = {Name = "STARTER", Amount = 10},
	[1234567891] = {Name = "SUPPORTER", Amount = 50},
	[1234567892] = {Name = "PREMIUM", Amount = 100},
	[1234567893] = {Name = "ELITE", Amount = 250},
	[1234567894] = {Name = "LEGENDARY", Amount = 500},
	[1234567895] = {Name = "MYTHIC", Amount = 1000}
}

-- Cache du leaderboard (en mémoire pour performance)
local leaderboardCache: {{Username: string, UserId: number, TotalDonated: number, Rank: number}} = {}
local cacheLastUpdated = 0

-- Types
type PlayerData = {
	Username: string,
	TotalDonated: number,
	LastUpdated: number
}

type DonatorData = {
	Username: string,
	UserId: number,
	TotalDonated: number,
	Rank: number
}

-- RemoteEvents/Functions
local donationSystemFolder = ReplicatedStorage:WaitForChild("DonationSystem")
local donationPurchasedEvent = donationSystemFolder:WaitForChild("DonationPurchased") :: RemoteEvent
local getLeaderboardFunction = donationSystemFolder:WaitForChild("GetLeaderboard") :: RemoteFunction
local getPlayerStatsFunction = donationSystemFolder:WaitForChild("GetPlayerStats") :: RemoteFunction

-- ============================================
-- DATASTORE FUNCTIONS
-- ============================================

local function getDataStoreKey(userId: number): string
	return `Player_{userId}`
end

-- Charge les données d'un joueur
local function loadPlayerData(userId: number): PlayerData?
	local key = getDataStoreKey(userId)
	local success, result = pcall(function()
		return donationDataStore:GetAsync(key)
	end)
	
	if success and result then
		return result
	elseif success then
		-- Nouveau joueur, données par défaut
		return {
			Username = "Unknown",
			TotalDonated = 0,
			LastUpdated = os.time()
		}
	else
		warn(`[DonationManager] Erreur lors du chargement des données pour UserId {userId}: {result}`)
		return nil
	end
end

-- Sauvegarde les données d'un joueur
local function savePlayerData(userId: number, data: PlayerData): boolean
	local key = getDataStoreKey(userId)
	local success, errorMsg = pcall(function()
		donationDataStore:SetAsync(key, data)
	end)
	
	if not success then
		warn(`[DonationManager] Erreur lors de la sauvegarde pour UserId {userId}: {errorMsg}`)
	end
	
	return success
end

-- ============================================
-- DONATION LOGIC
-- ============================================

-- Ajoute une donation au total du joueur
local function addDonation(userId: number, username: string, amount: number): boolean
	print(`[DonationManager] Ajout donation: {username} ({userId}) - {amount} Robux`)
	
	-- Charge les données actuelles
	local playerData = loadPlayerData(userId)
	if not playerData then
		warn(`[DonationManager] Impossible de charger les données pour {userId}`)
		return false
	end
	
	-- Met à jour les données
	playerData.Username = username
	playerData.TotalDonated = playerData.TotalDonated + amount
	playerData.LastUpdated = os.time()
	
	-- Sauvegarde
	local success = savePlayerData(userId, playerData)
	
	if success then
		print(`[DonationManager] ✅ Donation enregistrée! Nouveau total: {playerData.TotalDonated} Robux`)
		
		-- Met à jour le cache du leaderboard
		updateLeaderboardCache()
		
		-- Notifie tous les clients
		donationPurchasedEvent:FireAllClients(userId, username, amount)
	end
	
	return success
end

-- ============================================
-- LEADERBOARD FUNCTIONS
-- ============================================

-- Met à jour le cache du leaderboard
function updateLeaderboardCache()
	local allDonators: {DonatorData} = {}
	
	-- Récupère tous les joueurs connectés + leurs données
	for _, player in Players:GetPlayers() do
		local data = loadPlayerData(player.UserId)
		if data and data.TotalDonated > 0 then
			table.insert(allDonators, {
				Username = player.Name,
				UserId = player.UserId,
				TotalDonated = data.TotalDonated,
				Rank = 0 -- Sera défini après le tri
			})
		end
	end
	
	-- Note: Dans un vrai système, vous voudriez aussi scanner le DataStore
	-- pour les joueurs non connectés avec OrderedDataStore
	
	-- Trie par TotalDonated (décroissant)
	table.sort(allDonators, function(a, b)
		return a.TotalDonated > b.TotalDonated
	end)
	
	-- Assigne les rangs
	for rank, donator in allDonators do
		donator.Rank = rank
	end
	
	leaderboardCache = allDonators
	cacheLastUpdated = os.time()
	
	print(`[DonationManager] Cache leaderboard mis à jour: {#allDonators} donateurs`)
end

-- Retourne le Top N donateurs
local function getTopDonators(limit: number): {DonatorData}
	-- Rafraîchit le cache si plus vieux de 30 secondes
	if os.time() - cacheLastUpdated > 30 then
		updateLeaderboardCache()
	end
	
	local topDonators: {DonatorData} = {}
	for i = 1, math.min(limit, #leaderboardCache) do
		table.insert(topDonators, leaderboardCache[i])
	end
	
	return topDonators
end

-- Retourne les stats d'un joueur spécifique
local function getPlayerStats(userId: number): {Rank: number, TotalDonated: number}
	local data = loadPlayerData(userId)
	if not data then
		return {Rank = 0, TotalDonated = 0}
	end
	
	-- Trouve le rang dans le cache
	local rank = 0
	for i, donator in leaderboardCache do
		if donator.UserId == userId then
			rank = i
			break
		end
	end
	
	return {
		Rank = rank,
		TotalDonated = data.TotalDonated
	}
end

-- ============================================
-- MARKETPLACE PROCESSRECEIPT
-- ============================================

-- Callback automatique de Roblox lors d'un achat
local function processReceipt(receiptInfo)
	local userId = receiptInfo.PlayerId
	local productId = receiptInfo.ProductId
	
	print(`[DonationManager] ProcessReceipt appelé: UserId={userId}, ProductId={productId}`)
	
	-- Vérifie si c'est un produit de donation
	local productConfig = DONATION_PRODUCTS[productId]
	if not productConfig then
		warn(`[DonationManager] ProductId {productId} non reconnu`)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	
	-- Récupère le joueur
	local player = Players:GetPlayerByUserId(userId)
	if not player then
		warn(`[DonationManager] Joueur {userId} non trouvé`)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	
	-- Ajoute la donation
	local success = addDonation(userId, player.Name, productConfig.Amount)
	
	if success then
		print(`[DonationManager] ✅ Achat traité: {player.Name} a donné {productConfig.Amount} Robux`)
		return Enum.ProductPurchaseDecision.PurchaseGranted
	else
		warn(`[DonationManager] ❌ Échec du traitement de l'achat`)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
end

-- Enregistre le callback
MarketplaceService.ProcessReceipt = processReceipt

-- ============================================
-- REMOTE FUNCTION HANDLERS
-- ============================================

-- Gère les demandes de leaderboard des clients
getLeaderboardFunction.OnServerInvoke = function(player: Player, limit: number)
	limit = limit or 10
	return getTopDonators(limit)
end

-- Gère les demandes de stats des clients
getPlayerStatsFunction.OnServerInvoke = function(player: Player, userId: number?)
	userId = userId or player.UserId
	return getPlayerStats(userId)
end

-- ============================================
-- PLAYER EVENTS
-- ============================================

-- Sauvegarde finale quand un joueur quitte
Players.PlayerRemoving:Connect(function(player)
	local data = loadPlayerData(player.UserId)
	if data then
		savePlayerData(player.UserId, data)
		print(`[DonationManager] Données sauvegardées pour {player.Name}`)
	end
end)

-- Met à jour le cache au démarrage
task.wait(2) -- Attend que les joueurs se connectent
updateLeaderboardCache()

-- Auto-refresh du cache toutes les 60 secondes
task.spawn(function()
	while true do
		task.wait(60)
		updateLeaderboardCache()
	end
end)

print("✅ [DonationManager] Système initialisé avec succès")
print(`📊 [DonationManager] {#DONATION_PRODUCTS} produits configurés`)
print(`💾 [DonationManager] DataStore: {DATASTORE_NAME}`)

Créé il y a 1 semaine.

Rechercher un Pastebin

Aucun paste trouvé.