---@class UGCGameState_C:BP_UGCGameState_C ---@field WrapperClass UClass ---@field ShootWeaponClass UClass --Edit Below-- UGCGameSystem.UGCRequire('Script.Common.ue_enum_custom') require('Script.Global.Global') local UGCGameState = {}; --- 服务器时间 UGCGameState.ServerTime = 0; --- 服务器时间 - 客户端时间的差值;如果想在服务器求客户端时间:当前时间 - 该值; UGCGameState.ServerTimeDiff = 0; --- 地图数据 UGCGameState.MapData = { SelectMapIndex = {}; }; --- 玩家数据 UGCGameState.PlayerDatas = { ---@type table ArchiveData = {}; ---@type table AccountInfo = {}; }; ---@type table> 玩家 Key 列表 UGCGameState.PlayerList = {}; ---@type table 支持排序功能 UGCGameState.PlayerKDA_Damages = {}; --- 游戏进程数据 UGCGameState.CountDownTime = 0; UGCGameState.ProgressType = DefaultSettings.EGameProgress.NON_START; ---@type table 玩家属性 UGCGameState.PlayerAttribute = {}; --- Level 模式 UGCGameState.LevelMode = ModeTable.EModeType.Common; function UGCGameState:ReceiveBeginPlay() --- 初始化 self.bIsOpenShovelingAbility = DefaultSettings.OpenShovel; GlobalInit.InitGlobalVar(); if IsServer then -- 补人 UGCMultiMode.SetPlayerFill(DefaultSettings.TotalPlayerCount > 0); self.ServerTime = 1; -- 设置好 DOREPONCE(self, "ServerTime") else end if self.MiniGameManager == nil then self.MiniGameManager = require("Script.Blueprint.Mini.MiniGameManager"); end if GlobalBeginTool then GlobalBeginTool:ReceiveBeginPlay(); end table.func(self.MiniGameManager, "ReceiveBeginPlay", self); TestTool:Test_UE_Props(); self.SuperClass.ReceiveBeginPlay(self); end function UGCGameState:ReceiveTick(DeltaTime) if GlobalTickTool then GlobalTickTool:ReceiveTick(DeltaTime, self:GetServerTime()); end end function UGCGameState:ReceiveEndPlay() DefaultSettings = nil; EventTypes = nil; GameState = nil; LocalPlayerKey = nil; LocalPlayerController = nil; LocalTeamPlayers = nil; EnemyTeamPlayers = nil; UnableTable(); UnableTool(); UnableWidgetManager(); UGCGameSystem.GameState = nil; end function UGCGameState:GetAvailableServerRPCs() return "LoadMap" , "Server_SaveOrGetButtonSetting" , "CheckServerTime" , "SelectMap" end function UGCGameState:GetReplicatedProperties() return { "MapData", "Lazy" } , { "PlayerDatas", "Lazy" } , { "PlayerKDA_Damages", "Lazy" } , { "ProgressType", "Lazy" } , { "CountDownTime", "Lazy" } , { "PlayerList", "Lazy" } , { "PlayerAttribute", "Lazy" } , { "ServerTime", "Lazy" } , { "MiniModeState", "Lazy" } , { "LoadMapName", "Lazy" } , { "CurrMiniType", "Lazy" } , { "MiniInfo", "Lazy" } end ----------------------------------------- 玩家属性 ----------------------------------------- ---@param InPlayerKey PlayerKey ---@param InArchiveData table ---@param InAccountData table function UGCGameState:HandlePlayerDatas(InPlayerKey, InArchiveData, InAccountData) InArchiveData.GameTimes = InArchiveData.GameTimes + 1; -- 又多玩了一局游戏 self.PlayerDatas.ArchiveData[InPlayerKey] = InArchiveData; self.PlayerDatas.AccountInfo[InPlayerKey] = InAccountData; DOREPONCE(self, "PlayerDatas"); end function UGCGameState:OnRep_PlayerDatas() -- 检查当前玩了多少局 if LocalPlayerKey == nil then return end if self.PlayerDatas.ArchiveData[LocalPlayerKey] == nil then return end -- 显示拍脸图 UGCLogSystem.LogTree(string.format("[UGCGameState:OnRep_PlayerDatas] self.PlayerDatas ="), self.PlayerDatas) if self.PlayerDatas.ArchiveData[LocalPlayerKey].GameTimes <= DefaultSettings.ShowFaceNoticeGameTimes then UGCLogSystem.Log("[UGCGameState:OnRep_PlayerDatas] 执行") if not DefaultSettings.EnableTest then WidgetManager:ShowPanel(WidgetConfig.EUIType.FaceNotice, false); end end UGCEventSystem.SendEvent(EventTypes.UpdatePlayerDatas, self.PlayerDatas) end function UGCGameState:FindPlayerKDA_DamagesByPlayerKey(InPlayerKey) for i, v in pairs(self.PlayerKDA_Damages) do if v.PlayerKey == InPlayerKey then return i; end end return -1; end ---@param IsLogin bool ---@param InPlayerKey PlayerKey function UGCGameState:PlayerLoginOrLeave(IsLogin, InPlayerKey) local TeamId = UGCPlayerStateSystem.GetTeamID(InPlayerKey); local LogOut = false; local AlivePlayerCount = 0; if IsLogin then if self.PlayerList[TeamId] == nil then self.PlayerList[TeamId] = {}; end self.PlayerList[TeamId][#(self.PlayerList[TeamId]) + 1] = InPlayerKey; local index = self:FindPlayerKDA_DamagesByPlayerKey(InPlayerKey) if index == -1 then table.insert(self.PlayerKDA_Damages, { Damage = 0, KDA = { Kill = 0, Dead = 0, Assist = 0, }, PlayerKey = InPlayerKey, }); DOREPONCE(self, "PlayerKDA_Damages"); end if self.PlayerAttribute[InPlayerKey] == nil then self.PlayerAttribute[InPlayerKey] = {}; for i, v in pairs(DefaultSettings.BenefitInto) do self.PlayerAttribute[InPlayerKey][i] = v.DefaultValue; end DOREPONCE(self, "PlayerAttribute"); end else if self.PlayerList[TeamId] ~= nil then local RemoveIndex = 0; for i, v in pairs(self.PlayerList[TeamId]) do if v == InPlayerKey then RemoveIndex = i; end end table.remove(self.PlayerList[TeamId], RemoveIndex); end --- 进行保存数据 UGCPlayerStateSystem.SavePlayerArchiveData(self.PlayerDatas.AccountInfo[InPlayerKey].UID, self.PlayerDatas.ArchiveData[InPlayerKey]); end for i, v in pairs(self.PlayerList) do AlivePlayerCount = table.getCount(v) + AlivePlayerCount; end if AlivePlayerCount == 0 then LogOut = true; end UGCLogSystem.LogTree(string.format("[UGCGameState:PlayerLoginOrLeave] self.PlayerKDA_Damages ="), self.PlayerKDA_Damages) DOREPONCE(self, "PlayerList"); return LogOut, AlivePlayerCount; end ---@param HasLeave bool 是否包含退出游戏的玩家 ---@return int32 玩家数量 function UGCGameState:GetPlayerCount(HasLeave) return table.getCount(HasLeave and self.PlayerKDA_Damages or self.PlayerList) end ---@param InOld table function UGCGameState:OnRep_PlayerAttribute(InOld) UGCEventSystem.SendEvent(EventTypes.PlayerAttributeChanged, self.PlayerAttribute); if table.isEmpty(InOld) then return end for c, Table in pairs(self.PlayerAttribute) do if InOld[c] ~= nil then for i, v in pairs(Table) do if InOld[c][i] ~= v then UGCEventSystem.SendEvent(DefaultSettings.BenefitInto[v].Type, c, InOld[c][i], v); end end else for i, v in pairs(Table) do UGCEventSystem.SendEvent(DefaultSettings.BenefitInto[v].Type, c, nil, v); end end end end function UGCGameState:OnRep_PlayerList() if table.isEmpty(self.PlayerList) then return ; end if LocalPlayerKey == nil then return end -- 其他玩家 EnemyTeamPlayers = {}; LocalTeamPlayers = {}; LocalTeamId = UGCPlayerStateSystem.GetTeamID(LocalPlayerKey); for TeamId, PlayerArr in pairs(self.PlayerList) do if TeamId == LocalTeamId then for i, v in pairs(PlayerArr) do LocalTeamPlayers[#LocalTeamPlayers + 1] = v; end else for i, v in pairs(PlayerArr) do EnemyTeamPlayers[#EnemyTeamPlayers + 1] = v; end end end UGCEventSystem.SendEvent(EventTypes.PlayerListChanged, self.PlayerList) end function UGCGameState:OnRep_PlayerKDA_Damages() -- 刷新 KDA 和伤害 if table.isEmpty(self.PlayerKDA_Damages) then return ; end UGCLogSystem.LogTree(string.format("[UGCGameState:OnRep_PlayerKDA_Damages] self.PlayerKDA_Damages ="), self.PlayerKDA_Damages) UGCEventSystem.SendEvent(EventTypes.AllPlayerKDAChange, self.PlayerKDA_Damages) end --- 获取玩家 KDA ---@param InPlayerKey PlayerKey ---@return PlayerKDAItem1 function UGCGameState:GetPlayerKDA(InPlayerKey) UGCLogSystem.LogTree(string.format("[UGCGameState:GetPlayerKDA] self.PlayerKDA_Damages ="), self.PlayerKDA_Damages) local Item = self.PlayerKDA_Damages[self:FindPlayerKDA_DamagesByPlayerKey(InPlayerKey)]; if Item ~= nil then return Item.KDA; end return nil; end ---获取玩家伤害 ---@param InPlayerKey PlayerKey ---@return float function UGCGameState:GetPlayerDamage(InPlayerKey) local Item = self.PlayerKDA_Damages[InPlayerKey] if Item ~= nil then return Item.Damage; end return 0; end ----------------------------------------- 地图加载 ----------------------------------------- --- 已经加载了的地图名称 UGCGameState.LoadMapName = {}; --- 加载地图(服务器/客户端都可以执行) ---@param MapNameList table 地图索引 function UGCGameState:LoadMap(MapNameList) -- 找到对应地图,然后进行加载 if not table.isEmpty(self.LoadMapName) then -- 先卸载,再安装 local List = {}; for i, v in pairs(self.LoadMapName) do table.insert(List, v.Name); end self:UnloadMap(List); end for i, v in pairs(MapNameList) do table.insert(self.LoadMapName, { Name = v, Load = false, }); end LevelStreamTool.LoadStreamLevels(MapNameList, { Object = self, Func = self.LoadMapFinish }, false); DOREPONCE(self, "LoadMapName") end function UGCGameState:OnRep_LoadMapName() if table.isEmpty(self.LoadMapName) then return ; end UGCLogSystem.LogTree(string.format("[UGCGameState:OnRep_LoadMapName] self.LoadMapName ="), self.LoadMapName); local LoadedMaps = {}; for i, v in pairs(self.LoadMapName) do if v.Load then table.insert(LoadedMaps, v.Name); end end if table.isEmpty(LoadedMaps) then return ; end UGCEventSystem.SendEvent(EventTypes.OnMapLoaded, LoadedMaps); self.MiniGameManager:OnMapLoadComplete() -- 加载小地图 UGCLogSystem.Log("[UGCGameState:OnRep_LoadMapName] 开始加载小地图") for i, v in pairs(LevelTable.LevelInfo) do if v.MapName == self.LoadMapName[1].Name then UGCLogSystem.Log("[UGCGameState:OnRep_LoadMapName] 执行") self:LoadMinimap(i); break ; end end end --- 随机加载地图 ---@param function UGCGameState:LoadRandomMap(InIndex) if IsServer then self:UnloadMap(); -- 判断当前是不是随即关卡 UGCLogSystem.LogTree(string.format("[UGCGameState:LoadRandomMap] LevelTable.LevelInfo ="), LevelTable.LevelInfo) if InIndex == nil or InIndex == LevelTable.ELevelType.Random then self.MapData.SelectMapIndex = LevelTable.GetRandomLevel(true, 1); else self.MapData.SelectMapIndex = { InIndex }; end local MapNames = {}; for i, v in pairs(self.MapData.SelectMapIndex) do table.insert(MapNames, LevelTable.LevelInfo[v].MapName); end LevelStreamTool.LoadStreamLevels(MapNames, { Object = self, Func = self.LoadMapFinish }, false); DOREPONCE(self, "MapData"); else -- 发送 RPC 到服务器 UnrealNetwork.CallUnrealRPC(LocalPlayerController, self, "LoadMap", InIndex); end end --- 卸载地图 function UGCGameState:UnloadMap() if table.isEmpty(self.MapData.SelectMapIndex) then local MapNames = {}; for i, v in pairs(self.MapData.SelectMapIndex) do table.insert(MapNames, LevelTable.LevelInfo[v].MapName) end LevelStreamTool.UnLoadStreamLevels(MapNames, { Object = self, Func = self.UnLoadMapFinish }, false); self.MapData.SelectMapIndex = {}; -- 重置 ClientAlready self.bInitOnce = false; end end function UGCGameState:OnRep_MapData() if table.isEmpty(self.MapData.SelectMapIndex) then return end end --- 地图加载完成 function UGCGameState:LoadMapFinish() UGCLogSystem.Log("[UGCGameState:LoadMapFinish] 地图加载完成"); -- 写一个通知 UGCEventSystem.SendEvent(EventTypes.MapLoad, self.MapData.SelectMapIndex, true); self:OnMapLoaded(); end function UGCGameState:UnLoadMapFinish() UGCLogSystem.Log("[UGCGameState:UnLoadMapFinish] 地图卸载成功") self.MiniGameManager:OnMapUnLoadedComplete(); end --- 加载小地图 function UGCGameState:LoadMinimap(InType) if type(InType) == 'nil' then for i, v in pairs(LevelTable.LevelInfo) do if v.MapName == self.LoadMapName[1].Name then UGCLogSystem.Log("[UGCGameState:LoadMinimap] 执行") self:LoadMinimap(i); return ; end end end UGCLogSystem.Log("[UGCGameState:LoadMinimap] 开始加载 %s 的小地图", tostring(InType)); local MinimapInfo = LevelTable.LevelInfo[InType].MiniMapInfo; if not table.isEmpty(MinimapInfo) then UGCLogSystem.Log("[UGCGameState:LoadMinimap] 开始添加") UGCWidgetManagerSystem.ChangeMap(MinimapInfo.MapPath, MinimapInfo.MapCentre, MinimapInfo.MapSize, MinimapInfo.MapScale); end end function UGCGameState:OnMapLoaded() --- 加载地图上的东西 UGCLogSystem.Log("[UGCGameState:OnMapLoaded] 执行") UGCEventSystem.SetTimer(self, function() self:PostOnMapLoaded(); end, 2); -- 检测一下是否有默认地图 self.MiniGameManager:OnMapLoadComplete(); for i, v in pairs(self.LoadMapName) do v.Load = true; end DOREPONCE(self, "LoadMapName"); end ---@type table 玩家中心点 UGCGameState.CenterActors = {}; function UGCGameState:PostOnMapLoaded() end ----------------------------------------- 游戏进程 ----------------------------------------- ---@param InTime int32 初始化倒计时 function UGCGameState:OnGameActive(InTime) if self.MiniGameManager then table.func(self.MiniGameManager, "OnGameActive", InTime); end end function UGCGameState:OnBeforeGameStart(InTime) --if InTime == 2 then self:BeforeReset(InTime) end if self.MiniGameManager then table.func(self.MiniGameManager, "OnBeforeGameStart", InTime); end end ---游戏正式开始 function UGCGameState:OnGameStart() UGCLogSystem.Log("[UGCGameState:OnGameStart] 执行 ") end --- 游戏结束 function UGCGameState:OnGameEnded() -- 打开结算界面 if IsServer then for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do UGCPawnSystem.LeavePawnState(v, EPawnState.Move); v:K2_DestroyActor() end UnrealNetwork.CallUnrealRPC_Multicast(self, "OnGameEnded"); self:ShowUIByType(WidgetConfig.EUIType.GameEnd, true) end end --- 倒计时 function UGCGameState:OnGameProgress_Tick(InTime) self.CountDownTime = InTime; --UGCLogSystem.Log("[UGCGameState:OnGameProgress_Tick] InTime = %s", InTime); DOREPONCE(self, "CountDownTime"); end ---@param InState EGameProgress 游戏进度 function UGCGameState:ChangeGameProgressState(InState) if self.ProgressType ~= InState then if InState == DefaultSettings.EGameProgress.PREPARE then elseif InState == DefaultSettings.EGameProgress.GAMING then LuaQuickFireEvent("GameActive", self) elseif InState == DefaultSettings.EGameProgress.ENDED then LuaQuickFireEvent("GameEnd", self) end self.ProgressType = InState; DOREPONCE(self, "ProgressType") end end function UGCGameState:OnRep_ProgressType(InOldType) UGCEventSystem.SendEvent(EventTypes.GameProgressChange, self.ProgressType); if self.ProgressType == DefaultSettings.EGameProgress.GAMING then UGCEventSystem.SendEvent(EventTypes.GameProgressChange_Gaming) -- 当到这个的时候游戏就正式开始了,发 RPC 断线重连会执行不到 --table.func(self.MiniGameManager, "OnGameStart"); self:OnGameStart() end if WidgetManager then if self.ProgressType ~= DefaultSettings.EGameProgress.ENDED then if not WidgetManager:IsVisiblePanel(WidgetConfig.EUIType.Main) then WidgetManager:ShowPanel(WidgetConfig.EUIType.Main, false); end --if self.ProgressType == DefaultSettings.EGameProgress.GAMING then -- WidgetManager:ClosePanel(WidgetConfig.EUIType.FaceNotice); --end else if WidgetManager:IsVisiblePanel(WidgetConfig.EUIType.Main) then WidgetManager:ClosePanel(WidgetConfig.EUIType.Main); end if not WidgetManager:IsVisiblePanel(WidgetConfig.EUIType.GameEnd) then WidgetManager:ShowPanel(WidgetConfig.EUIType.GameEnd, false); end end end end function UGCGameState:OnRep_CountDownTime() UGCEventSystem.SendEvent(EventTypes.GameProgressCountDownTimeChange, self.CountDownTime); end --- 当前游戏时间,以服务器为基准(因为服务器不会改变) ---客户端准备好之后会发送一个 RPC 过来,之后就是 function UGCGameState:CheckServerTime(InPlayerKey, InTime) if IsServer then local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(InPlayerKey) UnrealNetwork.CallUnrealRPC(PC, self, "CheckClientTime", UE.GetCurrentTime()); self:OnClientAlready(); else UnrealNetwork.CallUnrealRPC(LocalPlayerController, self, "CheckServerTime", InPlayerKey, InTime); end end function UGCGameState:OnRep_ServerTime() -- 接收到之后就立刻发送 RPC 到服务器,或者也可以等一会 if self.ServerTime == 1 then if LocalPlayerKey == nil or LocalPlayerController == nil then UGCEventSystem.SetTimer(self, function() self:CheckServerTime(LocalPlayerKey, UE.GetCurrentTime()) end, 1.); return ; end self:CheckServerTime(LocalPlayerKey, UE.GetCurrentTime()) elseif self.ServerTime == 0 then else local Diff = self.ServerTime - UE.GetCurrentTime(); UGCLogSystem.Log("[UGCGameState:CheckClientTime] Diff = %f", Diff) self:OnClientAlready(); end end function UGCGameState:CheckClientTime(InTime) self.ServerTimeDiff = InTime - UE.GetCurrentTime(); UGCLogSystem.Log("[UGCGameState:CheckClientTime] self.ServerTimeDiff = %f", self.ServerTimeDiff); self:OnClientAlready(); end UGCGameState.bInitOnce = false; --- 是否有毒圈:0表示未知,1表示存在,-1 表示不存在 UGCGameState.HasPoison = 0; function UGCGameState:OnClientAlready() if self.bInitOnce then return end UGCEventSystem.SendEvent(EventTypes.ClientAlready) local ServerTime = self:GetServerTime() UGCLogSystem.Log("[UGCGameState:OnClientAlready] 执行 ServerTime = %f", ServerTime); if IsServer then UGCLogSystem.Log("[UGCGameState:OnClientAlready] 执行") self:OnGameActive(-1) end self:LoadResource(); if GlobalBeginTool then GlobalBeginTool:ReceiveClientAlready() GlobalBeginTool = nil; end self.bInitOnce = true; end --- S & C : 获取服务器时间 ---@return float|nil function UGCGameState:GetServerTime() if IsServer then return UE.GetCurrentTime(); else if self.ServerTimeDiff == 0 then return nil; else return self.ServerTimeDiff + UE.GetCurrentTime(); end end end --- 获取客户端时间 function UGCGameState:GetClientTime(InPlayerKey) if IsClient then return UE.GetCurrentTime(); else end end function UGCGameState:ClearAll() UnableTable() end --- 提前重置操作 function UGCGameState:BeforeReset(InTime) UGCLogSystem.Log("[UGCGameState:BeforeReset] 重置玩家") for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(v.PlayerKey); if Pawn and UE.IsValid(Pawn) and Pawn:IsAlive() then Pawn:K2_DestroyActor(); end UE.RespawnPlayer(v.PlayerKey, InTime); end --LuaQuickFireEvent("AllPlayerReset", self); self:ResetKill(); end function UGCGameState:ResetKill() -- 重置伤害 for i, v in pairs(self.PlayerKDA_Damages) do v.Damage = 0; v.KDA = { Kill = 0, Dead = 0, Assist = 0, } end for i, v in pairs(self.PlayerAttribute) do for c, d in pairs(v) do v[c] = DefaultSettings.BenefitInto[c].DefaultValue; end end -- 重置其他的 for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do v:ResetGame(); end DOREPONCE(self, "PlayerKDA_Damages") DOREPONCE(self, "PlayerAttribute") end --- 重置游戏 function UGCGameState:ResetGame() if IsServer then UnrealNetwork.CallUnrealRPC_Multicast(self, "ResetGame"); -- 重置击杀数 for i, v in pairs(UGCGameSystem.GetAllPlayerState(false)) do v:ResetKillNum(); end end end ----------------------------------------- 界面 UI ----------------------------------------- --- 显示 UI ---@param InUIType EUIType ---@param IsShow boolean function UGCGameState:ShowUIByType(InUIType, IsShow, ...) if IsServer then UnrealNetwork.CallUnrealRPC_Multicast(self, "ShowUIByType", InUIType, IsShow, ...); else if IsShow then WidgetManager:ShowPanel(InUIType, false, ...); else WidgetManager:ClosePanel(InUIType); end end end --- 显示 UI ---@param InUIType EUIType ---@param IsShow bool ---@param InPlayerKey PlayerKey function UGCGameState:PlayerShowUIByType(InUIType, IsShow, InPlayerKey, ...) if IsServer then if InPlayerKey == nil then UnrealNetwork.CallUnrealRPC_Multicast(self, "PlayerShowUIByType", InUIType, IsShow, ...); else UnrealNetwork.CallUnrealRPC(UGCGameSystem.GetPlayerControllerByPlayerKey(InPlayerKey), self, "PlayerShowUIByType", InUIType, IsShow, ...); end else if IsShow then WidgetManager:ShowPanel(InUIType, false, InPlayerKey, ...); else WidgetManager:ClosePanel(InUIType); end end end --- 保存或者获取数据 function UGCGameState:Server_SaveOrGetButtonSetting(PlayerKey, ButtonsRender) if ButtonsRender == nil then ButtonsRender = self.PlayerDatas.ArchiveData[PlayerKey].ButtonSettings; else self.PlayerDatas.ArchiveData[PlayerKey].ButtonSettings = ButtonsRender; end -- 提醒已经好了 self:SendEvent(true, PlayerKey, EventTypes.ButtonSettingCallBack, ButtonsRender); end ----------------------------------------- 场景物品 ----------------------------------------- ---@type BP_ResourceBase_C UGCGameState.ResourceActor = nil; --- 加载资源类,服务器,客户端都需要加载一次 ---@return BP_ResourceBase_C function UGCGameState:LoadResource() if self.ResourceActor == nil then self.ResourceActor = UE.FindActorByClass(ObjectPath.BP_ResourceBase); end UGCLogSystem.Log("[UGCGameState:LoadResource] %s", UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/UGCPlayerPawn.UGCPlayerPawn_C')) return self.ResourceActor; end -- 清除场景上的 Wrappers function UGCGameState:ClearWrappers() local InTable = {}; UE.FindActorsByClass(self:GetWrapperClass(), InTable, function(InIndex, InActor) return InActor:GetOwner() == nil; end); for i, v in pairs(InTable) do v:K2_DestroyActor(); end end ----------------------------------------- BUFF ----------------------------------------- ---@type AActor UGCGameState.MapCenterActor = nil; --- 获取中心点 ---@return AActor function UGCGameState:GetCenterPointLocation() if self.MapCenterActor ~= nil then return self.MapCenterActor:K2_GetActorLocation() end local CenterActors = {}; UE.FindActorsByClass(ObjectPath.BP_ActorStart, CenterActors, function(InIndex, InActor) return InActor:ActorHasTag("MapCenter"); end); UGCLogSystem.LogTree(string.format("[UGCGameState:GetCenterPointLocation] CenterActors ="), CenterActors) self.MapCenterActor = CenterActors[1]; if self.MapCenterActor == nil then return VectorHelper.ToLuaTable(DefaultSettings.MapCenterLocation) end return CenterActors[1]:K2_GetActorLocation(); end ----------------------------------------- 武器 ----------------------------------------- --- 获取武器基类 ---@return UClass 武器基类 function UGCGameState:GetShootWeaponClass() return self.ShootWeaponClass; end ---@return UClass function UGCGameState:GetWrapperClass() return self.WrapperClass; end ----------------------------------------- 载具 ----------------------------------------- --- 清空地面上的载具 function UGCGameState:ClearVehicles() if table.isEmpty(self.Vehicles) then self:FindVehicles(); end for i, v in pairs(self.Vehicles) do v:K2_DestroyActor(); end self.Vehicles = {}; end --- 加载地面上的载具,通过 ActorStart 进行查找 function UGCGameState:LoadVehicles() self:ClearVehicles(); local AllStarts = {}; UE.FindActorsByClass(ObjectPath.BP_ActorStart, AllStarts, function(InIndex, InActor) table.insert(self.Vehicles, UGCVehicleSystem.SpawnVehicleNew(VehicleTable.Car[InActor.Index].Path, InActor:K2_GetActorLocation(), InActor:K2_GetActorRotation(), false, false)); return true; end) end -- 查找载具 function UGCGameState:FindVehicles() if table.isEmpty(self.Vehicles) then self:LoadVehicles(); end return self.Vehicles; end ----------------------------------------- 信号圈 ----------------------------------------- ---@type PoisonCircleSystem_C UGCGameState.PoisonSystemActor = nil; ---@return PoisonCircleSystem_C function UGCGameState:FindPoisonCircle() if self.PoisonSystemActor == nil then self.PoisonSystemActor = UE.FindActorByClass(ObjectPath.PoisonCircleSystem); end return self.PoisonSystemActor; end ----------------------------------------- FUNCTIONAL ----------------------------------------- --- 发送自定义事件 function UGCGameState:SendEvent(IsSend, InPlayerKey, InEvent, ...) if IsServer then if IsSend then if InPlayerKey == nil then UnrealNetwork.CallUnrealRPC_Multicast(self, "SendEvent", false, nil, InEvent, ...); else UnrealNetwork.CallUnrealRPC(UGCGameSystem.GetPlayerControllerByPlayerKey(InPlayerKey), UGCGameSystem.GameState, "SendEvent", false, InPlayerKey, InEvent, ...); end else UGCEventSystem.SendEvent(InEvent, InPlayerKey, ...) end else -- 从客户端发送出去 if IsSend then UnrealNetwork.CallUnrealRPC(DefaultSettings.LocalPlayerController, UGCGameSystem.GameState, "SendEvent", false, DefaultSettings.LocalPlayerKey, InEvent, ...); else UGCEventSystem.SendEvent(InEvent, InPlayerKey, ...); end end end ----------------------------------------- 玩家属性 ----------------------------------------- --- 获取属性值和属性名称 ---@param InPlayerKey PlayerKey ---@param InAttributeName EPawnBenefitType function UGCGameState:GetPlayerAttribute(InPlayerKey, InAttributeName) if InAttributeName then if self.PlayerAttribute[InPlayerKey] ~= nil then return self.PlayerAttribute[InPlayerKey][InAttributeName]; end return nil; end return self.PlayerAttribute[InPlayerKey]; end function UGCGameState:AddPlayerAttribute(InPlayerKey, InAttributeName, InVal) self.PlayerAttribute[InPlayerKey][InAttributeName] = self.PlayerAttribute[InPlayerKey][InAttributeName] + InVal; if IsServer then DOREPONCE(self, "PlayerAttribute") end end function UGCGameState:MultiPlayerAttribute(InPlayerKey, InAttributeName, InVal) self.PlayerAttribute[InPlayerKey][InAttributeName] = self.PlayerAttribute[InPlayerKey][InAttributeName] * InVal; if IsServer then DOREPONCE(self, "PlayerAttribute") end end function UGCGameState:InitAttribute() local Table = {}; for i, v in pairs(DefaultSettings.EPawnBenefitType) do Table[v] = 1; end Table[DefaultSettings.EPawnBenefitType.Shield] = 0; return Table; end ---@param InPlayerKey PlayerKey function UGCGameState:PawnApplyBuff(InPlayerKey) local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(InPlayerKey); Pawn:ApplyBuff("ApplyKillChange"); end ----------------------------------------- MINI ----------------------------------------- UGCGameState.MiniModeState = nil; --- 当前选择的 MiniType UGCGameState.CurrMiniType = -1; ---@param InMiniType int32 function UGCGameState:SelectMiniType(InMiniType) self.CurrMiniType = InMiniType; DOREPONCE(self, "CurrMiniType"); end function UGCGameState:OnRep_CurrMiniType() if self.CurrMiniType < 0 then return ; end if self.MiniGameManager then self.MiniGameManager:LoadMiniGame(self.CurrMiniType); end end function UGCGameState:SetMiniModeState(InState) self.MiniModeState = InState; DOREPONCE(self, "MiniModeState"); end function UGCGameState:GetMiniModeState() return self.MiniModeState; end function UGCGameState:OnRep_MiniModeState(Old) if self.MiniGameManager then self.MiniGameManager.State = self.MiniModeState; self.MiniGameManager:OnRep_State(Old); end end --- 发送 MiniGame RPC ---@param InFuncName string 函数名称 ---@vararg any function UGCGameState:SendMiniGameRPC(InFuncName, ...) if IsServer then UnrealNetwork.CallUnrealRPC_Multicast(self, "MiniGameReceiveRPC", InFuncName, true, ...); else UnrealNetwork.CallUnrealRPC(LocalPlayerController, self, "MiniGameReceiveRPC", InFuncName, false, ...); end end --- Mini Game 接收到 RPC ---@param InFuncName string 函数名称 ---@param SendFromServer bool 是否发自服务器 function UGCGameState:MiniGameReceiveRPC(InFuncName, SendFromServer, ...) table.func(self.MiniGameManager, InFuncName, ...) end --- 小游戏需要同步的数据 UGCGameState.MiniInfo = {}; function UGCGameState:SetMiniInfo(InMiniInfo) self.MiniInfo = InMiniInfo; DOREPONCE(self, "MiniInfo"); end function UGCGameState:OnRep_MiniInfo(InOld) if table.isEmpty(self.MiniInfo) then return ; end -- 发送出去 if self.MiniGameManager then self.MiniGameManager.MiniInfo = self.MiniInfo; self.MiniGameManager:OnRep_MiniInfo(InOld); end end --- 获取 MiniGame 的数据 function UGCGameState:GetMiniInfo(Name) if self.MiniGameManager then return table.func(self.MiniGameManager, "GetMiniInfo", Name); end return nil; end --- 获取配置 function UGCGameState:GetMiniConfig(Name) if self.MiniGameManager then return table.func(self.MiniGameManager, "GetMiniInfo", Name); end return nil; end return UGCGameState;