884 lines
28 KiB
Lua
884 lines
28 KiB
Lua
|
---@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<PlayerKey, any>
|
|||
|
ArchiveData = {};
|
|||
|
---@type table<PlayerKey, PlayerAccountInfo>
|
|||
|
AccountInfo = {};
|
|||
|
};
|
|||
|
---@type table<TeamId, table<int32, PlayerKey>> 玩家 Key 列表
|
|||
|
UGCGameState.PlayerList = {};
|
|||
|
---@type table<int32, PlayerKDA_DamageItem> 支持排序功能
|
|||
|
UGCGameState.PlayerKDA_Damages = {};
|
|||
|
--- 游戏进程数据
|
|||
|
UGCGameState.CountDownTime = 0;
|
|||
|
UGCGameState.ProgressType = DefaultSettings.EGameProgress.NON_START;
|
|||
|
|
|||
|
---@type table<PlayerKey, PlayerAttributeItem_BigFight> 玩家属性
|
|||
|
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<ArchiveData>
|
|||
|
---@param InAccountData table<PlayerAccountInfo>
|
|||
|
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<PlayerKey, PlayerAttributeItem_BigFight>
|
|||
|
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<int32, string> 地图索引
|
|||
|
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<int32, BP_ActorStart_C> 玩家中心点
|
|||
|
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;
|