1307 lines
43 KiB
Lua
1307 lines
43 KiB
Lua
|
---@class UGCGameState_C:BP_UGCGameState_C
|
||
|
---@field VehicleClass UClass
|
||
|
---@field ShootWeaponClass UClass
|
||
|
--Edit Below--
|
||
|
|
||
|
UGCGameSystem.UGCRequire('Script.Common.ue_enum_custom')
|
||
|
require('Script.Global.Global')
|
||
|
|
||
|
---@type UGCGameState_C
|
||
|
local UGCGameState = {
|
||
|
CountDownTime = 0.;
|
||
|
ProcessState = 0;
|
||
|
---@type table<PlayerKey, ESoldierType> 队伍兵种类型
|
||
|
PlayerSoldierType = {};
|
||
|
---@type table<PlayerKey, table<TechnologyType, uint32>> 玩家的分数
|
||
|
PlayerScores = {};
|
||
|
---@type table<PlayerKey, ELevelType> 玩家选择的地图
|
||
|
PlayerSelectLevels = {};
|
||
|
---@type table<int32, PlayerDamageItem> 玩家造成的伤害
|
||
|
PlayerDamage = {};
|
||
|
---@type table<int32, ItemId> { [RoundTime] = TeamId } 哪局是哪个队伍赢了
|
||
|
GameRounds = {};
|
||
|
---@type int32 赢取的队伍ID
|
||
|
WinTeamId = -1;
|
||
|
CachedInit = {};
|
||
|
---@type table<int32, table<int32, PlayerKey>> 存在的玩家
|
||
|
ExistPlayerKeys = {};
|
||
|
};
|
||
|
|
||
|
---@type table<PlayerKey, ArchiveData> 玩家的存档数据
|
||
|
UGCGameState.PlayerArchives = {};
|
||
|
--- @type table<PlayerKey, PlayerAccountInfo>
|
||
|
UGCGameState.PlayerAccountInfoMap = {};
|
||
|
---@type table<PlayerKey, PlayerKDAItem>
|
||
|
UGCGameState.TotalPlayerKDA = {};
|
||
|
---@type table<int, table<int, PlayerKey>> { TeamId: { PlayerKey, PlayerKey, ... } }
|
||
|
UGCGameState.PlayerTeams = {};
|
||
|
UGCGameState.ServerTime = 0;
|
||
|
UGCGameState.ServerTimeDiff = 0;
|
||
|
|
||
|
-- 游戏回合相关数据
|
||
|
UGCGameState.RoundInfo = {
|
||
|
-- 当前回合次数
|
||
|
CurrRoundTime = 0;
|
||
|
-- 当前回合状态
|
||
|
RoundState = RoundState.Prepare;
|
||
|
RoundCountTime = 0.;
|
||
|
RoundSettleCountTime = 0.;
|
||
|
};
|
||
|
|
||
|
function UGCGameState:ReceiveBeginPlay()
|
||
|
UGCGameState.SuperClass.ReceiveBeginPlay(self);
|
||
|
self:SetProcessState(EventTypes.GameProcessStates.Prepare);
|
||
|
GlobalInit.InitGlobalVar();
|
||
|
self.bIsOpenShovelingAbility = true
|
||
|
UGCSendRPCSystem.InitUGCSendRPCSystem(self, "UGCSendRPCSystemFunc");
|
||
|
|
||
|
if not self:HasAuthority() then
|
||
|
LocalPlayerController = STExtraGameplayStatics.GetFirstPlayerController(self);
|
||
|
LocalPlayerKey = LocalPlayerController.PlayerKey;
|
||
|
|
||
|
UGCEventSystem.AddListener(EventTypes.PlayerUseBuff, self.OnPlayerUseBuff, self)
|
||
|
end
|
||
|
|
||
|
-- 在游戏开始的时候加载一下 BP_BuffManager
|
||
|
require('Script.Blueprint.BUFF.BP_BuffManager');
|
||
|
if self:HasAuthority() then
|
||
|
local Manager = BP_BuffManager.GetBuffManager();
|
||
|
Manager:Init(function(InPlayerKey, InPlayerKeyList, InBuffType)
|
||
|
self:ClientSendEvent(nil, EventTypes.SkillBenefit, InPlayerKey, InPlayerKeyList, InBuffType);
|
||
|
end);
|
||
|
self.ServerTime = 1;
|
||
|
DOREPONCE(self, "ServerTime");
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:ReceiveTick(DeltaTime)
|
||
|
self.SuperClass.ReceiveTick(self, DeltaTime);
|
||
|
GlobalTickTool:ReceiveTick(DeltaTime, self:GetServerTime());
|
||
|
end
|
||
|
|
||
|
function UGCGameState:GetReplicatedProperties()
|
||
|
return
|
||
|
"PlayerSoldierType",
|
||
|
{ "CountDownTime", "Lazy" },
|
||
|
{ "PlayerAccountInfoMap", "Lazy" },
|
||
|
{ "PlayerArchives", "Lazy" },
|
||
|
{ "ProcessState", "Lazy" },
|
||
|
{ "PlayerTeams", "Lazy" },
|
||
|
{ "TotalPlayerKDA", "Lazy" },
|
||
|
{ "PlayerSelectLevels", "Lazy" },
|
||
|
{ "PlayerScores", "Lazy" },
|
||
|
{ "PlayerDamage", "Lazy" },
|
||
|
{ "WinTeamId", "Lazy" },
|
||
|
{ "GameRounds", "Lazy" },
|
||
|
{ "RoundInfo", "Lazy" },
|
||
|
{ "ServerTime", "Lazy" },
|
||
|
{ "SelectMapIndex", "Lazy" }
|
||
|
end
|
||
|
|
||
|
function UGCGameState:GetAvailableServerRPCs()
|
||
|
return "RPCDelegationFunc",
|
||
|
"UGCSendRPCSystemFunc",
|
||
|
"CheckServerTime",
|
||
|
"Server_SelectMap"
|
||
|
end
|
||
|
|
||
|
function UGCGameState:UGCSendRPCSystemFunc(...) UGCSendRPCSystem.RPCFunc(...) end
|
||
|
function UGCGameState:OnRep_CountDownTime() UGCEventSystem.SendEvent(EventTypes.UpdateWaitingTime, self.CountDownTime); end
|
||
|
function UGCGameState:OnRep_ProcessState() UGCEventSystem:SendEvent(EventTypes.ChangeProcessState, self.ProcessState); end
|
||
|
|
||
|
function UGCGameState:OnRep_PlayerAccountInfoMap()
|
||
|
if table.isEmpty(self.PlayerAccountInfoMap) then return ; end
|
||
|
UGCEventSystem.SendEvent(EventTypes.UpdatePlayerAccountInfo, self.PlayerAccountInfoMap);
|
||
|
end
|
||
|
|
||
|
-- 同步队伍信息
|
||
|
function UGCGameState:OnRep_PlayerTeams()
|
||
|
if table.getCount(self.PlayerTeams) == 0 then return ; end
|
||
|
UGCEventSystem.SendEvent(EventTypes.UpdateNewTeams, self.PlayerTeams);
|
||
|
|
||
|
-- 获取本地 PlayerKey
|
||
|
if LocalPlayerKey == nil then return ; end
|
||
|
|
||
|
for TeamId, PlayerKeys in pairs(self.PlayerTeams) do
|
||
|
for i, PlayerKey in pairs(PlayerKeys) do
|
||
|
if PlayerKey == LocalPlayerKey then
|
||
|
DefaultSettings.LocalTeamId = TeamId;
|
||
|
break ;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
for i, v in pairs(self.PlayerTeams) do
|
||
|
if i ~= DefaultSettings.LocalTeamId and i ~= -1 then
|
||
|
DefaultSettings.EnemyTeamId = i;
|
||
|
break ;
|
||
|
end
|
||
|
end
|
||
|
if DefaultSettings.LocalTeamId == nil then return ; end
|
||
|
|
||
|
local LocalKeys = self.PlayerTeams[DefaultSettings.LocalTeamId];
|
||
|
end
|
||
|
|
||
|
function UGCGameState:OnRep_PlayerSoldierType()
|
||
|
-- 同步一下
|
||
|
if table.isEmpty(self.PlayerSoldierType) then return ; end
|
||
|
-- 检查客户端是否存在
|
||
|
UGCEventSystem.SendEvent(EventTypes.SelectSoldierType, self.PlayerSoldierType);
|
||
|
|
||
|
local Type = self.PlayerSoldierType[LocalPlayerKey];
|
||
|
if Type == nil then return ; end
|
||
|
|
||
|
if LocalPlayerController:GetSoldierBase(Type) == nil then
|
||
|
LocalPlayerController:AddSoldierBase(Type);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:OnRep_PlayerSelectLevels()
|
||
|
if table.isEmpty(self.PlayerSelectLevels) then return ; end
|
||
|
UGCEventSystem.SendEvent(EventTypes.UpdateSelectLevels, self.PlayerSelectLevels);
|
||
|
end
|
||
|
|
||
|
function UGCGameState:OnRep_TotalPlayerKDA()
|
||
|
-- 同步 KDA
|
||
|
if LocalPlayerKey == nil or table.isEmpty(self.TotalPlayerKDA) then return ; end
|
||
|
-- 更新玩家的 KDA 信息
|
||
|
UGCEventSystem.SendEvent(EventTypes.UpdatePlayerKDA, self.TotalPlayerKDA);
|
||
|
UGCLogSystem.LogTree("[UGCGameState:OnRep_PlayerKDA] TotalPlayerKDA = ", self.TotalPlayerKDA)
|
||
|
end
|
||
|
|
||
|
function UGCGameState:OnRep_PlayerArchives(OldArchive)
|
||
|
if table.isEmpty(self.PlayerArchives) then return ; end
|
||
|
-- 判断是否有自己的存档
|
||
|
if LocalPlayerKey == nil then return ; end
|
||
|
local OldData = nil
|
||
|
if OldArchive ~= nil then OldData = OldArchive[LocalPlayerKey] end
|
||
|
local LocalArchiveData = self.PlayerArchives[LocalPlayerKey];
|
||
|
if OldData == nil and LocalArchiveData ~= nil then
|
||
|
UGCLogSystem.LogTree(string.format("[UGCGameState:OnRep_PlayerArchives] LocalArchiveData ="), LocalArchiveData)
|
||
|
if self.RoundInfo.RoundState == RoundState.Prepare then
|
||
|
WidgetManager:ShowPanel(WidgetConfig.EUIType.SelectSoldier, false);
|
||
|
if DefaultSettings.EnableLevels then
|
||
|
WidgetManager:ShowPanel(WidgetConfig.EUIType.SelectMap, false);
|
||
|
end
|
||
|
end
|
||
|
if LocalArchiveData ~= nil and LocalArchiveData.LoginTimes ~= nil and LocalArchiveData.LoginTimes <= 3 and not DefaultSettings.HadShowFaceNotice then
|
||
|
DefaultSettings.HadShowFaceNotice = true;
|
||
|
WidgetManager:ShowPanel(WidgetConfig.EUIType.FaceNotice, false);
|
||
|
end
|
||
|
end
|
||
|
UGCEventSystem.SendEvent(EventTypes.UpdatePlayerArchive, LocalArchiveData);
|
||
|
end
|
||
|
|
||
|
function UGCGameState:OnRep_GameRounds()
|
||
|
if table.isEmpty(self.GameRounds) then return ; end
|
||
|
UGCEventSystem.SendEvent(EventTypes.UpdateGameRound, self.GameRounds);
|
||
|
self.CachedGameRounds = self.GameRounds;
|
||
|
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:CheckServerTime(InPlayerKey, InTime)
|
||
|
if UGCGameSystem.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:CheckClientTime(InTime)
|
||
|
self.ServerTimeDiff = InTime - UE.GetCurrentTime();
|
||
|
UGCLogSystem.Log("[UGCGameState:CheckClientTime] self.ServerTimeDiff = %f", self.ServerTimeDiff);
|
||
|
self:OnClientAlready();
|
||
|
end
|
||
|
|
||
|
UGCGameState.bInitOnce = false;
|
||
|
|
||
|
function UGCGameState:OnClientAlready()
|
||
|
if self.bInitOnce then return end
|
||
|
UGCEventSystem.SendEvent(EventTypes.ClientAlready)
|
||
|
|
||
|
local ServerTime = self:GetServerTime();
|
||
|
UGCLogSystem.Log("[UGCGameState:OnClientAlready] 执行 ServerTime = %f", ServerTime);
|
||
|
|
||
|
self.bInitOnce = true;
|
||
|
end
|
||
|
|
||
|
--- S & C : 获取服务器时间
|
||
|
---@return float|nil
|
||
|
function UGCGameState:GetServerTime()
|
||
|
if UGCGameSystem.IsServer() then
|
||
|
return UE.GetCurrentTime();
|
||
|
else
|
||
|
if self.ServerTimeDiff == 0 then
|
||
|
return nil;
|
||
|
else
|
||
|
return self.ServerTimeDiff + UE.GetCurrentTime();
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
----------------------------------
|
||
|
|
||
|
---@param InKey PlayerKey
|
||
|
---@param InData PlayerAccountInfo
|
||
|
function UGCGameState:LoadAccountInfo(InKey, InData)
|
||
|
self.PlayerAccountInfoMap[InKey] = InData;
|
||
|
DOREPONCE(self, "PlayerAccountInfoMap");
|
||
|
end
|
||
|
|
||
|
--- 初始化存档信息
|
||
|
function UGCGameState:InitArchiveData()
|
||
|
local Table = {
|
||
|
-- 登录次数
|
||
|
LoginTimes = 1;
|
||
|
-- 不同兵种选择
|
||
|
SoldierSelect = {};
|
||
|
-- 分数
|
||
|
Scores = {};
|
||
|
-- 已经解锁的类型
|
||
|
UnlockTypes = {};
|
||
|
};
|
||
|
|
||
|
for i, v in pairs(SoldierConfig.InitShowTypes) do Table.UnlockTypes[i] = v; end
|
||
|
|
||
|
return Table;
|
||
|
end
|
||
|
|
||
|
---@param InKey PlayerKey
|
||
|
---@param InData ArchiveData
|
||
|
function UGCGameState:LoadArchiveData(InKey, InData)
|
||
|
if InData == nil or table.getCount(InData) == 0 then
|
||
|
InData = self:InitArchiveData();
|
||
|
else
|
||
|
if type(InData.LoginTimes) == 'number' then
|
||
|
InData.LoginTimes = InData.LoginTimes + 1;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
self.PlayerArchives[InKey] = InData;
|
||
|
self:CheckUnlockType(InKey);
|
||
|
DOREPONCE(self, "PlayerArchives");
|
||
|
end
|
||
|
|
||
|
---@param InKey PlayerKey
|
||
|
function UGCGameState:CheckUnlockType(InKey)
|
||
|
local Scores = self.PlayerArchives[InKey].Scores;
|
||
|
local UnlockTypes = self.PlayerArchives[InKey].UnlockTypes;
|
||
|
local Total = 0;
|
||
|
if not table.isEmpty(Scores) then
|
||
|
for ScoreType, Count in pairs(Scores) do Total = Total + Count; end
|
||
|
end
|
||
|
|
||
|
for i, v in pairs(SoldierConfig.UnlockScore) do
|
||
|
if Total >= v.Score then
|
||
|
if not UnlockTypes[i] then self.PlayerArchives[InKey].UnlockTypes[i] = true; end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---@return PlayerKDAItem
|
||
|
function UGCGameState:InitPlayerKda()
|
||
|
return {
|
||
|
Kill = 0,
|
||
|
Dead = 0,
|
||
|
Assist = 0,
|
||
|
};
|
||
|
end
|
||
|
|
||
|
--- 更新玩家的 KDA
|
||
|
function UGCGameState:UpdateKDA(InPlayerKey, KillerPlayerKey)
|
||
|
if self.TotalPlayerKDA[InPlayerKey] then
|
||
|
self.TotalPlayerKDA[InPlayerKey].Dead = (self.TotalPlayerKDA[InPlayerKey].Dead or 0) + 1;
|
||
|
end
|
||
|
if self.TotalPlayerKDA[KillerPlayerKey] then
|
||
|
self.TotalPlayerKDA[KillerPlayerKey].Kill = (self.TotalPlayerKDA[KillerPlayerKey].Kill or 0) + 1;
|
||
|
end
|
||
|
|
||
|
DOREPONCE(self, "TotalPlayerKDA");
|
||
|
end
|
||
|
|
||
|
function UGCGameState:InitPlayerScore()
|
||
|
return {
|
||
|
[SoldierConfig.TechnologyType.Kill] = 0;
|
||
|
[SoldierConfig.TechnologyType.RoundWin] = 0;
|
||
|
[SoldierConfig.TechnologyType.Survive] = 0;
|
||
|
[SoldierConfig.TechnologyType.Recovery] = 0;
|
||
|
[SoldierConfig.TechnologyType.TrapDamage] = 0;
|
||
|
};
|
||
|
end
|
||
|
|
||
|
-- 添加玩家到队伍信息中
|
||
|
function UGCGameState:AddTeamPlayer(InTeamId, InKey)
|
||
|
if self.PlayerTeams[InTeamId] == nil then self.PlayerTeams[InTeamId] = {}; end
|
||
|
-- 判断当前是否有玩家
|
||
|
if self.PlayerDamage[InKey] ~= nil then return ; end
|
||
|
UGCLogSystem.Log("[UGCGameState:AddTeamPlayer] InTeamId = %d, InPlayerKey = %s", InTeamId, tostring(InKey))
|
||
|
|
||
|
table.insert(self.PlayerTeams[InTeamId], InKey)
|
||
|
UGCLogSystem.LogTree("[UGCGameState:AddTeamPlayer] self.PlayerTeams = ", self.PlayerTeams);
|
||
|
|
||
|
if self.PlayerScores[InKey] == nil then self.PlayerScores[InKey] = self:InitPlayerScore(); end
|
||
|
self.TotalPlayerKDA[InKey] = self:InitPlayerKda();
|
||
|
self.PlayerDamage[InKey] = 0;
|
||
|
|
||
|
-- 检查当前是否有足够的玩家
|
||
|
UnrealNetwork.CallUnrealRPC(self, self, "AllPlayerReady");
|
||
|
self:AllPlayerReady();
|
||
|
|
||
|
DOREPONCE(self, "PlayerTeams");
|
||
|
DOREPONCE(self, "PlayerScores");
|
||
|
DOREPONCE(self, "TotalPlayerKDA");
|
||
|
DOREPONCE(self, "PlayerDamage");
|
||
|
end
|
||
|
|
||
|
-- 添加Round
|
||
|
function UGCGameState:StartRound(InVal)
|
||
|
if self:HasAuthority() then
|
||
|
UGCLogSystem.Log("[UGCGameState:StartRound] 执行服务端")
|
||
|
InVal = InVal == nil and 1 or InVal
|
||
|
|
||
|
UGCEventSystem.SetTimer(self, function()
|
||
|
self:OnFormalStart();
|
||
|
end, DefaultSettings.SelectWeaponShowTime);
|
||
|
|
||
|
self.RoundInfo.CurrRoundTime = self.RoundInfo.CurrRoundTime + InVal
|
||
|
self.RoundInfo.RoundState = RoundState.PreRound;
|
||
|
if self.RoundInfo.CurrRoundTime == 1 then self:FirstRound() end
|
||
|
-- 通知客户端
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "StartRound", self.RoundInfo);
|
||
|
DOREPONCE(self, "RoundInfo");
|
||
|
|
||
|
local PCs = UGCGameSystem.GetAllPlayerController();
|
||
|
for i, v in pairs(PCs) do v:OnStartRound(); end
|
||
|
|
||
|
-- 检查当前是否有武器
|
||
|
self:CheckPlayerHasSoldierType();
|
||
|
-- 重置玩家是否存活
|
||
|
self:StartPoison(self.SelectMapIndex);
|
||
|
self:LoadVehicles();
|
||
|
else
|
||
|
UGCLogSystem.Log("[UGCGameState:StartRound] 执行客户端")
|
||
|
if InVal.CurrRoundTime == 1 then
|
||
|
WidgetManager:ClosePanel(WidgetConfig.EUIType.FaceNotice);
|
||
|
WidgetManager:ClosePanel(WidgetConfig.EUIType.WaitingTime);
|
||
|
WidgetManager:ShowPanel(WidgetConfig.EUIType.Main, false);
|
||
|
end
|
||
|
WidgetManager:ClosePanel(WidgetConfig.EUIType.SelectSoldier);
|
||
|
WidgetManager:ClosePanel(WidgetConfig.EUIType.RoundWin);
|
||
|
|
||
|
-- 显示一下选择武器
|
||
|
WidgetManager:ShowPanel(WidgetConfig.EUIType.Backpack, false);
|
||
|
-- 显示 控制面板
|
||
|
local MainControlPanel = GameBusinessManager.GetWidgetFromName(ingame, "MainControlPanelTochButton_C");
|
||
|
MainControlPanel:SetVisibility(ESlateVisibility.SelfHitTestInvisible);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--function UGCGameState:GetSelectMapIndex()
|
||
|
-- if self.PoisonManager then
|
||
|
-- return self.PoisonManager:GetSelectMapIndex();
|
||
|
-- end
|
||
|
-- return -1;
|
||
|
--end
|
||
|
|
||
|
UGCGameState.Vehicles = {};
|
||
|
|
||
|
function UGCGameState:GetShootWeaponClass()
|
||
|
return self.ShootWeaponClass;
|
||
|
end
|
||
|
|
||
|
function UGCGameState:LoadVehicles()
|
||
|
if not table.isEmpty(self.Vehicles) then
|
||
|
self:DestroyVehicles();
|
||
|
end
|
||
|
local AllActors = {};
|
||
|
UE.FindActorsByClass(ObjectPath.BP_ActorStart, AllActors, function(InIndex, InActor)
|
||
|
if InActor:ActorHasTag("Vehicle") then
|
||
|
if InActor.Index and not table.isEmpty(VehicleTable.Car[InActor.Index]) then
|
||
|
local Vehicle = UGCVehicleSystem.SpawnVehicleNew(VehicleTable.Car[InActor.Index].Path, InActor:K2_GetActorLocation(), InActor:K2_GetActorRotation(), false, false);
|
||
|
table.insert(self.Vehicles, Vehicle);
|
||
|
return true;
|
||
|
end
|
||
|
return false;
|
||
|
end
|
||
|
return false;
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
function UGCGameState:DestroyVehicles()
|
||
|
if not table.isEmpty(self.Vehicles) then
|
||
|
for i, v in pairs(self.Vehicles) do
|
||
|
UGCVehicleSystem.DestroySelf(v);
|
||
|
end
|
||
|
end
|
||
|
self.Vehicles = {};
|
||
|
end
|
||
|
|
||
|
function UGCGameState:FirstRound()
|
||
|
if self:HasAuthority() then
|
||
|
-- 同步一下
|
||
|
local PCs = UGCGameSystem.GetAllPlayerController();
|
||
|
for i, v in pairs(PCs) do
|
||
|
if UE.IsValid(v) then v:AddSoldierBase(self.PlayerSoldierType[v.PlayerKey]); end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:FirstFormalStart()
|
||
|
end
|
||
|
|
||
|
--- 正式开始游戏
|
||
|
function UGCGameState:OnFormalStart()
|
||
|
UGCLogSystem.Log("[UGCGameState:OnFormalStart] 执行")
|
||
|
if UGCGameSystem.IsServer() then
|
||
|
self:CheckHasWeapons();
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "OnFormalStart");
|
||
|
|
||
|
-- 开始打架
|
||
|
self.RoundInfo.RoundState = RoundState.InRound;
|
||
|
-- 所有玩家装上武器
|
||
|
local PCs = UGCGameSystem.GetAllPlayerController(false);
|
||
|
-- 检查是否存在属性
|
||
|
for i, v in pairs(PCs) do v:OnFormalStart(); end
|
||
|
|
||
|
-- 保存一下当前载具的位置,然后之后就重置到该位置
|
||
|
self:ResetGameState();
|
||
|
if self.RoundInfo.CurrRoundTime == 1 then self:FirstFormalStart(); end
|
||
|
|
||
|
-- 检查一下是否有人,
|
||
|
local IsAloneTeam, TeamId = self:CheckExistPlayers();
|
||
|
if IsAloneTeam then self:GotoGameEnd(TeamId) end
|
||
|
DOREPONCE(self, "RoundInfo")
|
||
|
else
|
||
|
local MainControlPanel = GameBusinessManager.GetWidgetFromName(ingame, "MainControlPanelTochButton_C");
|
||
|
MainControlPanel:SetVisibility(ESlateVisibility.SelfHitTestInvisible);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:CheckHasSoldier()
|
||
|
-- 检查是否有兵种,没有兵种给一个兵种
|
||
|
UGCLogSystem.Log("[UGCGameState:CheckHasSoldier] 开始检查是否有兵种")
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
|
||
|
if self.PlayerSoldierType[v.PlayerKey] == nil then
|
||
|
self.PlayerSoldierType[v.PlayerKey] = math.random(table.getCount(SoldierConfig.ESoldierType));
|
||
|
end
|
||
|
end
|
||
|
UGCLogSystem.LogTree(string.format("[UGCGameState:CheckHasSoldier] self.PlayerSoldierType ="), self.PlayerSoldierType)
|
||
|
end
|
||
|
|
||
|
--- 强制检查是否有枪,没有枪直接添加
|
||
|
function UGCGameState:CheckHasWeapons()
|
||
|
UGCLogSystem.Log("[UGCGameState:CheckHasWeapons] 开始检查是否有武器")
|
||
|
self:CheckHasSoldier();
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
|
||
|
local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(v.PlayerKey);
|
||
|
if Pawn ~= nil and UE.IsValid(Pawn) and Pawn:IsAlive() then
|
||
|
v:CheckHasWeapon();
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:UpdateRoundTime(InTime)
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateRoundTime] 执行,%s", tostring(InTime));
|
||
|
if InTime == nil then
|
||
|
LuaQuickFireEvent('RoundSettle', self);
|
||
|
else
|
||
|
-- 刷新时间
|
||
|
self.RoundInfo.RoundCountTime = InTime;
|
||
|
DOREPONCE(self, "RoundInfo");
|
||
|
local Time = math.floor(DefaultSettings.RoundInfo.EachRoundTime - InTime)
|
||
|
if Time == DefaultSettings.SelectWeaponShowTime then
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateRoundTime] 执行一次")
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "Client_ShowTips", "选择武器页面即将关闭,未选择则会随机选取武器");
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:Client_ShowTips(...)
|
||
|
local Params = { ... };
|
||
|
UGCLogSystem.Log("[UGCGameState:Client_ShowTips] %s", Params[1]);
|
||
|
UITool.ShowTips(...);
|
||
|
end
|
||
|
|
||
|
-- 同步回合数据
|
||
|
function UGCGameState:OnRep_RoundInfo()
|
||
|
-- 检查当前回合状态
|
||
|
if self.RoundInfo == nil then return ; end
|
||
|
-- 说明当前正在准备回合
|
||
|
if self.RoundInfo.RoundState == RoundState.Prepare then return ; end
|
||
|
if not WidgetManager:IsVisiblePanel(WidgetConfig.EUIType.Main) then
|
||
|
-- 显示这个
|
||
|
if self.RoundInfo.RoundState ~= RoundState.RoundEnd then
|
||
|
WidgetManager:ShowPanel(WidgetConfig.EUIType.Main, false);
|
||
|
-- 检查一下是否有技能
|
||
|
local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(LocalPlayerKey);
|
||
|
if PC then
|
||
|
UGCEventSystem.SetTimer(self, function()
|
||
|
PC:OnStartRound(true);
|
||
|
end, 2)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
UGCEventSystem.SendEvent(EventTypes.UpdateRound, self.RoundInfo);
|
||
|
end
|
||
|
|
||
|
function UGCGameState:StartRoundSettle(InVal)
|
||
|
UGCLogSystem.Log("[UGCGameState:StartRoundSettle] 执行");
|
||
|
if self:HasAuthority() then
|
||
|
-- 通知客户端结算当前小局
|
||
|
local PCs = UGCGameSystem.GetAllPlayerController(false);
|
||
|
for i, v in pairs(PCs) do
|
||
|
v:OnEnterRoundSettle();
|
||
|
end
|
||
|
self.RoundInfo.RoundState = RoundState.InRoundSettle;
|
||
|
UGCSendRPCSystem.ActorRPCNotify(nil, self, "StartRoundSettle", self.GameRounds);
|
||
|
DOREPONCE(self, "RoundInfo");
|
||
|
|
||
|
--self.PoisonManager:Toggle(false);
|
||
|
|
||
|
-- 检查当前是有什么
|
||
|
if DefaultSettings.RoundInfo.RoundNum <= self.RoundInfo.CurrRoundTime then
|
||
|
LuaQuickFireEvent('GameEnd', self);
|
||
|
end
|
||
|
else
|
||
|
-- 关闭观战
|
||
|
WidgetManager:ClosePanel(WidgetConfig.EUIType.Spectation);
|
||
|
-- 检查当前是谁赢了
|
||
|
if InVal == nil then return end
|
||
|
WidgetManager:ShowPanel(WidgetConfig.EUIType.RoundWin, false, InVal[#InVal]);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:UpdateRoundSettleTime(InTime)
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateRoundSettleTime] 执行")
|
||
|
if InTime == nil then
|
||
|
-- 检查当前一共有多少回合,如果超出了,则退出游戏
|
||
|
LuaQuickFireEvent('RoundStart', self);
|
||
|
else
|
||
|
DOREPONCE(self, "RoundInfo");
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- 倒计时时间
|
||
|
function UGCGameState:UpdateCountDown(InTime)
|
||
|
if self:HasAuthority() then
|
||
|
self.CountDownTime = InTime;
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateCountDown] 执行 InTime = %s", tostring(InTime));
|
||
|
if InTime <= 0 then
|
||
|
self.CountDownTime = 0;
|
||
|
LuaQuickFireEvent("RoundStart", self);
|
||
|
elseif InTime <= 1 then
|
||
|
-- 提示关闭页面
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateCountDown] 随机给予兵种类型");
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
|
||
|
if self.PlayerSoldierType[v.PlayerKey] == nil then v:RandSelectSoldierType(); end
|
||
|
end
|
||
|
elseif InTime <= 2 then
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
|
||
|
local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(v.PlayerKey);
|
||
|
if UE.IsValid(Pawn) then Pawn:K2_DestroyActor(); end
|
||
|
end
|
||
|
-- 加载
|
||
|
local PoisonActor = self:FindPoisonCircle();
|
||
|
if PoisonActor then PoisonActor:RandomSelectCenter(); end
|
||
|
elseif InTime <= DefaultSettings.SelectSoldierTime then
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateCountDown] 开始加载地图")
|
||
|
self:LoadSelectMap();
|
||
|
end
|
||
|
|
||
|
DOREPONCE(self, "CountDownTime");
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- 准备开始游戏(因为可能存在等待玩家复活等操作)
|
||
|
function UGCGameState:BeginGameStart()
|
||
|
UGCLogSystem.Log("[UGCGameState:BeginGameStart] 重置玩家");
|
||
|
if self:HasAuthority() then
|
||
|
local PCs = UGCGameSystem.GetAllPlayerController(false);
|
||
|
for i, v in pairs(PCs) do
|
||
|
if UE.IsValid(v) then v:ResetPlayer(); end
|
||
|
end
|
||
|
self:SetProcessState(EventTypes.GameProcessStates.Gaming);
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "BeginGameStart");
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:ResetGameState()
|
||
|
end
|
||
|
|
||
|
--- 设置游戏进程
|
||
|
---@param InState int32
|
||
|
function UGCGameState:SetProcessState(InState)
|
||
|
self.ProcessState = InState;
|
||
|
DOREPONCE(self, "ProcessState");
|
||
|
end
|
||
|
|
||
|
function UGCGameState:OnGameEnded(InRes)
|
||
|
UGCLogSystem.LogTree("[UGCGameState:OnGameEnded] InRes = ", InRes);
|
||
|
if self:HasAuthority() then
|
||
|
self:SetProcessState(EventTypes.GameProcessStates.Ended);
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do
|
||
|
if UE.IsValid(v) and v:IsAlive() then
|
||
|
v:K2_DestroyActor();
|
||
|
end
|
||
|
end
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "OnGameEnded", InRes);
|
||
|
else
|
||
|
WidgetManager:ClosePanel(WidgetConfig.EUIType.Main);
|
||
|
WidgetManager:ShowPanel(WidgetConfig.EUIType.Settlement, true, true);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:GetPlayerAccountInfo(InPlayerKey) return self.PlayerAccountInfoMap[InPlayerKey]; end
|
||
|
|
||
|
--- 通过玩家Key获取玩家名字
|
||
|
---@param PlayerKey PlayerKey
|
||
|
---@return string
|
||
|
function UGCGameState:GetPlayerNameByPlayerKey(PlayerKey)
|
||
|
if self.PlayerAccountInfoMap[PlayerKey] then
|
||
|
return self.PlayerAccountInfoMap[PlayerKey].PlayerName;
|
||
|
else
|
||
|
return "";
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- 通过玩家Key获取玩家 Icon Path
|
||
|
---@param PlayerKey PlayerKey
|
||
|
---@return string
|
||
|
function UGCGameState:GetHeadIconByPlayerKey(PlayerKey)
|
||
|
if self.PlayerAccountInfoMap[PlayerKey] then
|
||
|
return self.PlayerAccountInfoMap[PlayerKey].IconURL
|
||
|
else
|
||
|
return ""
|
||
|
end
|
||
|
end
|
||
|
|
||
|
------------------------------ BUFF 相关 ------------------------------
|
||
|
|
||
|
---@param InDeadKey PlayerKey 死亡玩家的PlayerKey
|
||
|
---@param InKillerKey PlayerKey 击杀者的PlayerKey
|
||
|
function UGCGameState:Multi_PlayerDead(InDeadKey, InKillerKey)
|
||
|
if InDeadKey == LocalPlayerKey then
|
||
|
WidgetManager:ShowPanel(WidgetConfig.EUIType.Spectation, false);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---@param InPlayerKey PlayerKey
|
||
|
function UGCGameState:Client_PlayerUseBuff(InPlayerKey, BuffID)
|
||
|
UGCEventSystem.SendEvent(EventTypes.TriggerSoldier, InPlayerKey);
|
||
|
end
|
||
|
|
||
|
function UGCGameState:OnRep_PlayerHasBuff()
|
||
|
end
|
||
|
|
||
|
--- 选择兵种
|
||
|
---@param InPlayerKey PlayerKey 玩家 Key
|
||
|
---@param InType int32 类型
|
||
|
function UGCGameState:Server_SelectSoldier(InPlayerKey, InType)
|
||
|
UGCLogSystem.Log("[UGCGameState:Server_SelectSoldier] 执行 PlayerKey = %s, SoldierType = %s", tostring(InPlayerKey), tostring(InType));
|
||
|
-- 所有玩家选择的兵种类型
|
||
|
self.PlayerSoldierType[InPlayerKey] = InType;
|
||
|
DOREPONCE(self, "PlayerSoldierType");
|
||
|
end
|
||
|
|
||
|
--- S
|
||
|
function UGCGameState:Server_SelectMap(InPlayerKey, InType)
|
||
|
-- 判断当前有多少人
|
||
|
self.PlayerSelectLevels[InPlayerKey] = InType;
|
||
|
local AllPlayerSelect = true;
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
|
||
|
local PlayerKey = v.PlayerKey;
|
||
|
if self.PlayerSelectLevels[PlayerKey] == nil then
|
||
|
AllPlayerSelect = false;
|
||
|
break ;
|
||
|
end
|
||
|
end
|
||
|
UGCLogSystem.LogTree(string.format("[UGCGameState:Server_SelectMap] self.PlayerSelectLevels ="), self.PlayerSelectLevels)
|
||
|
DOREPONCE(self, "PlayerSelectLevels");
|
||
|
if AllPlayerSelect then
|
||
|
-- 检测当前时间是多少
|
||
|
if self.CountDownTime > DefaultSettings.SelectSoldierTime + 2 then
|
||
|
-- 直接进入游戏
|
||
|
UGCEventSystem.SendEvent(EventTypes.AllPlayerHadSelectMap, DefaultSettings.SelectSoldierTime + 2);
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
UGCGameState.SelectMapIndex = 0;
|
||
|
|
||
|
function UGCGameState:GetSelectMap() return self.SelectMapIndex; end
|
||
|
|
||
|
-- 加载地图
|
||
|
function UGCGameState:LoadSelectMap()
|
||
|
if not UGCGameSystem.IsServer() then return ; end
|
||
|
if self.SelectMapIndex ~= 0 then return ; end
|
||
|
if DefaultSettings.EnableLevels then
|
||
|
if table.getCount(LevelTable.LevelInfo) > 2 then
|
||
|
local SelectMaps = {};
|
||
|
-- 检查有多少个 Random
|
||
|
for PlayerKey, LevelType in pairs(self.PlayerSelectLevels) do
|
||
|
if LevelType ~= LevelTable.ELevelType.Random then
|
||
|
if SelectMaps[LevelType] == nil then
|
||
|
SelectMaps[LevelType] = 1;
|
||
|
else
|
||
|
SelectMaps[LevelType] = 1 + SelectMaps[LevelType];
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
UGCLogSystem.LogTree(string.format("[UGCGameState:LoadSelectMap] SelectMaps ="), SelectMaps)
|
||
|
local MapCount = table.getCount(LevelTable.ELevelType) - 1;
|
||
|
if table.isEmpty(SelectMaps) then
|
||
|
self.SelectMapIndex = math.random(1, MapCount);
|
||
|
else
|
||
|
local MaxCount = 0;
|
||
|
for LevelType, Count in pairs(SelectMaps) do
|
||
|
if Count > MaxCount then
|
||
|
MaxCount = Count;
|
||
|
self.SelectMapIndex = LevelType;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
if self.SelectMapIndex == 0 then
|
||
|
for i, v in pairs(SelectMaps) do
|
||
|
if v >= 1 and v <= MapCount then self.SelectMapIndex = i; end
|
||
|
end
|
||
|
end
|
||
|
UGCLogSystem.Log("[UGCGameState:LoadSelectMap] 111 SelectMapIndex = %d", self.SelectMapIndex);
|
||
|
end
|
||
|
end
|
||
|
if self.SelectMapIndex <= 0 then self.SelectMapIndex = 1 end
|
||
|
if self.SelectMapIndex > table.getCount(LevelTable.ELevelType) - 1 then
|
||
|
self.SelectMapIndex = 1;
|
||
|
end
|
||
|
DOREPONCE(self, "SelectMapIndex");
|
||
|
UGCLogSystem.Log("[UGCGameState:LoadSelectMap] self.SelectMapIndex = %d", self.SelectMapIndex);
|
||
|
|
||
|
-- 加载一下地图
|
||
|
LevelStreamTool.LoadStreamLevels({ LevelTable.LevelInfo[self.SelectMapIndex].MapName }, { Object = self, Func = self.LoadMapFinish }, false);
|
||
|
end
|
||
|
|
||
|
function UGCGameState:OnRep_SelectMapIndex()
|
||
|
UGCLogSystem.Log("[UGCGameState:OnRep_SelectMapIndex] self.SelectMapIndex = %d", self.SelectMapIndex);
|
||
|
if self.SelectMapIndex > 0 then
|
||
|
-- 加载两次确保能够加载到
|
||
|
UGCLogSystem.Log("[UGCGameState:OnRep_SelectMapIndex] 开始加载 地图")
|
||
|
self:LoadNowMiniMap(self.SelectMapIndex);
|
||
|
UGCWidgetManagerSystem.ShowTipsUI(string.format("已选择 %s 地图", LevelTable.LevelInfo[self.SelectMapIndex].ShowName));
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:LoadMapFinish()
|
||
|
UGCLogSystem.Log("[UGCGameState:LoadMapFinish] 地图加载完成");
|
||
|
UGCEventSystem.SendEvent(EventTypes.MapLoadFinish)
|
||
|
end
|
||
|
|
||
|
-- 客户端执行
|
||
|
-- 加载小地图
|
||
|
function UGCGameState:LoadNowMiniMap(InType)
|
||
|
local MiniMapInfo = LevelTable.LevelInfo[InType].MiniMapInfo
|
||
|
if MiniMapInfo then
|
||
|
local bSuccess = UGCWidgetManagerSystem.ChangeMap(MiniMapInfo.MapPath, MiniMapInfo.MapCentre, MiniMapInfo.MapSize, MiniMapInfo.MapScale)
|
||
|
if bSuccess then
|
||
|
UGCLogSystem.Log("[UGCGameState:LoadNowMiniMap] 玩家加载地图成功")
|
||
|
else
|
||
|
UGCLogSystem.Log("[UGCGameState:LoadNowMiniMap] 玩家加载地图失败")
|
||
|
end
|
||
|
else
|
||
|
UGCLogSystem.Log("[UGCGameState:LoadNowMiniMap] 无法加载小地图 %s", tostring(InType));
|
||
|
end
|
||
|
UGCLogSystem.Log("[UGCGameState:LoadNowMiniMap] Finish")
|
||
|
end
|
||
|
|
||
|
-- 检查玩家是否拥有兵种类型
|
||
|
function UGCGameState:CheckPlayerHasSoldierType()
|
||
|
UGCLogSystem.Log("[UGCGameState:CheckPlayerHasWeapon] 执行")
|
||
|
local PCs = UGCGameSystem.GetAllPlayerController(false);
|
||
|
for i, v in pairs(PCs) do
|
||
|
if UE.IsValid(v) then
|
||
|
if v.SelectWeapons == nil then
|
||
|
v.SelectWeapons = {};
|
||
|
end
|
||
|
if table.isEmpty(v.SelectWeapons) == 0 then
|
||
|
-- 说明没有选择武器
|
||
|
-- 查看当前选择的兵种
|
||
|
local SoldierType = self.PlayerSoldierType[v.PlayerKey];
|
||
|
if SoldierType == nil then
|
||
|
self.PlayerSoldierType[v.PlayerKey] = math.random(1, table.getCount(SoldierConfig.ESoldierType));
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:LogoutPlayer(InPlayerKey)
|
||
|
-- 判断当前是否只有一队玩家了,如果只剩一队玩家那么直接获胜
|
||
|
local AllPlayerKeys = {};
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
|
||
|
table.insert(AllPlayerKeys, v.PlayerKey);
|
||
|
end
|
||
|
|
||
|
self:UpdateAlivePlayer(InPlayerKey, false, nil);
|
||
|
return table.getCount(AllPlayerKeys);
|
||
|
end
|
||
|
|
||
|
---@param InPlayerKey PlayerKey 造成伤害的玩家Key
|
||
|
---@param InDamage float 造成多少伤害
|
||
|
function UGCGameState:UpdateDamage(InPlayerKey, InDamage)
|
||
|
self.PlayerDamage[InPlayerKey] = (self.PlayerDamage[InPlayerKey] or 0) + InDamage;
|
||
|
DOREPONCE(self, "PlayerDamage");
|
||
|
end
|
||
|
|
||
|
function UGCGameState:UpdateScore(InKey, InType, InScore)
|
||
|
if self.PlayerScores[InKey] == nil then self.PlayerScores[InKey] = {}; end
|
||
|
if self.PlayerScores[InKey][InType] == nil then self.PlayerScores[InKey][InType] = 0; end
|
||
|
self.PlayerScores[InKey][InType] = self.PlayerScores[InKey][InType] + InScore;
|
||
|
|
||
|
-- 加载到表中
|
||
|
table.addTableNum(self.PlayerArchives[InKey], InType, InScore);
|
||
|
DOREPONCE(self, "PlayerScores");
|
||
|
end
|
||
|
|
||
|
--- 判断是否仅剩一个队伍
|
||
|
function UGCGameState:IsOneTeamAllDead(InDeadPlayerKey)
|
||
|
local AliveTeamIds = {};
|
||
|
-- 检查这个队伍是否还有人
|
||
|
local DeadTeamId = UGCPlayerStateSystem.GetTeamID(InDeadPlayerKey);
|
||
|
local PlayerList = UGCTeamSystem.GetPlayerKeysByTeamID(DeadTeamId);
|
||
|
UGCLogSystem.Log("[UGCGameState:IsOneTeamAllDead] DeadTeamId = %d", DeadTeamId);
|
||
|
UGCLogSystem.LogTree(string.format("[UGCGameState:IsOneTeamAllDead] PlayerList ="), PlayerList)
|
||
|
for i, v in pairs(PlayerList) do
|
||
|
local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(v)
|
||
|
if Pawn ~= nil and UE.IsValid(Pawn) and Pawn:IsAlive() then return false; end
|
||
|
end
|
||
|
UGCLogSystem.Log("[UGCGameState:IsOneTeamAllDead] 所有玩家都死亡了");
|
||
|
return true;
|
||
|
end
|
||
|
|
||
|
---@param InPlayerKey PlayerKey
|
||
|
---@param InIsAlive bool 玩家是否存活
|
||
|
function UGCGameState:UpdateAlivePlayer(InPlayerKey, InIsAlive, InKillerPlayerKey)
|
||
|
-- 当玩家死亡的时候:
|
||
|
UGCLogSystem.LogTree(string.format("[UGCGameState:UpdateAlivePlayer] self.PlayerTeams ="), self.PlayerTeams)
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateAlivePlayer] InKillerPlayerKey = %s", tostring(InKillerPlayerKey));
|
||
|
|
||
|
local IsOne = self:IsOneTeamAllDead(InPlayerKey);
|
||
|
if IsOne then
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateAlivePlayer] 仅剩一支队伍");
|
||
|
end
|
||
|
if not IsOne then return ; end
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateAlivePlayer] 执行")
|
||
|
if self.RoundInfo.RoundState == RoundState.InRound then
|
||
|
-- 检查一下有几支队伍,如果只有一对,那么直接获胜
|
||
|
-- 找到 WinnerId
|
||
|
local WinTeamId = nil;
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateAlivePlayer] InKillerPlayerKey = %s", tostring(InKillerPlayerKey));
|
||
|
if InKillerPlayerKey ~= nil and InKillerPlayerKey > 0 then
|
||
|
WinTeamId = UGCPlayerControllerSystem.GetTeamID(UGCGameSystem.GetPlayerControllerByPlayerKey(InKillerPlayerKey));
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateAlivePlayer] 开始查找 WinTeamId = %s", tostring(WinTeamId));
|
||
|
else
|
||
|
-- 获取还有谁,那么他们队伍获胜了
|
||
|
local AllPlayerPawn = {};
|
||
|
for i, Pawn in pairs(UGCGameSystem.GetAllPlayerPawn()) do
|
||
|
if Pawn ~= nil and UE.IsValid(Pawn) and Pawn:IsAlive() then
|
||
|
AllPlayerPawn[UGCPlayerStateSystem.GetTeamID(Pawn.PlayerKey)] = true;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- 保证可以执行
|
||
|
if table.getCount(AllPlayerPawn) == 1 then
|
||
|
for i, v in pairs(AllPlayerPawn) do WinTeamId = i; end
|
||
|
end
|
||
|
end
|
||
|
UGCLogSystem.Log("[UGCGameState:UpdateAlivePlayer] WinTeamId = %d", WinTeamId);
|
||
|
if WinTeamId ~= nil then
|
||
|
table.insert(self.GameRounds, WinTeamId);
|
||
|
DOREPONCE(self, "GameRounds");
|
||
|
end
|
||
|
-- 发一个 RPC
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "UpdateGameRounds", self.GameRounds);
|
||
|
if self.PlayerTeams[WinTeamId] ~= nil then
|
||
|
for i, v in pairs(self.PlayerTeams[WinTeamId]) do
|
||
|
self:UpdateScore(v, SoldierConfig.TechnologyType.RoundWin, 1);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if self:CheckGameRounds(WinTeamId) then return ; end
|
||
|
end
|
||
|
--- 如果没有结束游戏,则进入结算部分
|
||
|
self:UpdateRoundTime();
|
||
|
end
|
||
|
|
||
|
function UGCGameState:UpdateGameRounds(InRoundsInfo)
|
||
|
--获取一下
|
||
|
UGCLogSystem.LogTree(string.format("[UGCGameState:UpdateGameRounds] InRoundsInfo ="), InRoundsInfo)
|
||
|
-- 同步过去
|
||
|
self.CachedGameRounds = InRoundsInfo;
|
||
|
UGCEventSystem.SendEvent(EventTypes.UpdateGameRound, self.CachedGameRounds);
|
||
|
end
|
||
|
|
||
|
--- 检查游戏是否结束了,当一个队伍胜利太多就会赢取游戏
|
||
|
---@return bool 当前游戏是否已经结束了
|
||
|
function UGCGameState:CheckGameRounds(InId)
|
||
|
--- 先检查当前哪边赢得多,如果现在只剩下一方的人,那么这一方直接就获取胜利
|
||
|
local IsAloneTeam, WinTeamId = self:CheckExistPlayers();
|
||
|
if IsAloneTeam then
|
||
|
self:GotoGameEnd(InId);
|
||
|
return true;
|
||
|
end
|
||
|
|
||
|
local TeamCount = {};
|
||
|
for i, v in pairs(self.GameRounds) do
|
||
|
if TeamCount[v] == nil then
|
||
|
TeamCount[v] = 1;
|
||
|
else
|
||
|
TeamCount[v] = 1 + TeamCount[v];
|
||
|
end
|
||
|
end
|
||
|
for i, v in pairs(TeamCount) do
|
||
|
if v >= 4 or IsAloneTeam then
|
||
|
-- 说明当前可以执行
|
||
|
self:GotoGameEnd(i);
|
||
|
return true;
|
||
|
end
|
||
|
end
|
||
|
return false;
|
||
|
end
|
||
|
|
||
|
function UGCGameState:GotoGameEnd(InWinTeamId)
|
||
|
self.WinTeamId = InWinTeamId;
|
||
|
self.RoundInfo.RoundState = RoundState.RoundEnd;
|
||
|
-- 再一段时间后再执行
|
||
|
UGCEventSystem.SetTimer(self, function()
|
||
|
LuaQuickFireEvent("GameEnd", self)
|
||
|
end, DefaultSettings.RoundInfo.RoundSettleTime / 2);
|
||
|
-- 客户端显示出来
|
||
|
self:ClientShowUI(WidgetConfig.EUIType.RoundWin, self.WinTeamId)
|
||
|
DOREPONCE(self, "WinTeamId");
|
||
|
end
|
||
|
|
||
|
--- 检查存在的玩家
|
||
|
function UGCGameState:CheckExistPlayers()
|
||
|
local AllTeams = {};
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
|
||
|
local TeamId = UGCPlayerControllerSystem.GetTeamID(v)
|
||
|
if AllTeams[TeamId] == nil then AllTeams[TeamId] = {}; end
|
||
|
table.insert(AllTeams[TeamId], v.PlayerKey);
|
||
|
end
|
||
|
UGCLogSystem.LogTree(string.format("[UGCGameState:CheckExistPlayers] AllTeams ="), AllTeams)
|
||
|
if table.getCount(AllTeams) == 1 then
|
||
|
for i, v in pairs(AllTeams) do return true, i; end
|
||
|
end
|
||
|
return false;
|
||
|
end
|
||
|
|
||
|
function UGCGameState:ClientShowUI(UIType, ...)
|
||
|
if self:HasAuthority() then
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "ClientShowUI", UIType, ...);
|
||
|
else
|
||
|
WidgetManager:ShowPanel(UIType, false, ...)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- 获取本队之外的其他队的队伍ID
|
||
|
function UGCGameState:GetOtherTeamId(InTeamId)
|
||
|
for TeamId, v in pairs(self.PlayerTeams) do
|
||
|
if InTeamId ~= TeamId and TeamId ~= -1 then return TeamId; end
|
||
|
end
|
||
|
return -1;
|
||
|
end
|
||
|
|
||
|
function UGCGameState:CheckPlayerTeams()
|
||
|
self.PlayerTeams = {};
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
|
||
|
local TeamID = UGCPlayerControllerSystem.GetTeamID(v);
|
||
|
if self.PlayerTeams[TeamID] == nil then self.PlayerTeams[TeamID] = {}; end
|
||
|
table.insert(self.PlayerTeams[TeamID], v.PlayerKey);
|
||
|
end
|
||
|
DOREPONCE(self, "PlayerTeams");
|
||
|
end
|
||
|
|
||
|
---@param InTeamId TeamId|PlayerKey
|
||
|
function UGCGameState:GetOtherPlayerKeys(InTeamId)
|
||
|
if InTeamId < 1000 then
|
||
|
return self.PlayerTeams[self:GetOtherTeamId(InTeamId)];
|
||
|
end
|
||
|
local TeamId = self:GetPlayerTeamId(InTeamId);
|
||
|
return self:GetOtherPlayerKeys(TeamId);
|
||
|
end
|
||
|
|
||
|
--- 获取队伍的分数
|
||
|
---@param InTeamId int32 队伍Id
|
||
|
function UGCGameState:GetTeamScore(InTeamId)
|
||
|
local Score = 0;
|
||
|
for _, v in pairs(self.GameRounds) do
|
||
|
if v == InTeamId then Score = Score + 1; end
|
||
|
end
|
||
|
return Score;
|
||
|
end
|
||
|
|
||
|
---@param InTeamId TeamId 队伍Id
|
||
|
function UGCGameState:GetOtherTeamScore(InTeamId)
|
||
|
return table.getCount(self.GameRounds) - self:GetTeamScore(InTeamId);
|
||
|
end
|
||
|
|
||
|
--- S & C
|
||
|
---@return table<int32, table<int32, PlayerDamageItem>>
|
||
|
function UGCGameState:GetPlayerRank()
|
||
|
-- 区分一下左队右队
|
||
|
local TeamData = {};
|
||
|
for PlayerKey, Damage in pairs(self.PlayerDamage) do
|
||
|
local Info = self.TotalPlayerKDA[PlayerKey];
|
||
|
table.insert(TeamData, {
|
||
|
PlayerKey = PlayerKey,
|
||
|
Damage = Damage,
|
||
|
KDA = (Info.Kill + Info.Assist) / (Info.Dead == 0 and 1 or Info.Dead),
|
||
|
TeamId = self.PlayerAccountInfoMap[PlayerKey].TeamID,
|
||
|
});
|
||
|
end
|
||
|
table.sort(TeamData, function(a, b)
|
||
|
if a.KDA == b.KDA then return a.Damage > b.Damage; end
|
||
|
return a.KDA > b.KDA;
|
||
|
end);
|
||
|
UGCLogSystem.LogTree(string.format("[UGCGameState:GetPlayerRank] TeamData ="), TeamData)
|
||
|
return TeamData;
|
||
|
end
|
||
|
|
||
|
---@param InPlayerKey PlayerKey
|
||
|
function UGCGameState:GetPlayerTeamId(InPlayerKey)
|
||
|
return self.PlayerAccountInfoMap[InPlayerKey].TeamID;
|
||
|
end
|
||
|
|
||
|
--- 获取玩家当前在队伍中的排名,此时按照伤害进行排名
|
||
|
---@param InPlayerKey PlayerKey
|
||
|
---@return int32 Rank Num
|
||
|
function UGCGameState:GetPlayerRankByPlayerKey(InPlayerKey)
|
||
|
-- 对玩家进行排序
|
||
|
local PlayerDamages = self:GetPlayerRank();
|
||
|
local TeamId = self:GetPlayerTeamId(InPlayerKey);
|
||
|
for i, v in pairs(PlayerDamages[TeamId]) do
|
||
|
if v.PlayerKey == InPlayerKey then return i; end
|
||
|
end
|
||
|
return -1;
|
||
|
end
|
||
|
|
||
|
---@param InPlayerKey PlayerKey
|
||
|
---@return int32
|
||
|
function UGCGameState:GetPlayerDamageByPlayerKey(InPlayerKey)
|
||
|
for Index, Table in pairs(self.PlayerDamage) do
|
||
|
if Table.PlayerKey == InPlayerKey then return math.floor(Table.Damage); end
|
||
|
end
|
||
|
return 0.;
|
||
|
end
|
||
|
|
||
|
---@param InTeamId int
|
||
|
function UGCGameState:GetOtherTeamId(InTeamId)
|
||
|
if InTeamId == nil then return -1; end
|
||
|
for TeamId, PlayerList in pairs(self.PlayerTeams) do
|
||
|
if TeamId ~= InTeamId then return TeamId; end
|
||
|
end
|
||
|
return -1;
|
||
|
end
|
||
|
|
||
|
---@param InPlayerKey PlayerKey
|
||
|
function UGCGameState:GetOtherTeamIdByPlayerKey(InPlayerKey)
|
||
|
return self:GetOtherTeamId(self:GetPlayerTeamId(InPlayerKey));
|
||
|
end
|
||
|
|
||
|
--- 玩家当前获取的分数
|
||
|
---@param InPlayerKey PlayerKey
|
||
|
---@return int32 获取分数
|
||
|
function UGCGameState:GetScoreDataByPlayerKey(InPlayerKey)
|
||
|
local Score = self.PlayerScores[InPlayerKey];
|
||
|
local TotalScore = 0;
|
||
|
for i, v in pairs(Score) do TotalScore = TotalScore + v; end
|
||
|
return TotalScore;
|
||
|
end
|
||
|
|
||
|
--- 获取玩家的兵种类型
|
||
|
---@param InPlayerKey PlayerKey
|
||
|
function UGCGameState:GetSoldierTypeByPlayerKey(InPlayerKey)
|
||
|
return self.PlayerSoldierType[InPlayerKey];
|
||
|
end
|
||
|
|
||
|
-- 验证一下两个 ID 是否正常
|
||
|
function UGCGameState:CheckLocalTeamIds()
|
||
|
if DefaultSettings.LocalTeamId == -1 and DefaultSettings.EnemyTeamId == -1 then
|
||
|
DefaultSettings.LocalTeamId = self:GetPlayerTeamId(LocalPlayerKey);
|
||
|
end
|
||
|
if DefaultSettings.LocalTeamId == -1 then end
|
||
|
end
|
||
|
|
||
|
--- S & C
|
||
|
function UGCGameState:AllPlayerReady()
|
||
|
local BuffManager = BP_BuffManager.GetBuffManager();
|
||
|
BuffManager:Init()
|
||
|
end
|
||
|
|
||
|
---@param Enable bool
|
||
|
---@param TeamId TeamId
|
||
|
---@param BuffType EBuffType
|
||
|
function UGCGameState:ApplyShowEnemyPos(Enable, TeamId, BuffType)
|
||
|
local ShowTable = self.CachedInit[BuffType];
|
||
|
if table.isEmpty(ShowTable) then
|
||
|
if not self:LoadCachedInit(BuffType) then return ; end
|
||
|
ShowTable = self.CachedInit[BuffType];
|
||
|
end
|
||
|
if DefaultSettings.LocalTeamId ~= TeamId then
|
||
|
self:HideEnemyPos(BuffType);
|
||
|
return ;
|
||
|
end
|
||
|
|
||
|
if BuffType ~= nil then
|
||
|
local OtherTeamPlayers = self:GetOtherPlayerKeys(TeamId);
|
||
|
if table.isEmpty(OtherTeamPlayers) then return end
|
||
|
for i = 1, #OtherTeamPlayers do
|
||
|
UGCLogSystem.Log("[UGCGameState:ApplyShowEnemyPos] ActorName = %s", UE.GetName(ShowTable[i]));
|
||
|
ShowTable[i]:SetTrackPlayerKey(Enable and OtherTeamPlayers[i] or nil);
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:LoadCachedInit(InBuffType)
|
||
|
local BuffManager = BP_BuffManager.GetBuffManager()
|
||
|
BuffManager:Init();
|
||
|
if table.isEmpty(self.CachedInit[InBuffType]) then
|
||
|
UGCLogSystem.LogError("[UGCGameState:LoadCachedInit] 当前表中还是没有数据,请检查 BuffType = %s", tostring(InBuffType));
|
||
|
return false;
|
||
|
end
|
||
|
return true;
|
||
|
end
|
||
|
|
||
|
function UGCGameState:HideEnemyPos(BuffType)
|
||
|
UGCLogSystem.Log("[UGCGameState:HideEnemyPos] 隐藏起来敌方玩家");
|
||
|
local ShowTable = self.CachedInit[BuffType];
|
||
|
if table.isEmpty(ShowTable) then
|
||
|
return ;
|
||
|
end
|
||
|
for i = 1, #ShowTable do
|
||
|
ShowTable[i]:SetTrackPlayerKey(nil);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:SendSoldierRPC(IsMulti, FuncName, InPlayerKey, InSoldierType, ...)
|
||
|
if self:HasAuthority() then
|
||
|
if IsMulti then
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "SendSoldierRPC", IsMulti, FuncName, InPlayerKey, InSoldierType, ...)
|
||
|
else
|
||
|
local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(InPlayerKey);
|
||
|
UnrealNetwork.CallUnrealRPC(PC, self, "SendSoldierRPC", IsMulti, FuncName, InPlayerKey, InSoldierType, ...);
|
||
|
end
|
||
|
else
|
||
|
UGCLogSystem.Log("[UGCGameState:SendSoldierRPC] %s 执行客户端逻辑:%s", tostring(InPlayerKey), FuncName)
|
||
|
if InPlayerKey == LocalPlayerKey then
|
||
|
-- 进行处理
|
||
|
if LocalPlayerController ~= nil then
|
||
|
local SoldierBase = LocalPlayerController:GetSoldierBase(InSoldierType)
|
||
|
if SoldierBase == nil then
|
||
|
-- 创建一个
|
||
|
SoldierBase = LocalPlayerController:AddSoldierBase(InSoldierType);
|
||
|
end
|
||
|
SoldierBase[FuncName](SoldierBase, ...);
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UGCGameState:ClientSendEvent(InPlayerKey, InEvent, ...)
|
||
|
if self:HasAuthority() then
|
||
|
if InPlayerKey == nil then
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "ClientSendEvent", InEvent, ...);
|
||
|
else
|
||
|
local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(InPlayerKey);
|
||
|
UnrealNetwork.CallUnrealRPC(PC, UGCGameSystem.GameState, "ClientSendEvent", InEvent, ...);
|
||
|
end
|
||
|
else
|
||
|
UGCEventSystem.SendEvent(InPlayerKey, InEvent, ...);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---@param IsSend bool 是否是自己发送的
|
||
|
function UGCGameState:SendEvent(IsSend, InPlayerKey, InEvent, ...)
|
||
|
if self:HasAuthority() then
|
||
|
-- 检测是否存在 PlayerKey
|
||
|
if IsSend then
|
||
|
if InPlayerKey == nil then
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "SendEvent", false, nil, InEvent, ...);
|
||
|
else
|
||
|
local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(InPlayerKey);
|
||
|
if UE.IsValid(PC) then
|
||
|
UnrealNetwork.CallUnrealRPC(PC, UGCGameSystem.GameState, "SendEvent", false, InPlayerKey, InEvent, ...);
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
-- 那么就是接受过来的
|
||
|
UGCEventSystem.SendEvent(InEvent, InPlayerKey, ...)
|
||
|
end
|
||
|
else
|
||
|
-- 从客户端发送出去
|
||
|
if IsSend then
|
||
|
UnrealNetwork.CallUnrealRPC(LocalPlayerController, UGCGameSystem.GameState, "SendEvent", false, LocalPlayerKey, InEvent, ...);
|
||
|
else
|
||
|
UGCEventSystem.SendEvent(InEvent, InPlayerKey, ...);
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
UGCGameState.PlayerUseBuffs = {};
|
||
|
|
||
|
function UGCGameState:OnPlayerUseBuff(InPlayerKey, InBuffType, InBuffInfo, InServerTime)
|
||
|
local TeamId = self:GetPlayerTeamId(InPlayerKey);
|
||
|
if TeamId == DefaultSettings.LocalTeamId then
|
||
|
local Name = self:GetPlayerNameByPlayerKey(InPlayerKey);
|
||
|
|
||
|
UGCLogSystem.Log("[UGCGameState:OnPlayerUseBuff] Name = %s", Name)
|
||
|
if self.PlayerUseBuffs[InServerTime] == nil then
|
||
|
self.PlayerUseBuffs[InServerTime] = InPlayerKey;
|
||
|
UGCWidgetManagerSystem.ShowTipsUI(string.format('%s 启动了技能:%s', Name, BuffConfig.BuffInfo[InBuffType].Desc));
|
||
|
end
|
||
|
end
|
||
|
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
|
||
|
|
||
|
--- 配置并启动毒圈
|
||
|
---@param InConfigIndex int32 毒圈配置
|
||
|
function UGCGameState:StartPoison(InConfigIndex)
|
||
|
UGCLogSystem.Log("[UGCGameState:StartPoison] 执行")
|
||
|
local PoisonActor = self:FindPoisonCircle();
|
||
|
if PoisonActor then
|
||
|
PoisonActor:SetConfigIndex(InConfigIndex);
|
||
|
PoisonActor:StartPoison();
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return UGCGameState;
|