UGCProjects/InfFire/Script/Blueprint/Mini/MiniGameManager.lua
2025-01-04 23:00:19 +08:00

901 lines
30 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---@type FMiniGameManager
MiniGameManager = {};
---@private string 这是玩家选择的地图,按从前往后开始游玩
MiniGameManager.ScriptPath = "Script.Blueprint.Mini.Script.Mini_";
---@type table<int32, FMiniGameMapIndex> 当前所有玩家选择的地图
MiniGameManager.SelectMaps = {};
---@type FMiniGameMapIndex 当前选择的地图
MiniGameManager.CurrSelectMap = nil;
---@type UGCGameState_C 默认是 GameSate如果不是可以在具体实例里面实现对应方法
MiniGameManager.Owner = nil;
---@type table<any> 游戏配置,对应着 MiniGameConfig[self.CurrSelectMap]
MiniGameManager.GameConfig = nil;
---@type MiniGameMode 当前小玩法的具体实现,统一入口出口管理
MiniGameManager.CurrMiniMode = nil;
---@type int32 目标小游戏数量,低于这个数量会自动添加到这个数量
MiniGameManager.TargetMiniGameCount = 1;
MiniGameManager.State = 0;
---@type table<int32, any> 小游戏需要同步的数据,会自动执行 OnRep_xxx 函数
MiniGameManager.MiniInfo = {};
----------------------------------- 主要函数 -----------------------------------
--- 这是游戏启动,做一些初始化的操作即可
function MiniGameManager:ReceiveBeginPlay(InOwner)
UGCLogSystem.Log("[MiniGameManager:ReceiveBeginPlay] 执行成功 self = %s", tostring(self));
self.Owner = InOwner;
self.GameConfig = require('Script.Blueprint.Mini.MiniGameConfig')
GlobalTickTool:AddTick(self, self.OnTick);
UGCEventSystem.AddListener(EventTypes.ClientAlready, self.OnClientAlready, self)
if IsServer then
self:SetState(MiniGameState.SELECT_GAMES);
self:HandleAddTick(self:GetCurrStateTotalTime(), self.OnGameStart);
else
-- 执行客户端逻辑
self:MakeCachedMiniInfo();
end
-- 组装一下具体函数
self:MakeRepProps();
end
function MiniGameManager:OnTick(InDeltaTime, InServerTime)
end
function MiniGameManager:MakeRepProps()
local Func = function(...) return { ... }; end
local Props = Func(self:GetReplicatedProperties());
if self.Props == nil then self.Props = {}; end
for i, v in pairs(Props) do self.Props[v] = true; end
UGCLogSystem.LogTree(string.format("[MiniGameManager:MakeRepProps] self.Props ="), self.Props);
end
function MiniGameManager:IsRepProp(InName)
return self.Props[InName] == true;
end
--- 本身需要同步的数据放进来
function MiniGameManager:GetReplicatedProperties()
return "State"
, "SelectMaps"
, "CurrSelectMap"
, "TeamPlayerKeys"
end
--- 客户端准备好了,此时开始有 ServerTime
function MiniGameManager:OnClientAlready()
-- 显示
if IsClient then
UGCLogSystem.Log("[MiniGameManager:OnGameBegin] 显示 UI")
end
end
--- 可以改变任意时刻的时间
function MiniGameManager:ChangeTime(InTime)
GlobalTickTool:UpdateInternalCount(self, InTime);
end
--- 准备结束
function MiniGameManager:OnPrepareEnd()
if IsServer then
self:SetMiniInfo();
end
self:DoMiniFunc("OnPrepareEnd")
self:OnMiniRoundPrepare();
end
function MiniGameManager:SendRPC(InRPCName, ...)
UGCLogSystem.Log("[MiniGameManager:SendRPC] InRPCName = %s", InRPCName);
self.Owner:SendMiniGameRPC(InRPCName, ...);
end
--- 当游戏激活之时
function MiniGameManager:OnGameActive()
-- 这个函数几乎是紧挨着 ReceiveBeginPlay 之后执行
end
--- 在游戏进行之前执行
---@param InTime int32 从游戏开始到游戏正式开始的倒计时
function MiniGameManager:OnBeforeGameStart(InTime)
UGCLogSystem.Log("[MiniGameManager:OnBeforeGameStart] InTime = %s", tostring(InTime));
if InTime == 3 then
-- 玩家死亡重生
-- 移除所有的东西
UE.ForeachAllPawns(function(Pawn)
ItemTool.ClearAllItems(Pawn);
end)
GameState:BeforeReset(2);
end
end
--- 游戏正式开始
function MiniGameManager:OnGameStart()
UGCLogSystem.Log("[MiniGameManager:OnGameStart] 执行")
if IsServer then
-- 检查当前选择的地图是否小于对应数量,如果小于,那么就随机选择为选择的
-- 获取选择了的
if table.getCount(MiniGameConfig) == 1 then
for i, v in pairs(MiniGameConfig) do
table.insert(self.SelectMaps, i);
end
else
local SortTable = self.Owner:SortMapData();
for i, v in pairs(SortTable) do table.insert(self.SelectMaps, v.Index); end
end
local NeedCount = self.TargetMiniGameCount - table.getCount(self.SelectMaps);
if NeedCount > 0 then
for i = 1, NeedCount do table.insert(self.SelectMaps, math.random(table.getCount(MiniGameConfig))) end
end
UGCLogSystem.LogTree(string.format("[MiniGameManager:OnGameStart] self.SelectMaps ="), self.SelectMaps)
-- 表示如果第一个加载不成,那么就依次完后加载,直到全部加载都不行
local bSuccess = false;
repeat bSuccess = self:LoadMiniGame() until bSuccess or table.isEmpty(self.SelectMaps);
if not bSuccess then self:OnGameEnd(); end
else
WidgetManager:ClosePanel(WidgetConfig.EUIType.SelectMap);
WidgetManager:ShowPanel(WidgetConfig.EUIType.Main, false);
end
end
function MiniGameManager:OnClientAlready()
self:DoMiniFunc("OnClientAlready");
end
function MiniGameManager:OnGameEnd()
UGCLogSystem.Log("[MiniGameManager:OnGameEnd] 游戏结束")
if IsServer then
self:SetState(MiniGameState.ENDED);
LuaQuickFireEvent("GameEnd", self.Owner);
else
-- 显示结算界面
WidgetManager:ShowPanel(WidgetConfig.EUIType.GameEnd, false);
end
end
---@param InMiniType MiniGameMapType Mini 游戏类型,只会在客户端存在
function MiniGameManager:LoadMiniGame(InMiniType)
if IsServer then
self:SetState(MiniGameState.MINI_PREPARE);
self:AllPlayerDead();
UGCLogSystem.Log("[MiniGameManager:LoadMiniGame] 执行")
if table.isEmpty(self.SelectMaps) then return false; end
UGCLogSystem.Log("[MiniGameManager:LoadMiniGame] 开始执行流程")
self.CurrSelectMap = self.SelectMaps[1];
if self.CurrSelectMap == nil then return false; end
table.remove(self.SelectMaps, 1);
-- 加载 CurrMiniMode
UGCLogSystem.Log("[MiniGameManager:LoadMiniGame] 加载 Mini Mode")
if not self:DoMiniFunc("Init", self) then return false; end
self:LoadMap(self.CurrSelectMap);
-- 发送到客户端表示当前已经同步了
self.Owner:SelectMiniType(self.CurrSelectMap); -- 这样写是确保一定可以执行成功
UGCLogSystem.Log("[MiniGameManager:LoadMiniGame] Mini Mode 加载成功")
self:CurrMiniModeInit();
if not table.hasFunc(self.CurrMiniMode, "DOREPONCE") then
self.CurrMiniMode["DOREPONCE"] = function(o, Name)
o.Owner:SetGameInfo(Name, o[Name]);
end
end
if self.CurrMiniMode.RoundTimes == nil then self.CurrMiniMode.RoundTimes = 1; end
self:SetRoundTimes(self.CurrMiniMode.RoundTimes);
UGCLogSystem.Log("[MiniGameManager:LoadMiniGame] Time = %s", tostring(Time))
self:HandleAddTick(self:GetCurrStateTotalTime(), self.OnPrepareEnd);
UGCLogSystem.Log("[MiniGameManager:LoadMiniGame] 全部加载完成")
return true;
else
UGCLogSystem.Log("[MiniGameManager:LoadMiniGame] 客户端加载")
self.CurrSelectMap = InMiniType;
self:DoMiniFunc("Init", self);
self:CurrMiniModeInit();
end
end
--- 服务器客户端初始化的共同操作
function MiniGameManager:CurrMiniModeInit()
--- 默认设置一些变量供使用或者驱动
self.CurrMiniMode.Owner = self;
self.CurrMiniMode.MapIndex = self.CurrSelectMap;
self.CurrMiniMode.CreateTime = UE.GetServerTime();
self.CurrMiniMode.bGameEnd = false;
self.CurrMiniMode.bRoundEnd = false;
self.CurrMiniMode.RoundTimes = self.GameConfig[self.CurrSelectMap].RoundTimes; -- 当前回合数
self.CurrMiniMode.TotalRoundTimes = self.GameConfig[self.CurrSelectMap].RoundTimes; -- 总回合数
self.CurrMiniMode.bCanRespawn = self.GameConfig[self.CurrSelectMap].bCanRespawn; -- 是否可以重生
GlobalMiniMode = self.CurrMiniMode;
for i, v in pairs(self.MiniInfo) do
if type(v) == 'table' then
self.CurrMiniMode[i] = TableHelper.DeepCopyTable(v);
else
self.CurrMiniMode[i] = v;
end
end
UGCLogSystem.Log("[MiniGameManager:CurrMiniModeInit] 开始加载地图")
-- 加载 Tick
GlobalTickTool:AddTick(self.CurrMiniMode, self.CurrMiniMode.OnTick, nil, function(o)
return not (o.bEnableTick == false);
end);
-- 进入准备
self:DoMiniFunc("OnPrepare");
end
--- 处理 Tick
function MiniGameManager:HandleAddTick(InTime, lf, InFunc, ...)
local Time = math.abs(InTime);
GlobalTickTool:AddInternalCount(self, function(o, dt, st, t)
-- 如果 InTime < 0
if InTime > 0 then t = InTime - t; end
o:OnMiniGameTimeCount(t, Time);
if InFunc then InFunc(o, dt, st, t); end
end, 1, Time, lf, ...);
end
function MiniGameManager:UnLoadMiniGame()
-- 先取消上一个的
if IsServer then
if self.CurrMiniMode ~= nil then
GlobalTickTool:RemoveTick(self.CurrMiniMode);
-- 然后赶紧除去地图并且加载
self:UnLoadMap();
end
end
end
function MiniGameManager:OnMiniGameTimeCount(InVal, InTotal)
if IsServer then
InVal = math.floor(InVal);
--- 执行
self.Owner:OnGameProgress_Tick(InVal);
else
if InTotal == nil then InTotal = self:GetCurrStateTotalTime() end
end
self:DoMiniFunc("OnTimeCountDown", InVal, InTotal);
end
function MiniGameManager:OnMiniGameEnd()
UGCLogSystem.Log("[MiniGameManager:OnMiniGameEnd] ")
self:SetState(MiniGameState.MINI_END);
-- 从小局中取出来
self.MiniInfo.Scores = self:DoMiniFunc("GetScore")
self:DoMiniFunc("OnGameEnd", self.MiniInfo.Scores);
self:SetMiniInfo();
self:HandleAddTick(self:GetCurrStateTotalTime(), self.OnMiniGameSwitch)
end
--- 切换到下一个 MiniGame
function MiniGameManager:OnMiniGameSwitch()
-- 检查是否还有下一个了
if table.isEmpty(self.SelectMaps) then
self:OnGameEnd();
return ;
end
self:UnLoadMiniGame();
self:LoadMiniGame();
end
function MiniGameManager:SetState(InState)
if IsServer then
self.State = InState;
self.MiniInfo.State = InState;
UGCLogSystem.Log("[MiniGameManager:SetState] CurrState = %s", TableHelper.printEnum(MiniGameState, self.State));
self:SetMiniInfo();
if self.CurrMiniMode ~= nil then
self.CurrMiniMode.State = InState;
end
if self.GameConfig then
self:DoMiniFunc('SetState', InState)
end
end
end
function MiniGameManager:SetRoundTimes(InTimes)
if IsServer then
self.MiniInfo.RoundTimes = InTimes;
self:SetMiniInfo();
if self.CurrMiniMode ~= nil then
self.CurrMiniMode.RoundTimes = InTimes;
end
end
end
function MiniGameManager:OnRep_RoundTimes(InOld)
if self.CurrMiniMode ~= nil then
self.CurrMiniMode.RoundTimes = self.MiniInfo.RoundTimes;
end
end
function MiniGameManager:OnRep_State(InOld)
UGCLogSystem.Log("[MiniGameManager:OnRep_State] self.State = %s, StateName = %s", tostring(self.MiniInfo.State), TableHelper.printEnum(MiniGameState, self.State));
self.State = self.MiniInfo.State;
UGCEventSystem.SendEvent(EventTypes.MiniStateChange, self.State);
if self.State == MiniGameState.MINI_PREPARE then
elseif self.State == MiniGameState.ROUND_PREPARE then
self:OnPrepareEnd();
elseif self.State == MiniGameState.ROUND_GAMING then
self:OnMiniRoundFormalStart();
elseif self.State == MiniGameState.ROUND_END then
self:OnMiniRoundEnd();
elseif self.State == MiniGameState.MINI_END then
self:OnMiniGameEnd();
elseif self.State == MiniGameState.ENDED then
self:OnGameEnd();
end
end
--- 设置同步 MiniInfo,
function MiniGameManager:SetMiniInfo()
self.Owner:SetMiniInfo(self.MiniInfo);
end
--- 设置游戏数据
---@vararg
function MiniGameManager:SetGameInfo(InName, InInfo)
--UGCLogSystem.LogTree(string.format("[MiniGameManager:SetGameInfo] InInfo ="), InInfo)
if type(InInfo) == 'table' then
self.MiniInfo[InName] = TableHelper.DeepCopyTable(InInfo);
else
self.MiniInfo[InName] = InInfo;
end
self:SetMiniInfo();
end
-- 给予子模块的数据同步
function MiniGameManager:DOREPONCE(Name)
if self.CurrMiniMode then
self:SetGameInfo(Name, self.CurrMiniMode[Name]);
end
end
function MiniGameManager:DoMiniFunc(InName, ...)
if self.CurrMiniMode then
return table.func(self.CurrMiniMode, InName, ...);
else
if self.CurrSelectMap then
-- 加载一下
self.CurrMiniMode = require(self.ScriptPath .. self.GameConfig[self.CurrSelectMap].Script);
if self.CurrMiniMode == nil then return false; end
if not table.isEmpty(self.GameConfig[self.CurrSelectMap].Params) then
for i, v in pairs(self.GameConfig[self.CurrSelectMap].Params) do
assert(self.CurrMiniMode[i] == nil);
self.CurrMiniMode[i] = v;
end
end
if IsClient then
-- 立刻发送过去表示当前已经创建完毕
self:SendRPC("ClientMiniGameReady", LocalPlayerKey);
self:ClientMiniGameReady(LocalPlayerKey);
end
return self:DoMiniFunc(InName, ...);
end
end
end
---@param InPlayerKey PlayerKey 具体是哪个客户端就绪了
function MiniGameManager:ClientMiniGameReady(InPlayerKey)
-- 客户端的已经就绪,此时可以直接执行对应操作
UGCLogSystem.Log("[MiniGameManager:ClientMiniGameReady] InPlayerKey = %d", tostring(InPlayerKey));
end
----------------------------------- 地图函数 -----------------------------------
MiniGameManager.CurrLoadMapName = nil;
--- 加载地图
function MiniGameManager:LoadMap(InIndex)
-- 检查当前是什么东西,如果是随机的话
local MapNames = MiniGameConfig[InIndex].Map.MapName;
local LoadMap = "";
if type(MapNames) == 'table' then
local Total = 0;
local Maps = {};
for Name, Rate in pairs(MapNames) do
if type(Name) == 'string' then
Total = Total + Rate;
table.insert(Maps, {
Name = Name,
Rate = Rate,
});
elseif type(Name) == 'number' then
table.insert(Maps, {
Name = Rate,
Rate = 1,
})
end
end
local MapCount = table.getCount(Maps);
if Total == 0 then
-- 从这两个中随机一个
LoadMap = Maps[math.random(MapCount)].Name;
else
local RandomNum = math.pop() * Total;
for i = 1, table.getCount(Maps) do
RandomNum = RandomNum - Maps[i].Rate;
if RandomNum <= 0 then
LoadMap = Maps[i].Name;
break ;
end
end
end
elseif type(MapNames) == 'string' then
LoadMap = MapNames;
end
self.CurrLoadMapName = LoadMap;
self.Owner:LoadMap({ LoadMap });
end
--- 完成加载地图
function MiniGameManager:OnMapLoadComplete()
UGCLogSystem.Log("[MiniGameManager:OnMapLoadComplete] 地图加载完成")
if IsServer then
self:AllPlayerRespawn(0.5);
end
self:OnMapLoaded();
end
--- 加载地图
function MiniGameManager:OnMapLoaded()
UGCLogSystem.Log("[MiniGameManager:OnMapLoaded] 加载地图成功")
self:DoMiniFunc("OnAlready");
end
--- 卸载地图
function MiniGameManager:UnLoadMap()
-- 然后过一会再重新加载地图
self.Owner:UnloadMap({ self.CurrLoadMapName });
end
function MiniGameManager:OnMapUnLoadedComplete()
UGCLogSystem.Log("[MiniGameManager:OnMapUnLoadedComplete] 异步卸载地图完成")
end
--- 玩家选择地图
function MiniGameManager:OnPlayerSelectMap(InPlayer, InMapIndex)
if IsServer then
table.insert(self.SelectMaps, InMapIndex);
-- 发送 RPC
self:SendRPC("OnPlayerSelectMap", self.SelectMaps)
else
UGCEventSystem.SendEvent(EventTypes.MiniGame_SelectMap, self.SelectMaps);
end
end
----------------------------------- 回合函数 -----------------------------------
--- 开启小局
function MiniGameManager:OnMiniRoundPrepare()
-- 小局次数 - 1
if IsServer then
self:SetState(MiniGameState.ROUND_PREPARE);
local PreTime = self:GetCurrStateTotalTime()
self:HandleAddTick(PreTime, self.OnMiniRoundFormalStart, function(o, dt, st, t)
o:OnBeforeGameStart(t);
end);
self.CurrMiniMode.RoundTimes = self.CurrMiniMode.RoundTimes - 1;
self.CurrMiniMode.bGameEnd = false;
self.CurrMiniMode.bRoundEnd = false;
self:SetRoundTimes(self.CurrMiniMode.RoundTimes);
else
-- 看看是否要执行什么
UGCLogSystem.Log("[MiniGameManager:OnMiniRoundPrepare] CurrSelectMap = %s", tostring(self.CurrSelectMap));
end
self:DoMiniFunc("OnRoundStart", self:GetCurrRoundTimes())
end
--- 小局正式开始
function MiniGameManager:OnMiniRoundFormalStart()
-- 这是正式开启了
UGCLogSystem.Log("[MiniGameManager:OnMiniRoundFormalStart] 正式开始游戏")
if self.CurrMiniMode then
self.CurrMiniMode.RoundStartTime = UE.GetServerTime();
end
if IsServer then
-- 启动计时,让小游戏有一个时限
self:SetState(MiniGameState.ROUND_GAMING);
self:HandleAddTick(self:GetCurrStateTotalTime(), self.OnMiniRoundEnd, nil, function(o)
return o.CurrMiniMode.bGameEnd or o.CurrMiniMode.bRoundEnd;
end);
-- 解除玩家封禁状态
self:SetAllPawnsCanMove(true);
end
self:DoMiniFunc("OnRoundFormalStart", self:GetCurrRoundTimes(), self.CurrMiniMode.RoundStartTime);
end
function MiniGameManager:OnMiniRoundEnd()
-- 通知结束了
UGCLogSystem.Log("[MiniGameManager:OnMiniRoundEnd] 结束")
self.CurrMiniMode.RoundEndTime = UE.GetServerTime();
local Winner = 0;
if IsServer then
self:SetState(MiniGameState.ROUND_END);
if self.CurrMiniMode.RoundTimes <= 0 or self.CurrMiniMode.bGameEnd then
UGCLogSystem.Log("[MiniGameManager:OnMiniRoundEnd] 回合结束")
self:HandleAddTick(self:GetCurrStateTotalTime(), self.OnMiniGameEnd);
else
-- 继续
-- 开始计时
UGCLogSystem.Log("[MiniGameManager:OnMiniRoundEnd] 下一小局开始")
self:HandleAddTick(self:GetCurrStateTotalTime(), self.OnMiniRoundPrepare);
end
if table.hasFunc(self.CurrMiniMode, 'GetRoundWinner') then
self.MiniInfo.RoundWinner = self:DoMiniFunc("GetRoundWinner", self:GetCurrRoundTimes());
end
Winner = self.MiniInfo.RoundWinner;
UGCLogSystem.Log("[MiniGameManager:OnMiniRoundEnd] Winner = %s", tostring(Winner))
-- 检查是否需要关闭
self:SetAllPawnsCanMove(false);
else
-- 显示回合成功或者失败执行到此一定可以拿到Winner是谁
-- 直接获取 Winner
Winner = self.MiniInfo.RoundWinner
UGCLogSystem.Log("[MiniGameManager:OnMiniRoundEnd] RoundWinner = %s", tostring(Winner));
-- 显示 UI
end
self:DoMiniFunc("OnRoundEnd", self:GetCurrRoundTimes(), Winner, self.CurrMiniMode.RoundEndTime - self.CurrMiniMode.RoundStartTime);
end
function MiniGameManager:SetGameOver()
self.CurrMiniMode.bRoundEnd = true;
self.CurrMiniMode.bGameEnd = true;
end
----------------------------------- 玩家函数 -----------------------------------
--- 当添加玩家的时候执行
function MiniGameManager:OnPlayerLogin(TeamId, InPlayerKey)
UGCLogSystem.Log("[MiniGameManager:OnPlayerLogin] 玩家:%d 登录", InPlayerKey);
if self.TeamPlayerKeys == nil then
self.TeamPlayerKeys = {};
end
if self.TeamPlayerKeys[TeamId] == nil then
self.TeamPlayerKeys[TeamId] = {};
end
table.insert(self.TeamPlayerKeys[TeamId], InPlayerKey);
self:DoMiniFunc("OnPlayerLogin", TeamId, InPlayerKey);
-- 如何发送到客户端呢?
self:SetGameInfo("TeamPlayerKeys", self.TeamPlayerKeys);
end
function MiniGameManager:OnRep_TeamPlayerKeys()
-- 执行
UGCLogSystem.LogTree(string.format("[MiniGameManager:OnRep_TeamPlayerKeys] self.TeamPlayerKeys ="), self.TeamPlayerKeys);
end
function MiniGameManager:OnPlayerLeave(InPlayerKey)
UGCLogSystem.Log("[MiniGameManager:OnPlayerLeave] 玩家:%d 登出", InPlayerKey);
self:DoMiniFunc("OnPlayerLeave", InPlayerKey);
if IsServer then
-- 判断还有多少人
local LastPCs = {};
local TeamIds = {};
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
if UE.IsValid(v) and v.PlayerKey ~= InPlayerKey then
local TeamId = UGCPlayerControllerSystem.GetTeamID(v);
table.insert(LastPCs, v);
TeamIds[TeamId] = 1;
end
end
-- 仅剩一队的情况下无论如何都要退出游戏,因此写在这里
if table.getCount(TeamIds) <= 1 then
-- 直接结束
for TeamId, _ in pairs(TeamIds) do
self:DoMiniFunc("OnLastTeam", TeamId, LastPCs);
end
self:SetGameOver();
end
end
end
--- 检查还有多少人,如果仅剩一个人那么直接结束游戏
function MiniGameManager:CheckLastPlayers()
local LastPlayers = {};
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
if UE.IsValid(v) and v.PlayerKey then
table.insert(LastPlayers, v);
end
end
if table.isEmpty(LastPlayers) then
-- 直接结束,一点不考虑
return true;
end
return false;
end
--- 检查当前是否仅剩一支队伍?
---@return bool, table<TeamId, int32> 是否仅剩一只队伍,剩余队伍的 TeamID
function MiniGameManager:CheckAliveTeam()
local TeamIds = {};
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
if UE.IsValid(v) and v.PlayerKey ~= InPlayerKey then
local TeamId = UGCPlayerControllerSystem.GetTeamID(v);
TeamIds[TeamId] = 1;
end
end
for i, v in pairs(TeamIds) do
return true, i;
end
return false, TeamIds;
end
---@param PlayerStartList table<TeamId, table<int32, APlayerStart>>
---@param Controller UGCPlayerController_C
function MiniGameManager:SelectPlayerStart(PlayerStartList, Controller)
return self:DoMiniFunc('SelectPlayerStart', PlayerStartList, Controller);
end
--- S & C 玩家在加载好之后进行的初始化操作
function MiniGameManager:OnPawnInit(Pawn)
if IsServer then
UGCLogSystem.Log("[MiniGameManager:OnPawnInit] self.CurrSelectMap = %s", tostring(self.CurrSelectMap))
if self.CurrSelectMap == nil then return ; end
local Weapons = self.GameConfig[self.CurrSelectMap].InitWeapons;
UGCLogSystem.LogTree(string.format("[MiniGameManager:OnPawnInit] Weapons ="), Weapons)
self:DoMiniFunc('OnPawnInit', Pawn, Weapons);
else
self:DoMiniFunc('OnPawnInit', Pawn);
end
end
--- 修改伤害函数
---@param DamagedActor UGCPlayerPawn_C
---@param Damage float
---@param DamageType EDamageType
---@param EventInstigator UGCPlayerController_C
function MiniGameManager:OnPlayerDamage(DamagedActor, Damage, DamageType, EventInstigator)
UGCLogSystem.Log("[MiniGameManager:OnPlayerDamage] DamagedActor = %s, Damage = %f", UE.GetName(DamagedActor), Damage);
local CalDamage = self:DoMiniFunc('OnPlayerTakeDamage', DamagedActor, Damage, DamageType, EventInstigator)
if CalDamage == nil then return Damage; end
return CalDamage;
end
--- S & C 接受到伤害函数
function MiniGameManager:BPReceiveDamage(DamagedActor, Damage, DamageType, InstigatedBy, DamageCauser)
if IsServer then
self:DoMiniFunc('BPReceiveDamage', DamagedActor, Damage, DamageType, InstigatedBy, DamageCauser)
end
end
--- 当玩家死亡
---@param DeadPlayerKey PlayerKey
---@param KillerPlayerKey PlayerKey
function MiniGameManager:OnPlayerDead(DeadPlayerKey, KillerPlayerKey)
self:DoMiniFunc('OnPlayerDead', DeadPlayerKey, KillerPlayerKey);
if IsServer then
-- 发送 RPC
self:SendRPC("OnPlayerDead", DeadPlayerKey, KillerPlayerKey);
end
end
function MiniGameManager:OnPlayerRespawn(InPlayerKey)
self:DoMiniFunc("OnPlayerRespawn", InPlayerKey)
end
function MiniGameManager:OnPlayerPossessed(Pawn, NewController)
-- 检查是否有初始武器,如果有,那么直接添加
if self.CurrSelectMap == nil or self.CurrMiniMode == nil then return ; end
if self.GameConfig[self.CurrSelectMap].IsPlayerStunPrepare then
NewController:SetCanMove(false);
end
self:DoMiniFunc("OnPlayerPossessed", Pawn, NewController);
end
---@param PlayerController UGCPlayerController_C
---@param Target APickUpWrapperActor
---@param ItemID int32
---@param Count int32
function MiniGameManager:OnPlayerPickup(PlayerController, Target, ItemID, Count)
self:DoMiniFunc("OnPlayerPickup", PlayerController, Target, ItemID, Count)
end
---@param InPawn UGCPlayerPawn_C
---@param Weapon ASTExtraWeapon
function MiniGameManager:OnPlayerGetWeapon(InPawn, Weapon)
if self.CurrMiniMode then
self:DoMiniFunc("OnPlayerGetWeapon", InPawn, Weapon);
end
end
--- 武器攻击到什么东西的时候
---@param InPawn UGCPlayerPawn_C 是谁射到了
---@param ShootWeapon ASTExtraShootWeapon 发射用的武器
---@param Bullet ASTExtraShootWeaponBulletBase 射中的子弹
---@param HitInfo FHitResult Hit
function MiniGameManager:OnWeaponBulletHit(InPawn, ShootWeapon, Bullet, HitInfo)
if self.CurrMiniMode then
self:DoMiniFunc("OnWeaponBulletHit", InPawn, ShootWeapon, Bullet, HitInfo);
end
end
---@param InPawn UGCPlayerPawn_C
---@param ShootWeapon ASTExtraShootWeapon
---@param BulletID int32
function MiniGameManager:OnPlayerShoot(InPawn, ShootWeapon, BulletID)
if self.CurrMiniMode then
self:DoMiniFunc("OnPlayerShoot", InPawn, ShootWeapon, BulletID);
end
end
------------------------------------ 获取函数 ------------------------------------
--- 获取当前模式
function MiniGameManager:GetCurrentMode() return self.CurrMiniMode; end
--- 获取当前地图名
function MiniGameManager:GetCurrLevel() return self.GameConfig[self.CurrSelectMap].Map.MapName; end
--- 获取当前显示地图名称
function MiniGameManager:GetShowName() return self.GameConfig[self.CurrSelectMap].Map.ShowName; end
--- 获取当前是第几回合
function MiniGameManager:GetCurrRoundTimes()
if table.isEmpty(self.GameConfig) or self.CurrSelectMap == nil or table.isEmpty(self.GameConfig[self.CurrSelectMap]) then
return 1;
end
if self.GameConfig[self.CurrSelectMap].RoundTimes == nil then
return 1;
end
return self.GameConfig[self.CurrSelectMap].RoundTimes - self.CurrMiniMode.RoundTimes;
end
--- S & C 获取当前 State 的总时间
function MiniGameManager:GetCurrStateTotalTime()
if self.State == nil then return 0; end
local Times = nil;
if self.CurrSelectMap ~= nil and self.GameConfig ~= nil then
Times = self.GameConfig[self.CurrSelectMap].MiniGameTimes;
end
local TimeFunc = function(key)
local Time = 0;
if Times ~= nil and Times[key] ~= nil then
Time = Times[key];
else
Time = MiniGameTimes[key];
end
assert(Time ~= nil);
return Time;
end
if self.State <= MiniGameState.NON_START then
return 0;
elseif self.State == MiniGameState.SELECT_GAMES then
return MiniGameTimes.Active;
elseif self.State == MiniGameState.MINI_PREPARE then
return TimeFunc("Prepare");
elseif self.State == MiniGameState.ROUND_PREPARE then
return TimeFunc("RoundPrepare");
elseif self.State == MiniGameState.ROUND_GAMING then
return TimeFunc("RoundGaming");
elseif self.State == MiniGameState.ROUND_END then
return TimeFunc("RoundEnd")
elseif self.State == MiniGameState.MINI_END then
return TimeFunc("MiniGameEnd")
end
end
--- 获取总的回合数
function MiniGameManager:GetTotalRoundTimes()
if table.isEmpty(self.GameConfig) or self.CurrSelectMap == nil or table.isEmpty(self.GameConfig[self.CurrSelectMap]) then
return 1;
end
if self.GameConfig[self.CurrSelectMap].RoundTimes == nil then
return 1;
else
return self.GameConfig[self.CurrSelectMap].RoundTimes
end
end
------------------------------------ 给予函数 ------------------------------------
--- 所有玩家死亡
function MiniGameManager:AllPlayerDead()
for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do
if v:IsAlive() then v:K2_DestroyActor(); end
end
end
--- 所有玩家重生
function MiniGameManager:AllPlayerRespawn(InTime)
self:AllPlayerDead();
UGCEventSystem.SetTimer(self.Owner, function()
for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do
UGCGameSystem.RespawnPlayer(v.PlayerKey);
end
end, InTime);
end
---@param InPawn UGCPlayerPawn_C
---@param InState EPawnState
function MiniGameManager:SetPawnState(InPawn, InState, IsSet)
if IsSet then
UGCPawnSystem.EnterPawnState(InPawn, InState)
else
UGCPawnSystem.LeavePawnState(InPawn, InState)
end
end
function MiniGameManager:SetAllPawnsCanMove(IsCan)
if self.CurrSelectMap == nil then return ; end
if table.isEmpty(self.GameConfig) then return ; end
if table.isEmpty(self.GameConfig[self.CurrSelectMap]) then return ; end
if not self.GameConfig[self.CurrSelectMap].IsPlayerStunPrepare then return ; end
for i, v in pairs(UGCGameSystem.GetAllPlayerController()) do v:SetCanMove(IsCan); end
end
--- 这个需要放在 GameState 中进行更改
function MiniGameManager:DOREPONCE(k, v)
self.Owner[k] = v;
DOREPONCE(self.Owner, k);
end
MiniGameManager.CachedMiniInfo = {};
--- 缓存一份
function MiniGameManager:MakeCachedMiniInfo()
if self.CachedMiniInfo.State == nil then
self.CachedMiniInfo.State = MiniGameState.NON_START;
end
end
--- 属性同步,对比是否不同,只有不同的会进行 OnRep_ 否则就不会进行。
function MiniGameManager:OnRep_MiniInfo(InOld)
for i, v in pairs(self.MiniInfo) do
-- 如果发生改变再执行对应的 OnRep
if type(v) == 'table' then
-- 比较一下这两者有什么不同
if not table.compare(v, self.CachedMiniInfo[i]) then
-- 更新一下
UGCLogSystem.Log("[MiniGameManager:OnRep_MiniInfo] 相同变量 Index = %s", tostring(i));
if self:IsRepProp(tostring(i)) then
self[i] = v;
table.func(self, "OnRep_" .. tostring(i), self.CachedMiniInfo[i]);
end
if self.CurrMiniMode ~= nil then
self.CurrMiniMode[i] = TableHelper.DeepCopyTable(v);
self:DoMiniFunc("OnRep_" .. tostring(i), self.CachedMiniInfo[i]);
end
end
else
if self.CachedMiniInfo[i] ~= v then
if self:IsRepProp(tostring(i)) then
self[i] = v;
table.func(self, "OnRep_" .. tostring(i), self.CachedMiniInfo[i]);
end
if self.CurrMiniMode ~= nil then
self.CurrMiniMode[i] = v;
self:DoMiniFunc("OnRep_" .. tostring(i), self.CachedMiniInfo[i]);
end
end
end
UGCLogSystem.Log("[MiniGameManager:OnRep_MiniInfo] Index = %s", i);
self.CachedMiniInfo[i] = nil;
end
-- 检查是否有多余的
for i, v in pairs(self.CachedMiniInfo) do
if self.MiniInfo[i] == nil then
if self:IsRepProp(tostring(i)) then
self[tostring(i)] = nil;
table.func(self, "OnRep_" .. tostring(i), v);
end
if self.CurrMiniMode ~= nil then
self.CurrMiniMode[tostring(i)] = nil;
self:DoMiniFunc("OnRep_" .. tostring(i), v);
end
UGCLogSystem.Log("[MiniGameManager:OnRep_MiniInfo] 执行冗余的 Index = %s", tostring(i));
end
UGCLogSystem.Log("[MiniGameManager:OnRep_MiniInfo] 冗余的 Index = %s", tostring(i));
end
-- 设置上去进行缓存
self.CachedMiniInfo = TableHelper.DeepCopyTable(self.MiniInfo);
end
--- 获取内部数据
function MiniGameManager:GetMiniInfo(InName)
if self.CurrMiniMode then
local Item = self:DoMiniFunc("GetMiniInfo", InName);
if Item ~= nil then return Item; end
return self.CurrMiniMode[InName];
end
return nil;
end
return MiniGameManager;