2025-08-01 19:23:12 +08:00

324 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 关卡代理
local LevelProxy = {}
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
--> Variables
local Utils = require(ReplicatedStorage.Tools.Utils)
local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy)
local MobsProxy = require(ServerStorage.Proxy.MobsProxy)
local ItemProxy = require(ServerStorage.Proxy.ItemProxy)
local TypeList = require(ServerStorage.Base.TypeList)
--> Dependencies
local Communicate = require(ServerStorage.Modules.Tools.Communicate)
--> Json
local JsonLevel = require(ReplicatedStorage.Json.Level)
local JsonParam = require(ReplicatedStorage.Json.Param)
--> Events
local BD_ChallengeEnd = ReplicatedStorage.Events.BD_ChallengeEnd
local RE_CleanPlayerPerformance = ReplicatedStorage.Events.RE_CleanPlayerPerformance
--> Constants
local STORE_NAME = "Level"
local ENUM_LEVEL_TYPE = {
Main = 1,
BossFail = 0,
}
--------------------------------------------------------------------------------
-- 初始化生成关卡目录
local LevelFolder = Utils:CreateFolder(STORE_NAME, game.Workspace)
--------------------------------------------------------------------------------
-- 获取玩家关卡文件夹
local function GetPlayerLevelFolder(Player: Player, ChildFolderName: string?)
local PlayerFolder = LevelFolder:FindFirstChild(Player.UserId)
if not PlayerFolder then warn("PlayerFolder not found", Player.UserId) return end
if ChildFolderName then
local ChildFolder = PlayerFolder:FindFirstChild(ChildFolderName)
if not ChildFolder then warn("ChildFolder not found", ChildFolderName) return end
return ChildFolder
end
return PlayerFolder
end
-- 获取玩家关卡Workspace目录
local function GetPlayerLevelWorkspaceFolder(PlayerUserId: string)
return LevelFolder:FindFirstChild(PlayerUserId)
end
-- 创建关卡信息实例
local function CreateLevelInstance(Player: Player, Folder: Instance, LevelKey: string, LevelValue: any)
if not Player or not Folder or not LevelKey then return end
local InstanceType
if type(LevelValue) == "number" then
InstanceType = "NumberValue"
elseif type(LevelValue) == "boolean" then
InstanceType = "BoolValue"
elseif type(LevelValue) == "string" then
InstanceType = "StringValue"
else
InstanceType = "NumberValue"
end
local LevelInstance = Instance.new(InstanceType)
LevelInstance.Name = LevelKey
LevelInstance.Parent = Folder
LevelInstance.Value = LevelValue
return LevelInstance
end
-- 初始化玩家关卡信息
local function ExtraAddPlayerLevel(Player: Player, LevelData: table)
if not Player or not LevelData then return end
-- 如果列表中不包含信息就添加到表中
for LevelKey, LevelValue in ENUM_LEVEL_TYPE do
if not LevelData[LevelKey] then
LevelData[LevelKey] = LevelValue
end
end
end
local EXCEPT_KEY = { "Task", "Mobs"}
local function ChangeValue(Player: Player, Folder: Instance, LevelKey: string, LevelValue: any)
if not Player or not Folder or not LevelKey then warn("LevelProxy ChangeValue", Player.UserId, Folder.Name, LevelKey, LevelValue) return end
if table.find(EXCEPT_KEY, LevelKey) then return end
local ValueInstance = Folder:FindFirstChild(LevelKey)
if not ValueInstance then warn("ValueInstance not found", LevelKey) return end
local storeTable
if Folder.Name == "Challenge" then
storeTable = LevelProxy.pData[Player.UserId]
else
storeTable = ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress
end
storeTable[LevelKey] = LevelValue
ValueInstance.Value = LevelValue
end
-- 怪物死亡,由初始化时传入
local function OnMobDied(Player: Player, Mob: TypeList.Character)
-- 怪物死亡后增加玩家货币
-- TODO这里暂时没做对应玩家属性处理
local mob_died_get = Utils:GetIdDataFromJson(JsonParam, 3)
local PlayerInfoProxy = require(ServerStorage.Proxy.PlayerInfoProxy)
local getNumber = math.floor(mob_died_get["intArray"][2] + LevelProxy:GetLevelGetBonus(Player) / 100)
PlayerInfoProxy:ChangeItemCount(Player, mob_died_get["intArray"][1], getNumber)
for _, mob in LevelProxy.pData[Player.UserId].Mobs do
if mob.Instance ~= Mob.Instance then continue end
table.remove(LevelProxy.pData[Player.UserId].Mobs, table.find(LevelProxy.pData[Player.UserId].Mobs, mob))
-- 怪物被击杀时做关卡数据处理
local LevelData = Utils:GetIdDataFromJson(JsonLevel, LevelProxy.pData[Player.UserId].LevelId)
if LevelProxy.pData[Player.UserId].SpawnWaveFinish and #LevelProxy.pData[Player.UserId].Mobs == 0 then
if LevelProxy.pData[Player.UserId].NowWave < #LevelData["wave"] then
-- -- 波数增长
LevelProxy.pData[Player.UserId].ShouldWave = LevelProxy.pData[Player.UserId].ShouldWave + 1
-- 新波次重置怪物生成状态标记
local ChallengeFolder = GetPlayerLevelFolder(Player, "Challenge")
ChangeValue(Player, ChallengeFolder, "SpawnWaveFinish", false)
elseif LevelProxy.pData[Player.UserId].NowWave >= #LevelData["wave"] then
-- 结束判断
LevelProxy:ChallengeEnd(Player, true)
end
end
break
end
end
--------------------------------------------------------------------------------
function LevelProxy:InitPlayer(Player: Player)
local PlayerLevelFolder = Utils:CreateFolder(Player.UserId, LevelFolder)
local ProgressFolder = Utils:CreateFolder("Progress", PlayerLevelFolder)
local DungeonFolder = Utils:CreateFolder("Dungeon", PlayerLevelFolder)
-- 当前关卡状态 不存储
local ChallengeFolder = Utils:CreateFolder("Challenge", PlayerLevelFolder)
-- Utils:CreateFolder("Stats", PlayerLevelFolder)
-- 新玩家数据初始化
if not ArchiveProxy.pData[Player.UserId][STORE_NAME] then
ArchiveProxy.pData[Player.UserId][STORE_NAME] = {}
ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress = {}
-- 副本之后再做
ArchiveProxy.pData[Player.UserId][STORE_NAME].Dungeon = {}
end
ExtraAddPlayerLevel(Player, ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress)
-- 前端变化
for LevelKey, LevelValue in ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress do
CreateLevelInstance(Player, ProgressFolder, LevelKey, LevelValue)
end
-- 本地内容初始化(关卡挑战信息,不存储)
if not LevelProxy.pData then LevelProxy.pData = {} end
if not LevelProxy.pData[Player.UserId] then LevelProxy.pData[Player.UserId] = {} end
LevelProxy.pData[Player.UserId].Task = nil
LevelProxy.pData[Player.UserId].Time = 0
LevelProxy.pData[Player.UserId].LevelId = 0
LevelProxy.pData[Player.UserId].MaxTime = 0
LevelProxy.pData[Player.UserId].IsBoss = false
LevelProxy.pData[Player.UserId].NowWave = 0
LevelProxy.pData[Player.UserId].ShouldWave = 0
LevelProxy.pData[Player.UserId].SpawnWaveFinish = false
LevelProxy.pData[Player.UserId].Mobs = {}
-- 关卡挑战信息前端
for key, value in LevelProxy.pData[Player.UserId] do
if key == "Task" or key == "Mobs" then continue end
CreateLevelInstance(Player, ChallengeFolder, key, value)
end
end
-- 挑战关卡(挑战副本用另一个函数)
function LevelProxy:ChallengeLevel(Player: Player, LevelId: number)
local LevelData = Utils:GetIdDataFromJson(JsonLevel, LevelId)
if not LevelData then warn("Level Data not found", LevelId) return end
-- 给前端传数据,做表现
-- 场景后端生成
-- 后端生成当前关卡状态数据
local ChallengeFolder = GetPlayerLevelFolder(Player,"Challenge")
if not ChallengeFolder then warn("ChallengeFolder not found") return end
local levelTask = task.spawn(function()
ChangeValue(Player, ChallengeFolder, "IsBoss", LevelData.type == 2 and true or false)
ChangeValue(Player, ChallengeFolder, "LevelId", LevelId)
ChangeValue(Player, ChallengeFolder, "Time", 0)
ChangeValue(Player, ChallengeFolder, "NowWave", 0)
ChangeValue(Player, ChallengeFolder, "ShouldWave", 1)
ChangeValue(Player, ChallengeFolder, "MaxTime", LevelData.timeLimit or 0)
ChangeValue(Player, ChallengeFolder, "Mobs", {})
ChangeValue(Player, ChallengeFolder, "SpawnWaveFinish", false)
while task.wait(1) do
ChangeValue(Player, ChallengeFolder, "Time", LevelProxy.pData[Player.UserId].Time + 1)
-- 关卡生成
if LevelProxy.pData[Player.UserId].NowWave < #LevelData.wave and
LevelProxy.pData[Player.UserId].NowWave < LevelProxy.pData[Player.UserId].ShouldWave and
LevelProxy.pData[Player.UserId].SpawnWaveFinish == false then
ChangeValue(Player, ChallengeFolder, "NowWave", LevelProxy.pData[Player.UserId].NowWave + 1)
local waveData = LevelData.wave[LevelProxy.pData[Player.UserId].NowWave]
for i = 1, #waveData, 3 do
local mobId = waveData[i + 1]
local mobCount = waveData[i + 2]
for _ = 1, mobCount do
print("怪物增益", LevelData.atkBonus, LevelData.hpBonus)
local mob = MobsProxy:CreateMob(Player, mobId, LevelData.atkBonus, LevelData.hpBonus, OnMobDied)
table.insert(LevelProxy.pData[Player.UserId].Mobs, mob)
end
end
ChangeValue(Player, ChallengeFolder, "SpawnWaveFinish", true)
end
if LevelProxy.pData[Player.UserId].NowWave >= LevelProxy.pData[Player.UserId].ShouldWave and
LevelProxy.pData[Player.UserId].SpawnWaveFinish == true and
#LevelProxy.pData[Player.UserId].Mobs == 0 then
local maxWave = #LevelData.wave
if LevelProxy.pData[Player.UserId].NowWave < maxWave then
-- 下一波
ChangeValue(Player, ChallengeFolder, "ShouldWave", LevelProxy.pData[Player.UserId].ShouldWave)
else
-- 挑战胜利
self:ChallengeEnd(Player, true)
end
end
-- 时间结束
if LevelData.timeLimit then
if LevelProxy.pData[Player.UserId].Time >= LevelData.timeLimit then
self:ChallengeEnd(Player, false)
end
end
end
end)
LevelProxy.pData[Player.UserId].Task = levelTask
end
-- 挑战结束
function LevelProxy:ChallengeEnd(Player: Player, result: boolean)
local ProgressFolder = GetPlayerLevelFolder(Player, "Progress")
-- 停止关卡循环
if LevelProxy.pData[Player.UserId].Task then
task.cancel(LevelProxy.pData[Player.UserId].Task)
LevelProxy.pData[Player.UserId].Task = nil
end
-- 清除剩余怪物
for _, mob in pairs(LevelProxy.pData[Player.UserId].Mobs) do mob:Died(true) end
LevelProxy.pData[Player.UserId].Mobs = {}
-- 清除玩家表现
Communicate:SendToClientFree(RE_CleanPlayerPerformance, Player)
-- 判断玩家是否通关
if result then
local levelData = Utils:GetIdDataFromJson(JsonLevel, LevelProxy.pData[Player.UserId].LevelId)
-- 防止之后失败重复添加奖励
if ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress.Main == LevelProxy.pData[Player.UserId].LevelId then
-- 添加首次通关奖励
if levelData.finishRewards then
for i = 1, #levelData.finishRewards, 2 do
local itemId = levelData.finishRewards[i]
local itemCount = levelData.finishRewards[i + 1]
ItemProxy:AddItem(Player, itemId, itemCount)
print("添加首次通关奖励", itemId, itemCount)
end
end
end
ChangeValue(Player, ProgressFolder, "Main", LevelProxy.pData[Player.UserId].LevelId + 1)
else
local IsBoss = LevelProxy.pData[Player.UserId].IsBoss
if IsBoss then
ChangeValue(Player, ProgressFolder, "BossFail", LevelProxy.pData[Player.UserId].LevelId)
end
end
BD_ChallengeEnd:Fire(Player, LevelProxy.pData[Player.UserId].LevelId, result)
end
-- 获得关卡产出货币百分比
function LevelProxy:GetLevelGetBonus(Player: Player)
if not Player then warn('获取关卡产出货币百分比失败: ', Player.Name) return end
local level_get_bonus = Utils:GetIdDataFromJson(JsonParam, 2)
local level = ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress.Main
return level_get_bonus["intArray"][1] + (level - 1) * level_get_bonus["intArray"][2]
end
function LevelProxy:OnPlayerRemoving(Player: Player)
-- 关卡文件夹清除
local PlayerLevelFolder = GetPlayerLevelWorkspaceFolder(Player.UserId)
if PlayerLevelFolder then
PlayerLevelFolder:Destroy()
end
-- 关卡存储数据清除
if LevelProxy.pData[Player.UserId].Task then
task.cancel(LevelProxy.pData[Player.UserId].Task)
end
LevelProxy.pData[Player.UserId] = nil
end
-- ReplicatedStorage.Remotes.PlayerRemoving.Event:Connect(function(PlayerUserId: string)
-- LevelProxy:OnPlayerRemoving(PlayerUserId)
-- end)
Players.PlayerRemoving:Connect(function(Player: Player)
LevelProxy:OnPlayerRemoving(Player)
end)
return LevelProxy