---@class UGCGameState_C:BP_UGCGameState_C ---@field DataTables TArray --Edit Below-- UGCGameSystem.UGCRequire('Script.Common.ue_enum_custom') UGCGameSystem.UGCRequire('Script.Common.ue_struct_custom') UGCGameSystem.UGCRequire('Script.Global.Global') local UGCGameState = { IsRunOnServer = false, --玩家数据列表 PlayerDataList = {}, --玩家难度选择 PlayerDifficultySelection = { }, --游戏难度 GameDifficulty = 0, --首领血量系数 BossHealthMultiplier = 1.0, --怪物血量及攻击力系数 MonsterHealthAndAttackValueMultiplier = { ["Health"] = 1.0, ["Attack"] = 1.0, }, --游戏是否胜利 GameIsWin = false, --游戏开始时间 GameStartTimeStamp = 0, --游戏结束时间 GameEndTimeStamp = 0, --当前游戏时长 GameDuration = 0.0, --是否应用初始角色属性 bHasApplyedAttribute = false, --在场地中央的玩家们 PlayerPawnInArena = {}, --水晶 Crystal = nil, --等待玩家进入剩余时间 WaitPlayerJoinTime = -1, --游戏阶段 GameStage = -1, --准备阶段各个状态 GameReadyStage = -1, --准备阶段各个状态剩余时间 GameReadyStageRemainTime = -1, --进攻波次是否存在 IsInAttackWave = false, --总进攻波次 TotalAttackWave = -1, --进攻波次 CurAttackWave = -1, --战斗阶段各个波次剩余时间 GameFightStageRemainTime = -1, --Item全局唯一ID CurDropItemThisID = 1, --掉落物全局表 GlobalDropItemActorList = {}, --根据玩家进行区分掉落物,除了玩家以外掉落的为 InArena: 0;玩家本身使用 PlayerKey DropItemList = { [0] = {}, }; --玩家伤害 {[PlayerKey] = {[BossID] = number} ... } PlayerDamageList = {}, --首领列表 BossList = {}, --玩家伤害 {[PlayerKey] = {[Level] = number, [CurExp] = number}, ... } PlayerLevelAndExpList = {}, --玩家战力值 PlayerCombatPointList = {}, -- 本局游戏玩家死亡次数 { PlayerKey: DieCount } PlayerDieTimes = {}, -- 玩家重生数据 { Type: Value } PlayerArchiveDatas = {}, -- 练功房物品数量上限 ExerciseRoomItemLimit = 50; PlayerInitDatas = {}; GameResultData = {}; --游戏结算信息 }; require('Script.Manager.CommandQueneManager') --设置同步的属性 function UGCGameState:GetReplicatedProperties() return "GameDuration", "PlayerDataList", "PlayerDifficultySelection", "GameStage", "WaitPlayerJoinTime", "TotalAttackWave", "CurAttackWave", "IsInAttackWave", "GameFightStageRemainTime", {"GameResultData", "Lazy"}, {"GameReadyStage", "Lazy"}, "GameReadyStageRemainTime", "PlayerDamageList", {"BossList", "Lazy"}, "GameDifficulty", "PlayerLevelAndExpList", "PlayerCombatPointList", "PlayerDieTimes" end function UGCGameState:GetAvailableServerRPCs() return -- "Client_MulticastRPC_ShowGeneralNoticeTips", -- "Client_MulticastRPC_ShowNoticeTips", -- "Client_MulticastRPC_SendEvent", -- "Client_MulticastRPC_ShowPanel", -- "Client_MulticastRPC_ClosePanel", -- "Client_MulticastRPC_ShowCrystalAttackedByBoss", ---Sound -- "Client_MulticastRPC_PlaySound2D", -- "Client_MulticastRPC_PlaySoundAtLocation", -- "Client_MulticastRPC_PlaySoundAttachActor", -- "Client_MulticastRPC_StopAllSound", -- "Client_MulticastRPC_StopSoundByActor", -- "Client_MulticastRPC_StopSoundByID" ---Unpacking -- "Client_RPC_UnpackingResults", "Server_RPC_Unpacking" end function UGCGameState:ReceiveBeginPlay() UGCGameSystem.UGCRequire('Script.Global.Global') UGCGameState.SuperClass.ReceiveBeginPlay(self) self.IsRunOnServer = UGCGameSystem.IsServer() self.IsShowDeadBox = false --游戏数据初始化 GameDataManager:Init() if self:HasAuthority() == true then EventSystem:AddListener(EventType.PlayerPawnInArenaChanged, UGCGameState.OnPlayerPawnInArenaChanged, self) EventSystem:AddListener(EventType.SpawnDropItem, UGCGameState.SpawnDropItem, self) EventSystem:AddListener(EventType.SpawnDropItemByID, UGCGameState.SpawnDropItemByID, self) EventSystem:AddListener(EventType.ServerOnLevelAndExpChanged, UGCGameState.OnPlayerLevelAndExpChanged, self) EventSystem:AddListener(EventType.ServerOnCombatPointChanged, UGCGameState.OnCombatPointChanged, self) GameEndManager:Init() else --预加载资源 AsyncLoadTools:Init() local CommandManager = require('Script.Manager.CommandQueneManager') CommandManager:AddInitCommand(self, self.Client_Init) end end function UGCGameState:ReceiveEndPlay() if self:HasAuthority() == true then EventSystem:RemoveListener(EventType.SpawnDropItemByID, UGCGameState.SpawnDropItemByID, self) EventSystem:RemoveListener(EventType.SpawnDropItem, UGCGameState.SpawnDropItem, self) EventSystem:RemoveListener(EventType.PlayerPawnInArenaChanged, UGCGameState.OnPlayerPawnInArenaChanged, self) EventSystem:RemoveListener(EventType.ServerOnLevelAndExpChanged, UGCGameState.OnPlayerLevelAndExpChanged, self) EventSystem:RemoveListener(EventType.ServerOnCombatPointChanged, UGCGameState.OnCombatPointChanged, self) else AsyncLoadTools:UnInit() if NewPlayerGuideManager then NewPlayerGuideManager:UnInit() end end GameDataManager:UnInit() UGCGameState.SuperClass.ReceiveEndPlay(self) end function UGCGameState:ReceiveTick(DeltaTime) UGCGameState.SuperClass.ReceiveTick(self, DeltaTime) if not self.IsRunOnServer then if self.bHasInitClient == nil then CommandQueneManager.bGameStateReady = true self.bHasInitClient = true UE.Log("[UGCGameState] *** UGCGameState Tick Init Ready") end CommandQueneManager:Update() else end end function UGCGameState:Client_Init() self:OnRep_BossList() self:OnRep_PlayerDamageList() self:OnRep_GameStage() self:OnRep_PlayerLevelAndExpList() self:OnRep_PlayerCombatPointList() end -- 使用默认属性 function UGCGameState:ApplyDefaultAttributes() local AllPlayerStates = UGCGameSystem.GetAllPlayerState(false) for _, PlayerState in pairs(AllPlayerStates) do -- 将属性设置到PlayerState local Temp = {} for i = 0, AttributeType.WeaponSpecial do local Attribute = {} for j, v in pairs(GlobalConfigs.Attributes) do if i == 0 then Attribute[j] = v.Value else Attribute[j] = 0 end end Temp[i] = Attribute end PlayerState.Attributes = Temp -- 在初始化属性结束后(GameState:ApplyDefaultAttributes())进行玩家存档属性的初始化 PlayerState:InitData() PlayerState:ApplyAttributes() end self.bHasApplyedAttribute = true end -- 进行通知应用玩家属性 function UGCGameState:ApplyPlayerWeaponAttributes(InPlayerKey) -- 找到对应 PlayerState local PlayerState = UGCGameSystem.GetPlayerStateByPlayerKey(InPlayerKey) PlayerState:ApplyAttributes() end function UGCGameState:CheckAllPlayersGameDifficultySelection() local ValidVoteInfo = {} if table.getCount(self.PlayerDifficultySelection) > 0 then for Index, VoteNum in pairs(self.PlayerDifficultySelection) do if VoteNum > 0 then table.insert(ValidVoteInfo, { VoteType = Index, VoteNum = VoteNum }) end end end if table.getCount(ValidVoteInfo) > 0 then --有效投票(有人投票) table.sort(ValidVoteInfo, function(a, b) if a.VoteNum > b.VoteNum then return true elseif a.VoteNum == b.VoteNum then return a.VoteType > b.VoteType else return false end end) for _, v in pairs(ValidVoteInfo) do UE.Log("[UGCGameState:CheckAllPlayersGameDifficultySelection] VoteIndex = %s, VoteNum = %d", v.VoteType, v.VoteNum) end if table.getCount(ValidVoteInfo) > 0 then for index, v in pairs(ValidVoteInfo) do --self.GameDifficulty = GlobalConfigs.GameDifficulty[v.VoteType] self.GameDifficulty = v.VoteType break end else self.GameDifficulty = 1 end else --无有效投票(所有人都没投票)则固定难度1 self.GameDifficulty = 1 end if self.GameDifficulty <= 0 then NoticeTipsTools.MulticastGeneralNoticeTips("游戏难度配置错误,请检查逻辑,游戏终止", true, 4.0) return end UE.Log("[UGCGameState:CheckAllPlayersGameDifficultySelection] GameDifficulty = "..tostring(self.GameDifficulty)) NoticeTipsTools.MulticastGeneralNoticeTips("游戏难度:难"..tostring(self.GameDifficulty)) local FightStageConfig = Tables.GameFightStageConfig[math.clamp(self.GameDifficulty, 1, 4)] self.TotalAttackWave = table.getCount(FightStageConfig) UE.Log("[UGCGameState:CheckAllPlayersGameDifficultySelection] TotalAttackWave = %d", self.TotalAttackWave) local BossTotaNum = 0 for _, Config in pairs(FightStageConfig) do BossTotaNum = BossTotaNum + Config.MonsterNum.Boss end -- Boss难度表 local BossSort = { { ID = 10001, Diff = 3 }, { ID = 10002, Diff = 4 }, { ID = 10003, Diff = 2 }, { ID = 10004, Diff = 9 }, { ID = 10005, Diff = 1 }, { ID = 10006, Diff = 10 }, }; table.sort(BossSort, function(a, b) return a.Diff < b.Diff; end) for i = 1, BossTotaNum do local BossInfo = nil if i <= 2 then BossInfo = table.remove(BossSort, math.random(1, #BossSort - 2)); else BossInfo = table.remove(BossSort, math.random(1, #BossSort)) end if BossInfo then table.insert(self.BossList, BossInfo.ID) end end UnrealNetwork.RepLazyProperty(self, "BossList") local AllPlayerStates = UGCGameSystem.GetAllPlayerState(false) for _, PlayerState in pairs(AllPlayerStates) do self.PlayerDamageList[PlayerState.PlayerKey] = {} for _, BossID in pairs(self.BossList) do self.PlayerDamageList[PlayerState.PlayerKey][BossID] = 0.0 end end end function UGCGameState:CheckAllPlayersDefaultWeaponSelection() local AllPlayerStates = UGCGameSystem.GetAllPlayerState(false) for _, PlayerState in pairs(AllPlayerStates) do local InPlayerKey = PlayerState.PlayerKey if table.getCount(PlayerState.OwnerWeapons) <= 0 then -- 设置初始武器 local PlayerController = UGCGameSystem.GetPlayerControllerByPlayerKey(InPlayerKey) PlayerController:ServerRPC_SelectDefaultWeapon(101) ---配置默认武器R1895 end end end function UGCGameState:CheckAllPlayersDefaultTelentSelection() local AllPlayerController = UGCGameSystem.GetAllPlayerController(false) for _, PC in pairs(AllPlayerController) do local InPlayerKey = PC.PlayerKey if next(PC.ActiveSkillNameList) == nil then PC:GiveSkillList({ESkillName.Heal, ESkillName.Dash}) NoticeTipsTools.ServerGeneralNoticeTips(InPlayerKey, "已选择默认天赋技能:冲刺") else PC:GiveSkill(ESkillName.Heal) end end NoticeTipsTools.MulticastGeneralNoticeTips("所有玩家已准备完毕,练功房激活! 等待进攻波次开始!", false, 8.0) end function UGCGameState:GetGameDuration() return math.ceil(self.GameEndTimeStamp - self.GameStartTimeStamp) end function UGCGameState:SetIsGameWin(IsWin) self.GameIsWin = IsWin end function UGCGameState:GetIsGameWin() return self.GameIsWin end function UGCGameState:GetCrystal() if self.Crystal == nil or UE.IsValid(self.Crystal) == false then local CrystalClass = UE.LoadClass(BPClassPath.Crystal) local Crystals = GameplayStatics.GetAllActorsOfClass(self, CrystalClass, {}) local Crystal = Crystals[1] self.Crystal = Crystal end return self.Crystal end function UGCGameState:GetAttackWaveSpawner() if self.AttackWaveSpawner == nil or UE.IsValid(self.AttackWaveSpawner) == false then local SpawnerClass = UE.LoadClass(BPClassPath.MonsterSpawner) local Spawners = GameplayStatics.GetAllActorsOfClass(self, SpawnerClass, {}) for _, Spawner in pairs(Spawners) do if Spawner.Type == EMonsterSpawnerType.AttackWave then self.AttackWaveSpawner = Spawner break end end end return self.AttackWaveSpawner end function UGCGameState:GetAllHangUpRoomSpawners() if self.HangUpRoomSpawners == nil then self.HangUpRoomSpawners = {} local Spawners = GameplayStatics.GetAllActorsOfClass(self, UE.LoadClass(BPClassPath.MonsterSpawner), {}) for _, Spawner in pairs(Spawners) do if Spawner.Type == EMonsterSpawnerType.HangUpRoom then self.HangUpRoomSpawners[Spawner.TargetPlayerKey] = Spawner end end end return self.HangUpRoomSpawners end function UGCGameState:GetAllSpawners() local AttackWaveSpawner = self:GetAttackWaveSpawner() local HangUpRoomSpawners = self:GetAllHangUpRoomSpawners() local AllSpawners = {} table.insert(AllSpawners, AttackWaveSpawner) for _, Spawner in pairs(HangUpRoomSpawners) do table.insert(AllSpawners, Spawner) end return AllSpawners end function UGCGameState:GetSpawnerByPlayerKey(InPlayerKey) if self.HangUpRoomSpawners == nil then self.HangUpRoomSpawners = {} local Spawners = GameplayStatics.GetAllActorsOfClass(self, UE.LoadClass(BPClassPath.MonsterSpawner), {}) for _, Spawner in pairs(Spawners) do if Spawner.Type == EMonsterSpawnerType.HangUpRoom then self.HangUpRoomSpawners[Spawner.TargetPlayerKey] = Spawner end end end return self.HangUpRoomSpawners[InPlayerKey] end function UGCGameState:GetAllTeleporters() if self.Teleporters == nil then self.Teleporters = {} local Teleporters = GameplayStatics.GetAllActorsOfClass(self, UE.LoadClass(BPClassPath.Teleporter), {}) for _, Teleporter in pairs(Teleporters) do table.insert(self.Teleporters, Teleporter) end end return self.Teleporters end function UGCGameState:GetAllPlayerStarts() if self.PlayerStarts == nil then self.PlayerStarts = {} self.PlayerStarts[ETeleportType.InArena] = {} self.PlayerStarts[ETeleportType.InHangupRoom] = {} local AllPlayerStarts = GameplayStatics.GetAllActorsOfClass(self, UE.LoadClass(BPClassPath.PlayerStart), {}) print(string.format('[UGCGameState:GetAllPlayerStarts] 一共有%d个 PlayerStart', table.getCount(AllPlayerStarts))) for _, PlayerStart in pairs(AllPlayerStarts) do table.insert(self.PlayerStarts[PlayerStart:GetType()], PlayerStart) end end return self.PlayerStarts end function UGCGameState:GetPlayersInArena() return self.PlayerPawnInArena end function UGCGameState:OnPlayerPawnInArenaChanged(InRangePlayerPawn) self.PlayerPawnInArena = InRangePlayerPawn end function UGCGameState:OnPlayerLevelAndExpChanged(PlayerKey, InLevel, InCurExp, InTotalExp) if self.PlayerLevelAndExpList[PlayerKey] == nil then self.PlayerLevelAndExpList[PlayerKey] = {} end self.PlayerLevelAndExpList[PlayerKey] = {Level = InLevel, CurExp = InCurExp, TotalExp = InTotalExp} end function UGCGameState:OnCombatPointChanged(PlayerKey, CombatPoint) self.PlayerCombatPointList[PlayerKey] = CombatPoint end -- 生成一个掉落物 function UGCGameState:SpawnDropItem(InLoc, InRot, InPlayerKey, InData) local ItemData if InData == nil then ItemData = GenerateDropItemData() else ItemData = InData end if InPlayerKey ~= nil then -- 判断是否生成在 InArena:如果玩家此时在场内,说明就生成在场内 local ThePawn = UGCGameSystem.GetPlayerPawnByPlayerKey(InPlayerKey) if ThePawn then if not ThePawn.IsInArena then -- 说明在场内 self:SpawnDropItem_ExerciseRoom(InLoc, InRot, InPlayerKey, ItemData) --self.DropItemList[0][self.CurDropItemThisID] = DropItemActor; else self:SpawnDropItem_InArena(InLoc, InRot, InPlayerKey, ItemData) --if self.DropItemList[InPlayerKey] == nil then -- self.DropItemList[InPlayerKey] = {} --end ---- 添加到数组中,可以设置为当玩家在练功房的时候自动拾取里面的所有东西 --self.DropItemList[InPlayerKey][self.CurDropItemThisID] = DropItemActor; end else print(string.format('[UGCGameState:SpawnDropItem] 无法找到当前玩家')) end return end end function UGCGameState:SpawnDropItem_InArena(InLoc, InRot, InPlayerKey, InData) local ItemBaseClass = UE.LoadClass(BPClassPath.PickupItemClass) local Location = self:GetDropLocation(InLoc) local Scale = VectorHelper.ScaleOne() --此处生成了一个具体的 Item local DropItemActor = UGCGameSystem.SpawnActor( self, ItemBaseClass, Location, InRot, Scale, self ) if DropItemActor then DropItemActor:SetPickItemData(string.format("%d;%d", InData.ItemID, InData.Count)) DropItemActor:SetThisID(self.CurDropItemThisID) self.GlobalDropItemActorList[self.CurDropItemThisID] = DropItemActor self.CurDropItemThisID = self.CurDropItemThisID + 1 end end function UGCGameState:SpawnDropItem_ExerciseRoom(InLoc, InRot, InPlayerKey, InData) -- 判断场景中的物品数量是否超过指定数量 if not self:CanExerciseCreateDropItem(InPlayerKey) then return end log_tree('InData = ', InData) -- 加入到数组中,场景中的不加入 if self.DropItemList[InPlayerKey] == nil then self.DropItemList[InPlayerKey] = {} end if self.DropItemList[InPlayerKey][InData.ItemID] == nil then self.DropItemList[InPlayerKey][InData.ItemID] = InData.Count else self.DropItemList[InPlayerKey][InData.ItemID] = self.DropItemList[InPlayerKey][InData.ItemID] + InData.Count end log_tree("DropItemList", self.DropItemList) -- 发送 RPC 通知客户端创建东西 local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(InPlayerKey) InLoc = self:GetDropLocation(InLoc) PC:RequestExerciseDropItem(InPlayerKey, InLoc, InRot, InData, true) end --是否可以在练功房创建掉落物 function UGCGameState:CanExerciseCreateDropItem(InPlayerKey) if self.DropItemList[InPlayerKey] ~= nil then -- i: ItemID, v: ItemCount local TotalCount = 0 for i, v in pairs(self.DropItemList[InPlayerKey]) do TotalCount = TotalCount + v; end return self.ExerciseRoomItemLimit > TotalCount; else return true; end end --玩家丢弃的时候生成 function UGCGameState:SpawnDropItemByID(InItemID, InCount, InLoc, InRot, InPlayerKey, IsFromDiscard) UE.Log("[UGCGameState:SpawnDropItemByID] 开始执行") local ItemBaseClass = UE.LoadClass(BPClassPath.PickupItemClass) local Location = self:GetDropLocation(InLoc) local Rotation = InRot local Scale = VectorHelper.ScaleOne() local DropItemActor = UGCGameSystem.SpawnActor( self, ItemBaseClass, Location, Rotation, Scale, self ) if DropItemActor then UE.Log("[UGCGameState:SpawnDropItemByID] 执行掉落方法") UE.Log("{ItemID类型是 = %s, Count = %s}", type(InItemID), type(InCount)) DropItemActor:SetPickItemData(string.format("%d;%d", InItemID, InCount)) DropItemActor:SetThisID(self.CurDropItemThisID) if IsFromDiscard then DropItemActor:SetAutoPickupDisabled(InPlayerKey) end self.GlobalDropItemActorList[self.CurDropItemThisID] = DropItemActor self.CurDropItemThisID = self.CurDropItemThisID + 1 end UE.Log("[UGCGameState:SpawnDropItemByID] 执行完成") end function UGCGameState:GetDropLocation(InStartLocation) local StartPos = VectorHelper.Add(InStartLocation, {X=0,Y=0,Z=50}) local EndPos = VectorHelper.Sub(InStartLocation, {X=0,Y=0,Z=500}) local ObjectTypes = {EObjectTypeQuery.ObjectTypeQuery1} local AllWeapons = GameplayStatics.GetAllActorsOfClass(self, UE.LoadClass(BPClassPath.Weapon), {}) local bHit, HitResult = KismetSystemLibrary.LineTraceSingleForObjects(self, StartPos, EndPos, ObjectTypes, false, AllWeapons, EDrawDebugTrace.None, nil, true, nil,nil, nil) local DropPos = {} if bHit then DropPos = HitResult.ImpactPoint else DropPos = InStartLocation end return DropPos end --S function UGCGameState:UpdatePlayerDamage(InPlayerKey, InBossID, InDeltaDamage) if self.PlayerDamageList[InPlayerKey] == nil then self.PlayerDamageList[InPlayerKey] = {} end if self.PlayerDamageList[InPlayerKey][InBossID] == nil then self.PlayerDamageList[InPlayerKey][InBossID] = 0 end local CurDamage = self.PlayerDamageList[InPlayerKey][InBossID] self.PlayerDamageList[InPlayerKey][InBossID] = CurDamage + InDeltaDamage end --S function UGCGameState:UpdateIsInAttackWave(bNewIsInAttackWave) if self.IsInAttackWave ~= bNewIsInAttackWave then self.IsInAttackWave = bNewIsInAttackWave EventSystem:SendEvent(EventType.OnIsInAttackWaveChanged, self.IsInAttackWave) if bNewIsInAttackWave == false then -- 提示当前过3秒传回练功房 EventSystem.SetTimer(self, function() -- 发送到练功房 EventSystem:SendEvent(EventType.SendPlayersToExercise) end, 3) end end end function UGCGameState:GetAllPlayerLevel() local LevelTable = {} for PlayerKey, Info in pairs(self.PlayerLevelAndExpList) do LevelTable[PlayerKey] = Info.Level end return LevelTable end function UGCGameState:GetAllPlayerExp() local ExpTable = {} for PlayerKey, Info in pairs(self.PlayerLevelAndExpList) do ExpTable[PlayerKey] = {CurExp = Info.CurExp, TotalExp = Info.TotalExp} end return ExpTable end function UGCGameState:OnRep_PlayerDataList() for k,v in pairs(self.PlayerDataList) do UE.Log("[UGCGameState:OnRep_PlayerDataList] PlayerKey = "..tostring(v.PlayerKey).." PlayerName = "..v.PlayerName) end EventSystem:SendEvent(EventType.PlayerDataListChanged, self.PlayerDataList) end function UGCGameState:OnRep_PlayerDifficultySelection() if table.getCount(self.PlayerDifficultySelection) > 0 then for k, v in pairs(self.PlayerDifficultySelection) do UE.Log("[UGCGameState:OnRep_PlayerDifficultySelection] key = %s, value = %d", tostring(k), v) end end EventSystem:SendEvent(EventType.PlayerDifficultySelectionChanged, self.PlayerDifficultySelection) end function UGCGameState:OnRep_WaitPlayerJoinTime() UE.Log("[UGCGameState:OnRep_WaitPlayerJoinTime] WaitPlayerJoinTime = %d", self.WaitPlayerJoinTime) EventSystem:SendEvent(EventType.OnWaitPlayerJoinTimeChanged, self.WaitPlayerJoinTime) end function UGCGameState:OnRep_GameStage() UE.Log("[UGCGameState:OnRep_GameStage] GameStage = %d", self.GameStage) EventSystem:SendEvent(EventType.OnGameStageChanged, self.GameStage); end function UGCGameState:OnRep_GameReadyStage() UE.Log("[UGCGameState:OnRep_GameReadyStage] GameReadyStage = %s", tostring(self.GameReadyStage)) -- 这里只发了一次 if UIManager and UIManager.HasInitialized then if self.GameReadyStage >= 0 then for _, Config in pairs(Tables.GameReadyStageConfig) do if Config.Stage == self.GameReadyStage then local TriggerUI = Config.TriggerUI UIManager:ShowPanel(TriggerUI) break end end end end end function UGCGameState:OnRep_GameReadyStageRemainTime() UE.Log("[UGCGameState:OnRep_GameReadyStageRemainTime] GameReadyStageRemainTime = %s", tostring(self.GameReadyStageRemainTime)) EventSystem:SendEvent(EventType.OnGameReadyStageRemainTimeChanged, self.GameReadyStageRemainTime) end function UGCGameState:OnRep_CurAttackWave() UE.Log("[UGCGameState:OnRep_CurAttackWave] CurAttackWave = %s", tostring(self.CurAttackWave)) EventSystem:SendEvent(EventType.OnCurAttackWaveChanged, self.CurAttackWave, self.TotalAttackWave) if self.CurAttackWave > 0 and self.TotalAttackWave > 0 and UIManager then UIManager:ShowNotice(ECustomNoticeType.GeneralNotice, string.format("第%d波进攻开始", self.CurAttackWave), false, 3.0) UIManager:ShowNotice(ECustomNoticeType.AttackWaveNotice, self.CurAttackWave, self.TotalAttackWave) end end function UGCGameState:OnRep_IsInAttackWave() UE.Log("[UGCGameState:OnRep_IsInAttackWave] IsInAttackWave = %s", tostring(self.IsInAttackWave)) EventSystem:SendEvent(EventType.OnIsInAttackWaveChanged, self.IsInAttackWave) if self.GameStage >= EGameStage.GameFight then for _, Teleporter in pairs(self:GetAllTeleporters()) do if self.IsInAttackWave == false then Teleporter:SetRingColor(Teleporter.Type == ETeleportType.InHangupRoom) else Teleporter:SetRingColor(Teleporter.Type == ETeleportType.InArena) end end end if self.GameStage == EGameStage.GameFight and self.IsInAttackWave == false then UIManager:ShowNotice(ECustomNoticeType.GeneralNotice, "进攻波次已清理完毕,可回到练功房继续提升等级", false, 3.0) end end function UGCGameState:OnRep_GameFightStageRemainTime() UE.Log("[UGCGameState:OnRep_GameFightStageRemainTime] GameFightStageRemainTime = %s", tostring(self.GameFightStageRemainTime)) EventSystem:SendEvent(EventType.OnGameFightStageRemainTimeChanged, self.GameFightStageRemainTime) if self.GameFightStageRemainTime > 5 then self.bHasNoticedAttackWave = false end if UIManager and UIManager.HasInitialized then if self.GameFightStageRemainTime >= 0 then UIManager:ShowNotice(ECustomNoticeType.AttackWaveRemainTimeNotice, self.GameFightStageRemainTime) end if self.GameFightStageRemainTime <= 5 and not self.bHasNoticedAttackWave then UIManager:ShowNotice(ECustomNoticeType.CountDownNotice, "怪物进攻倒计时", self.GameFightStageRemainTime, true) self.bHasNoticedAttackWave = true end end end function UGCGameState:OnRep_PlayerDamageList() log_tree("[OnRep_PlayerDamageList] PlayerDamageList = ", self.PlayerDamageList) EventSystem:SendEvent(EventType.OnPlayerDamageChanged, self.PlayerDamageList) end function UGCGameState:OnRep_BossList() log_tree_dev("[OnRep_BossList] BossList = ", self.BossList) EventSystem:SendEvent(EventType.ChangeBossList, self.BossList) end function UGCGameState:OnRep_PlayerLevelAndExpList() local LevelTable = {} local ExpTable = {} for PlayerKey, Info in pairs(self.PlayerLevelAndExpList) do LevelTable[PlayerKey] = Info.Level ExpTable[PlayerKey] = Info.CurExp end EventSystem:SendEvent(EventType.OnPlayerLevelChanged, self:GetAllPlayerLevel()) EventSystem:SendEvent(EventType.OnPlayerExpChanged, self:GetAllPlayerExp()) end function UGCGameState:OnRep_PlayerCombatPointList() EventSystem:SendEvent(EventType.OnPlayerCombatPointChanged, self.PlayerCombatPointList) end function UGCGameState:OnRep_GameDuration() EventSystem:SendEvent(EventType.OnGameDurationChanged, self.GameDuration) end --------------------------------------------RPC-------------------------------------------- function UGCGameState:Client_MulticastRPC_ShowGeneralNoticeTips(InText, ShowAlert, ShowTime) if self:HasAuthority() then return end UIManager:ShowGeneralNotice(InText, ShowAlert, ShowTime) end function UGCGameState:Client_MulticastRPC_ShowNoticeTips(InNoticeType, ...) if self:HasAuthority() then return end UIManager:ShowNotice(InNoticeType, ...) end function UGCGameState:Client_MulticastRPC_SendEvent(InEventType, ...) if self:HasAuthority() then return end EventSystem:SendEvent(InEventType, ...) end function UGCGameState:Client_MulticastRPC_ShowPanel(InUIType, ...) if self:HasAuthority() then return end EventSystem:SendEvent(EventType.RequestShowPanel, InUIType, ...) end function UGCGameState:Client_MulticastRPC_ClosePanel(InUIType) if self:HasAuthority() then return end UIManager:ClosePanel(EUIType.DifficultInfo) EventSystem:SendEvent(EventType.RequestClosePanel, InUIType) end function UGCGameState:Client_MulticastRPC_ShowCrystalAttackedByBoss() if self:HasAuthority() then return end local Crystal = self:GetCrystal() Crystal.NarrationWidget.Widget:UpdateNarrationText("来看看是哪来的小东西,是在帮我挠痒痒吗?") end function UGCGameState:Server_RPC_Unpacking(PlayerKey, UnpackingLevel, InTimes) local TargetPlayerState = UGCGameSystem.GetPlayerStateByPlayerKey(PlayerKey) local Val = Tables.Unpacking.LevelCoinPoint[UnpackingLevel].CoinPoint1 if InTimes == 10 then Val = Tables.Unpacking.LevelCoinPoint[UnpackingLevel].CoinPoint10 end local Func = function(InValue) if InValue > 0 then InValue = -InValue end InValue = math.clamp(InValue, -1, 0) return InValue end -- 计算开箱所需金币 local Temp, Temp1, Temp2, Temp3 = 0, 0, 0, 0 for i, v in pairs(TargetPlayerState.Attributes) do Temp = Temp + v.Unpacking_Cost Temp1 = Temp1 + v.Primary_Raffle_Cost Temp2 = Temp2 + v.Middle_Raffle_Cost Temp3 = Temp3 + v.Senior_Raffle_Cost end local Func1 = function(TheTime, InPlayerState, Num) if TheTime == 10 then if InPlayerState.EasterEggsData[Num] == nil then InPlayerState.EasterEggsData[Num] = 1 else InPlayerState.EasterEggsData[Num] = InPlayerState.EasterEggsData[Num] + 1 end -- 比较一下 ArchiveTable.Funcs[ArchiveTable.ArchiveType.EasterEggs](InPlayerState, Num) end end local Val1 = 0 if UnpackingLevel == 1 then Val1 = Temp1 elseif UnpackingLevel == 2 then Val1 = Temp2 elseif UnpackingLevel == 3 then Val1 = Temp3 end Val = Val * (1 + Temp) * (1 + Val1) if TargetPlayerState.CoinPoint.Current > Val then -- 可以扣金币 local UnpackingResults = {} for i = 1, InTimes do local UnpackingResult = self:Unpacking(PlayerKey, UnpackingLevel) table.insert(UnpackingResults, {Name = UnpackingResult.Name, UnpackingLevel = UnpackingResult.UnpackingLevel}) end TargetPlayerState:UpdateCoinPoint(- Val) if UnpackingLevel == 1 then Func1(InTimes, TargetPlayerState, 13) elseif UnpackingLevel == 2 then Func1(InTimes, TargetPlayerState, 12) elseif UnpackingLevel == 3 then Func1(InTimes, TargetPlayerState, 11) end local TargetPawn = ScriptGameplayStatics.GetPlayerPawnByPlayerKey(self, PlayerKey) local TargetController = TargetPawn:GetController() TargetPlayerState.ArchiveData.TotalUnpackTimes = TargetPlayerState.ArchiveData.TotalUnpackTimes + InTimes; -- --local CurItemMap = TargetController:GetItemMap() --UnrealNetwork.CallUnrealRPC(TargetController, TargetController, "ClientRPC_UpdateBackpackItemMap", CurItemMap) UnrealNetwork.CallUnrealRPC(TargetController, self, "Client_RPC_UnpackingResults", PlayerKey, UnpackingResults) else UE.LogError("[UGCGameState:Server_RPC_Unpacking] 金币不足") end end function UGCGameState:Client_RPC_UnpackingResults(PlayerKey, UnpackingResults) EventSystem:SendEvent(EventType.UnpackingResult, PlayerKey, UnpackingResults) end function UGCGameState:Unpacking(PlayerKey, UnpackingLevel, Drop) if Drop == nil then Drop = Tables.Unpacking.CardDropping end while 1 do local RateList = {} if Drop.Children then for k, Child in pairs(Drop.Children) do if Child.Rate then RateList[k] = Child.Rate else print("UGCGameState_Fun_" .. "Unpacking_" .. "Error_" .. "Rate is nil") return end end local TargetIndex = self:GetRandomIndex(RateList) Drop = Drop.Children[TargetIndex] else if Drop.AddDataFun then local TargetController = ScriptGameplayStatics.GetPlayerPawnByPlayerKey(self,PlayerKey):GetController() return Drop.AddDataFun(TargetController, UnpackingLevel) else print("UGCGameState_Fun_" .. "Unpacking_" .. "Error_" .. "Children is nil and AddDataFun is nil") return end end end end function UGCGameState:GetRandomIndex(probabilityList) local totalProbability = 0 for i=1, #probabilityList do totalProbability = totalProbability + probabilityList[i] end local randomValue = math.random() * totalProbability local currentIndex = 1 for i=1, #probabilityList do randomValue = randomValue - probabilityList[i] if randomValue <= 0 then currentIndex = i break end end return currentIndex end -- 保存玩家数据 function UGCGameState:SavePlayersData(InPlayerKey) local Func = function(v) print(string.format('[UGCGameState:SavePlayersData] 开始保存数据')) -- 进行测试 --self:TestPlayerSaveData(v) local SaveData = v.ArchiveData local Version_Temp if Version == nil then Version_Temp = require('Script.Global.Version') else Version_Temp = Version end local SavedData = { ArchiveData = SaveData, Version = Version_Temp.GetCurrentVersion() } log_tree("SaveData = ", SavedData) UGCPlayerStateSystem.SavePlayerArchiveData(v.UID, SavedData) end if InPlayerKey ~= nil then local PlayerState = UGCGameSystem.GetPlayerStateByPlayerKey(InPlayerKey) Func(PlayerState) else local AllPlayerStates = UGCGameSystem.GetAllPlayerState(false) print(string.format('[UGCGameState:SavePlayersData] 保存数据')) for _, v in pairs(AllPlayerStates) do Func(v) end end end function UGCGameState:TestPlayerSaveData(InPlayerState) InPlayerState.ArchiveData = { --GameTimes = 100, --游玩局数 GameTimes = 1000, --游玩局数 GameClearanceTimes = 200, --游戏通关数 TotalCoinPoint = 200000000, --获取总金币数 TotalKillPoint = 1300000, --获取总杀敌点数 TotalBossKilledTimes = 500, --击杀 Boss 次数 TotalSuperSkill = 2000, --获取总超级技能数 TotalSuperFitting = 0, --获取超级配件数 TotalUnpackTimes = 40000, --总开箱次数 Score = 200000, --积分 PlayedGames = { --游玩过的游戏 [1] = 6, [2] = 6, [3] = 6, [4] = 6, [5] = 6, [6] = 6, [7] = 6, [8] = 6, [9] = 6, [10] = 6, [11] = 6, [12] = 6, [13] = 6, [14] = 6, [15] = 6, [16] = 6, [17] = 6, [18] = 6, [19] = 6, [20] = 6, [21] = 6, [22] = 6, [23] = 6, [24] = 6, [25] = 6, [26] = 6, [27] = 6, [28] = 6, [29] = 6, [30] = 6, [31] = 6, [32] = 6, [33] = 6, [34] = 6, [35] = 6, [36] = 6, [37] = 6, [38] = 6, [39] = 6, [40] = 6, [41] = 6, [42] = 6, [43] = 6, [44] = 6, [45] = 6, [46] = 6, [47] = 6, [48] = 6, [49] = 6, [50] = 6, [51] = 6, [52] = 6, [53] = 6, [54] = 6, [55] = 6, [56] = 6, [57] = 6, [58] = 6, [59] = 6, [60] = 6, [61] = 6, [62] = 6, [63] = 6, [64] = 6, [65] = 6, [66] = 6, }, BossDropItems = { -- BOSS 掉落物 ['慎'] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, }, ['魅'] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, }, ['春'] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, }, ['瞬'] = { [1] = 1, [2] = 2, [3] = 1, [4] = 2, }, ['蛮'] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, }, ['幻'] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, }, }, GameDropItems = { -- 游戏掉落物 [1] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [2] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [3] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [4] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [5] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [6] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [7] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [8] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [9] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [10] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [11] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [12] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [13] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [14] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [15] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [16] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [17] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [18] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [19] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [20] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [21] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [22] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [23] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [24] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [25] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [26] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [27] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [28] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [29] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [30] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [31] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [32] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [33] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [34] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [35] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [36] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [37] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [38] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [39] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [40] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [41] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [42] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [43] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [44] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [45] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [46] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [47] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [48] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [49] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [50] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [51] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [52] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [53] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [54] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [55] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [56] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [57] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [58] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [59] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [60] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [61] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [62] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [63] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [64] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [65] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, [66] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 6, }, }, -- EasterEggs = { --彩蛋类 [1] = { Active = true, }, [2] = { Active = true, }, [3] = { Active = true, }, [4] = { Active = true, }, [5] = { Active = true, }, [6] = { Active = true, }, [7] = { Active = true, }, [8] = { Active = true, }, -- [9] = { -- Active = false, -- }, [10] = { Active = true, }, [11] = { Active = true, }, [12] = { Active = true, }, [13] = { Active = true, }, --[14] = { -- Active = false, --}, }, } -- 测试存档 --for i = 1, table.getCount(ArchiveTable.EasterEggs) do -- InPlayerState.ArchiveData.EasterEggs[i] = { -- Active = false, -- 是否激活 -- } --end end -- 加载所有玩家数据 function UGCGameState:LoadPlayerData() local AllPlayerStates = UGCGameSystem.GetAllPlayerState(false) for i = 1, #AllPlayerStates do -- 获取玩家存档信息 local PlayerData = UGCPlayerStateSystem.GetPlayerArchiveData(AllPlayerStates[i].UID) if PlayerData ~= nil then -- 解析 PlayerData -- 依次检查对应版本 self.PlayerArchiveDatas[AllPlayerStates[i].UID] = self:HandlePlayerArchiveData(PlayerData) end end end -- 根据版本处理具体数据 function UGCGameState:HandlePlayerArchiveData(InPlayerData) -- 说明是最新版本,直接操作 if InPlayerData.Version == self.VersionId then return InPlayerData elseif InPlayerData.Version == '0.1' then return InPlayerData end return nil end -----------------------------------Sound----------------------------------- function UGCGameState:Client_MulticastRPC_PlaySound2D(ConfigId) if self:HasAuthority() then return end SoundManager.PlaySound2D(ConfigId) end function UGCGameState:Client_MulticastRPC_PlaySoundAtLocation(ConfigId, Location, Rotation) if self:HasAuthority() then return end SoundManager.PlaySoundAtLocation(ConfigId, Location, Rotation) end function UGCGameState:Client_MulticastRPC_PlaySoundAttachActor(ConfigId, AttachedActor, StopWhenAttachedToDestroyed) if self:HasAuthority() then return end SoundManager.PlaySoundAttachActor(ConfigId, AttachedActor, StopWhenAttachedToDestroyed) end function UGCGameState:Client_MulticastRPC_StopAllSound() if self:HasAuthority() then return end SoundManager.StopAllSound() end function UGCGameState:Client_MulticastRPC_StopSoundByActor(Actor) if self:HasAuthority() then return end SoundManager.StopSoundByActor(Actor) end function UGCGameState:Client_MulticastRPC_StopSoundByID(ID) if self:HasAuthority() then return end SoundManager.StopSoundByID(ID) end function UGCGameState:CloseNoticeUI() local PlayerControllerList = UGCGameSystem.GetAllPlayerController() for i, v in pairs(PlayerControllerList) do UnrealNetwork.CallUnrealRPC(v, v, "ClientRPC_ShowInitialPanel", false) end end function UGCGameState:SetInitialOver(InPlayerKey) self.PlayerInitDatas[InPlayerKey] = true local PSs = UGCGameSystem.GetAllPlayerState(false) if table.getCount(PSs) == table.getCount(self.PlayerInitDatas) and table.getCount(self.PlayerInitDatas) >= 4 then -- 执行操作 EventSystem:SendEvent(EventType.UpdateInitialWidget) UGCGameSystem.GameState.GameStage = EGameStage.GameReady; end end return UGCGameState;