2025-07-02 00:21:32 +08:00
|
|
|
-- 数据存储代理
|
|
|
|
local ArchiveProxy = {}
|
|
|
|
|
|
|
|
--> Services
|
|
|
|
local CollectionService = game:GetService("CollectionService")
|
|
|
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
|
|
local DataStoreService = game:GetService("DataStoreService")
|
|
|
|
local ServerStorage = game:GetService("ServerStorage")
|
|
|
|
local RunService = game:GetService("RunService")
|
|
|
|
local Players = game:GetService("Players")
|
|
|
|
|
|
|
|
--> Dependencies
|
|
|
|
local GameConfig = require(ReplicatedStorage.Data.GameConfig)
|
|
|
|
local ContentLibrary = require(ReplicatedStorage.Modules.ContentLibrary)
|
|
|
|
|
|
|
|
--> Variables
|
2025-07-03 01:48:06 +08:00
|
|
|
local UserData = DataStoreService:GetDataStore("UserData3")
|
2025-07-02 00:21:32 +08:00
|
|
|
local SameKeyCooldown = {}
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
function ArchiveProxy:IsPlayerDataLoaded(Player: Player)
|
|
|
|
local timeout = 5
|
|
|
|
local start = os.clock()
|
|
|
|
while not Player:GetAttribute("DataLoaded") do
|
|
|
|
if os.clock() - start > timeout then
|
|
|
|
return false -- 超时
|
|
|
|
end
|
|
|
|
Player:GetAttributeChangedSignal("DataLoaded"):Wait()
|
|
|
|
end
|
|
|
|
return true -- 成功加载
|
|
|
|
end
|
|
|
|
|
2025-07-09 23:59:56 +08:00
|
|
|
function ArchiveProxy:CleanPlayerData(Player: Player)
|
|
|
|
if not ArchiveProxy.pData[Player.UserId] then warn('CleanPlayerData: ', Player.Name, '数据不存在') return end
|
|
|
|
ArchiveProxy.pData[Player.UserId] = {}
|
|
|
|
print("清除数据成功")
|
|
|
|
end
|
|
|
|
|
2025-07-02 00:21:32 +08:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
local PlayerData = Instance.new("Configuration")
|
|
|
|
PlayerData.Name = "PlayerData"
|
|
|
|
PlayerData.Parent = ReplicatedStorage
|
|
|
|
|
|
|
|
local _warn = warn
|
|
|
|
local function warn(warning: string)
|
|
|
|
_warn("DataManager Failure: ".. warning)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Attempt to save user data. Returns whether or not the request was successful.
|
|
|
|
local function SaveData(Player: Player): boolean
|
|
|
|
if not Player:GetAttribute("DataLoaded") then
|
|
|
|
return false
|
|
|
|
end
|
2025-07-03 01:48:06 +08:00
|
|
|
|
|
|
|
local DataToSave = ArchiveProxy.pData[Player.UserId]
|
2025-07-02 00:21:32 +08:00
|
|
|
|
|
|
|
-- Save to DataStore --
|
|
|
|
local Success
|
|
|
|
for i = 1, 3 do
|
|
|
|
Success = xpcall(function()
|
|
|
|
return UserData:SetAsync("user/".. Player.UserId, DataToSave, {Player.UserId})
|
|
|
|
end, warn)
|
|
|
|
|
|
|
|
if Success then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
task.wait(6)
|
|
|
|
end
|
|
|
|
|
|
|
|
if Success then
|
|
|
|
print(("DataManager: User %s's data saved successfully."):format(Player.Name))
|
|
|
|
else
|
|
|
|
warn(("DataManager: User %s's data failed to save."):format(Player.Name))
|
|
|
|
end
|
|
|
|
|
|
|
|
return Success
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Attempt to load user data. Returns whether or not the request was successful, as well as the data if it was.
|
|
|
|
local function LoadData(Player: Player): (boolean, any)
|
|
|
|
local Success, Response = xpcall(function()
|
|
|
|
return UserData:GetAsync("user/".. Player.UserId)
|
|
|
|
end, warn)
|
|
|
|
|
|
|
|
if Success and Response then
|
2025-07-03 01:48:06 +08:00
|
|
|
print(("DataManager: User %s's data loaded into the game."):format(Player.Name))
|
2025-07-02 00:21:32 +08:00
|
|
|
else
|
|
|
|
print(("DataManager: User %s had no data to load from."):format(Player.Name))
|
|
|
|
end
|
|
|
|
return Success, Response
|
|
|
|
end
|
|
|
|
|
|
|
|
local function OnPlayerAdded(Player: Player)
|
|
|
|
local Success, Data = LoadData(Player)
|
|
|
|
|
|
|
|
if not Success then
|
|
|
|
CollectionService:AddTag(Player, "DataFailed")
|
|
|
|
Player:Kick("Data unable to load. DataStore Service may be down. Please rejoin later.")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if not ArchiveProxy.pData then
|
|
|
|
ArchiveProxy.pData = {}
|
|
|
|
end
|
2025-07-03 01:48:06 +08:00
|
|
|
|
|
|
|
-- 如果数据为空,则初始化数据
|
|
|
|
if not Data then
|
|
|
|
Data = {}
|
|
|
|
end
|
2025-07-02 00:21:32 +08:00
|
|
|
|
|
|
|
ArchiveProxy.pData[Player.UserId] = Data
|
|
|
|
Player:SetAttribute("DataLoaded", true)
|
|
|
|
end
|
|
|
|
|
2025-07-03 01:48:06 +08:00
|
|
|
local function OnPlayerRemoving(Player: string)
|
2025-07-02 00:21:32 +08:00
|
|
|
SaveData(Player)
|
|
|
|
ArchiveProxy.pData[Player.UserId] = nil
|
|
|
|
ReplicatedStorage.Remotes.PlayerRemoving:Fire(Player)
|
|
|
|
end
|
|
|
|
|
|
|
|
Players.PlayerAdded:Connect(OnPlayerAdded)
|
|
|
|
for _, Player in Players:GetPlayers() do
|
|
|
|
OnPlayerAdded(Player)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Save on leave
|
|
|
|
Players.PlayerRemoving:Connect(OnPlayerRemoving)
|
|
|
|
|
|
|
|
|
|
|
|
-- Server closing (save)
|
|
|
|
game:BindToClose(function()
|
|
|
|
task.wait(RunService:IsStudio() and 1 or 10)
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Auto-save
|
|
|
|
task.spawn(function()
|
|
|
|
while true do
|
|
|
|
task.wait(60)
|
|
|
|
for _, Player in Players:GetPlayers() do
|
|
|
|
task.defer(SaveData, Player)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
return ArchiveProxy
|