-- 关卡代理 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