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

1053 lines
36 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
local 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<PlayerKey, any> 玩家数据
MiniGameManager.PlayerDatas = {};
---@type table<int32, any> 小游戏需要同步的数据,会自动执行 OnRep_xxx 函数
MiniGameManager.MiniInfo = {};
MiniGameManager.PlayerKDAs = {};
MiniGameManager.PlayerDamages = {};
MiniGameManager.PlayerAssistTimes = {};
----------------------------------- 主要函数 -----------------------------------
--- 这是游戏启动,做一些初始化的操作即可
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"
, "PlayerKDAs"
, "PlayerDamages"
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
-- -- 玩家死亡重生
-- 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:OnGameEnd()
UGCLogSystem.Log("[MiniGameManager:OnGameEnd] 游戏结束")
if IsServer then
self:SetState(MiniGameState.ENDED);
GameState:OnGameEnded(MiniGameTimes.GameEnd);
UGCLogSystem.Log("[MiniGameManager:OnGameEnd] GameEnd Time = %f", MiniGameTimes.GameEnd)
UGCEventSystem.SetTimer(self.Owner, function()
LuaQuickFireEvent("CloseServer", self.Owner)
end, MiniGameTimes.GameEnd + 2);
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; -- 是否可以重生
-- 玩家击杀数据
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
self:DoMiniFunc("OnTimeCountDown", InVal, InTotal);
InVal = math.floor(InVal);
--- 执行
self.Owner:OnGameProgress_Tick(InVal);
end
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();
local Time = self:GetCurrStateTotalTime();
UGCLogSystem.Log("[MiniGameManager:OnMiniGameEnd] Time = %f", Time);
self:HandleAddTick(Time, self.OnMiniGameSwitch)
end
--- 切换到下一个 MiniGame
function MiniGameManager:OnMiniGameSwitch()
-- 检查是否还有下一个了
UGCLogSystem.Log("[MiniGameManager:OnMiniGameSwitch] 执行")
if table.isEmpty(self.SelectMaps) then return self:OnGameEnd(); 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 not table.compare(self.MiniInfo[InName], InInfo) then
if type(InInfo) == 'table' then
self.MiniInfo[InName] = TableHelper.DeepCopyTable(InInfo);
else
self.MiniInfo[InName] = InInfo;
end
self:SetMiniInfo();
end
end
function MiniGameManager:DOREPONCE_Mini(Name)
if self.CurrMiniMode then
table.func(self.CurrMiniMode, "DOREPONCE", "PlayerKDAs");
end
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
GlobalMiniMode = GlobalMiniMode or self.CurrMiniMode;
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
return self:DoMiniFunc(InName, ...);
end
end
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
-- 在此之前调用一下内部函数
local Map = table.func(self.CurrMiniMode, "SelectLevel", LoadMap)
if Map ~= nil then LoadMap = Map; end
self.CurrLoadMapName = LoadMap;
self.Owner:LoadMap({ LoadMap });
end
--- 完成加载地图
function MiniGameManager:OnMapLoadComplete()
UGCLogSystem.Log("[MiniGameManager:OnMapLoadComplete] 地图加载完成")
-- 查看是否加载成功了对应的东西,如果没加载成功,就不需要管了
self:ResetPlayers();
self:OnMapLoaded();
end
--- 加载地图
function MiniGameManager:OnMapLoaded()
UGCLogSystem.Log("[MiniGameManager:OnMapLoaded] 加载地图成功")
self:DoMiniFunc("OnAlready");
-- 重生一下玩家
if IsClient then
-- 加载是否有 GodCamera
self.CurrMiniMode.GodCamera = UE.FindActorByClass(ObjectPath.BP_GodCamera)
else
LuaQuickFireEvent("AllPlayerReset", self.Owner);
--if not self:Test_CheckActorStarts() then
-- self.CheckStartTimer = UGCEventSystem.SetTimerLoop(GameState, function()
-- if self:Test_CheckActorStarts() then
-- if self.CheckStartTimer then
-- UGCEventSystem.StopTimer(self.CheckStartTimer);
-- self.CheckStartTimer = nil;
-- end
-- end
-- end, 1);
--end
--if not self:Test_CheckPlayerStart() then
-- self.CheckPlayerStartTimer = UGCEventSystem.SetTimerLoop(GameState, function()
-- if self:Test_CheckPlayerStart() then
-- if self.CheckPlayerStartTimer then
-- UGCEventSystem.StopTimer(self.CheckPlayerStartTimer);
-- self.CheckPlayerStartTimer = nil;
-- end
-- end
-- end, 1);
--end
GameState:TogglePoison(1);
-- 检查是否存在
self:InitPlayerData();
end
end
function MiniGameManager:Test_CheckActorStarts()
-- 查找一下是否存在 ActorStart
local AllStarts = {};
UE.FindActorsByClass(ObjectPath.BP_ActorStart, AllStarts)
for i, v in pairs(AllStarts) do
UGCLogSystem.Log("[MiniGameManager:Test_CheckActorStarts] Actor Name = %s", UE.GetName(v));
end
return not table.isEmpty(AllStarts);
end
function MiniGameManager:Test_CheckPlayerStart()
local AllStarts = {};
UE.FindActorsByClass(ObjectPath.BP_PlayerStartBase, AllStarts);
for i, v in pairs(AllStarts) do
UGCLogSystem.Log("[MiniGameManager:Test_CheckPlayerStart] Actor Name = %s", UE.GetName(v));
end
return not table.isEmpty(AllStarts);
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);
-- 检查玩家身上是否有武器,如果没有武器,检查一下是否
local InitItems = self:GetInitItemIds();
UE.ForeachAllPawns(function(Pawn)
-- 检查第一个即可,如果第一个已经有了,其他的也会有
if not ItemTool.CheckPawnHasItemId(Pawn, InitItems[1]) then
Pawn:AddInitItems(InitItems.Init);
end
end);
-- 重置一下数据
self:ResetPlayers();
end
self:InitPlayerData();
self:DoMiniFunc("OnRoundFormalStart", self:GetCurrRoundTimes(), self.CurrMiniMode.RoundStartTime);
end
function MiniGameManager:GetInitItemIds()
local InitItems = self.GameConfig[self.CurrSelectMap].InitWeapons
if InitItems then
if InitItems.Init then
local ItemIds = {};
for i, v in pairs(InitItems.Init) do
local Name = v[1];
UGCLogSystem.Log("[MiniGameManager:GetInitItemIds] Item Name = %s", Name);
if EnglishNamedWeapon[Name] then
local ItemId = EnglishNamedWeapon[Name].ItemId;
table.insert(ItemIds, ItemId);
end
end
return ItemIds;
end
end
return nil;
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;
-- 检查是否需要关闭
self:SetAllPawnsCanMove(false);
else
-- 显示回合成功或者失败执行到此一定可以拿到Winner是谁
Winner = self.MiniInfo.RoundWinner
end
UGCLogSystem.Log("[MiniGameManager:OnMiniRoundEnd] RoundWinner = %s", tostring(Winner));
self:DoMiniFunc("OnRoundEnd", self:GetCurrRoundTimes(), Winner, self.CurrMiniMode.RoundEndTime - self.CurrMiniMode.RoundStartTime);
end
----------------------------------- 玩家函数 -----------------------------------
--- 当添加玩家的时候执行
function MiniGameManager:OnPlayerLogin(InPlayerKey)
UGCLogSystem.Log("[MiniGameManager:OnPlayerLogin] 玩家:%d 登录", InPlayerKey);
self:DoMiniFunc("OnPlayerLogin", InPlayerKey);
self.PlayerDatas[InPlayerKey] = {
IsConnect = true;
};
if self.PlayerDamages[InPlayerKey] == nil then
self.PlayerDamages[InPlayerKey] = 0;
self:SetGameInfo("PlayerDamages", self.PlayerDamages);
end
self.PlayerAssistTimes[InPlayerKey] = {};
if self.PlayerKDAs[InPlayerKey] == nil then
self.PlayerKDAs[InPlayerKey] = UE.InitKDA();
self:SetGameInfo("PlayerKDAs", self.PlayerKDAs);
else
-- 说明玩家重新登陆
self:OnPlayerRelogin(InPlayerKey);
end
end
--- 玩家重新登录
function MiniGameManager:OnPlayerRelogin(InPlayerKey)
-- 玩家重复登录执行
self:DoMiniFunc("OnPlayerRelogin", InPlayerKey);
end
--- 当玩家退出的时候执行
function MiniGameManager:OnPlayerLeave(InPlayerKey)
UGCLogSystem.Log("[MiniGameManager:OnPlayerLeave] 玩家:%d 登出", InPlayerKey);
self.PlayerDatas[InPlayerKey].IsConnect = false;
return self:DoMiniFunc("OnPlayerLeave", InPlayerKey);
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 玩家在加载好之后进行的初始化操作,该操作是在 Pawn 一秒钟后执行
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)
if self.PlayerAssistTimes[DamagedActor.PlayerKey] == nil then self.PlayerAssistTimes[DamagedActor.PlayerKey] = {}; end
if InstigatedBy ~= nil and InstigatedBy.PlayerKey ~= DamagedActor.PlayerKey then
self.PlayerAssistTimes[DamagedActor.PlayerKey][InstigatedBy.PlayerKey] = UE.GetServerTime() + MiniGlobalConfig.AssistTime;
if self.PlayerDamages[InstigatedBy.PlayerKey] == nil then
self.PlayerDamages[InstigatedBy.PlayerKey] = Damage;
else
self.PlayerDamages[InstigatedBy.PlayerKey] = Damage + self.PlayerDamages[InstigatedBy.PlayerKey];
end
UGCEventSystem.SendEvent(EventTypes.UpdatePlayerDamages, self.PlayerDamages);
self:SetGameInfo("PlayerDamages", self.PlayerDamages);
end
end
end
function MiniGameManager:OnRep_PlayerDamages()
UGCLogSystem.LogTree(string.format("[MiniGameManager:OnRep_PlayerDamages] self.PlayerDamages ="), self.PlayerDamages)
UGCEventSystem.SendEvent(EventTypes.UpdatePlayerDamages, self.PlayerDamages);
end
--- 当玩家死亡
---@param DeadPlayerKey PlayerKey
---@param KillerPlayerKey PlayerKey
function MiniGameManager:OnPlayerDead(DeadPlayerKey, KillerPlayerKey)
if DeadPlayerKey == nil or DeadPlayerKey <= 0 then return ; end
self:DoMiniFunc('OnPlayerDead', DeadPlayerKey, KillerPlayerKey);
if IsServer then
-- 处理死亡玩家
if self.PlayerKDAs[DeadPlayerKey] == nil then self:ResetPlayerKDA(DeadPlayerKey) end
self.PlayerKDAs[DeadPlayerKey].Dead = (self.PlayerKDAs[DeadPlayerKey].Dead or 0) + 1;
-- 记录一下当前击杀死亡的
if KillerPlayerKey ~= nil and KillerPlayerKey > 0 then
if self.PlayerKDAs[KillerPlayerKey] == nil then self:ResetPlayerKDA(KillerPlayerKey) end
self.PlayerKDAs[KillerPlayerKey].Kill = (self.PlayerKDAs[KillerPlayerKey].Kill or 0) + 1;
end
-- 处理助攻玩家
if self.PlayerAssistTimes[DeadPlayerKey] then
local ServerTime = UE.GetServerTime();
for PlayerKey, AssistTime in pairs(self.PlayerAssistTimes[DeadPlayerKey]) do
if AssistTime <= ServerTime and PlayerKey ~= DeadPlayerKey and PlayerKey ~= KillerPlayerKey then
self.PlayerKDAs[PlayerKey].Assist = (self.PlayerKDAs[PlayerKey].Assist or 0) + 1;
end
end
self.PlayerAssistTimes[DeadPlayerKey] = {};
end
self:SetGameInfo("PlayerKDAs", self.PlayerKDAs);
UGCLogSystem.LogTree(string.format("[MiniGameManager:OnPlayerDead] self.PlayerKDAs ="), self.PlayerKDAs)
-- 发送 RPC
self:SendRPC("OnPlayerDead", DeadPlayerKey, KillerPlayerKey);
end
end
function MiniGameManager:OnRep_PlayerKDAs()
UGCLogSystem.LogTree(string.format("[MiniGameManager:OnRep_PlayerKDAs] self.PlayerKDAs ="), self.PlayerKDAs)
UGCEventSystem.SendEvent(EventTypes.UpdatePlayerKDAs, self.PlayerKDAs);
end
--- 初始化所有数据,保证客户端可以拿到
function MiniGameManager:InitPlayerData()
if IsServer then
if table.isEmpty(self.PlayerKDAs) then
UE.ForeachAllPCs(function(PC)
local PlayerKey = PC.PlayerKey
UGCLogSystem.Log("[MiniGameManager:InitPlayerData] PlayerKey = %s", tostring(PlayerKey));
if PlayerKey then
self:ResetPlayerDamage(PlayerKey);
self:ResetPlayerKDA(PlayerKey);
self.PlayerDatas[PlayerKey] = {
IsConnect = true,
};
end
end)
self:SetGameInfo("PlayerDamages", self.PlayerDamages);
self:SetGameInfo("PlayerKDAs", self.PlayerKDAs);
UGCLogSystem.LogTree(string.format("[MiniGameManager:InitPlayerData] self.PlayerKDAs ="), self.PlayerKDAs)
UGCLogSystem.LogTree(string.format("[MiniGameManager:InitPlayerData] self.PlayerDamages"), self.PlayerDamages)
end
end
--- 让子模块去初始化
self:DoMiniFunc("InitPlayerData")
end
function MiniGameManager:ResetPlayerKDA(InPlayerKey)
if InPlayerKey == nil then
for i, v in pairs(self.PlayerKDAs) do
self:ResetPlayerKDA(i);
end
self:SetGameInfo("PlayerKDAs", self.PlayerKDAs);
else
self.PlayerKDAs[InPlayerKey] = UE.InitKDA();
end
end
function MiniGameManager:ResetPlayerDamage(InPlayerKey)
if InPlayerKey == nil then
for PlayerKey, Damage in pairs(self.PlayerDamages) do
self:ResetPlayerDamage(PlayerKey);
end
self.PlayerAssistTimes = {};
self:SetGameInfo("PlayerDamages", self.PlayerDamages);
else
self.PlayerDamages[InPlayerKey] = 0;
end
end
function MiniGameManager:ResetPlayers()
if IsServer then
self:ResetPlayerKDA();
self:ResetPlayerDamage();
-- 重置玩家击杀
UE.ForeachAllPCs(function(PC) PC:ResetGame(); end);
UE.RespawnAllPlayer();
end
self:DoMiniFunc("ResetMini");
end
--- 玩家重生
---@param InPlayerKey PlayerKey
function MiniGameManager:OnPlayerRespawn(InPlayerKey)
self:DoMiniFunc("OnPlayerRespawn", InPlayerKey)
end
--- 当 Pawn 被控制时
---@param Pawn UGCPlayerPawn_C
---@param NewController UGCPlayerController_C
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;
else
return self.GameConfig[self.CurrSelectMap].RoundTimes - self.CurrMiniMode.RoundTimes;
end
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("MiniEnd")
elseif self.State == MiniGameState.ENDED then
return TimeFunc("GameEnd")
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(GameState, 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)
--UGCLogSystem.LogTree(string.format("[MiniGameManager:OnRep_MiniInfo] self.MiniInfo ="), self.MiniInfo)
--UGCLogSystem.LogTree(string.format("[MiniGameManager:OnRep_MiniInfo] self.CachedMiniInfo Begin ="), self.CachedMiniInfo)
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;
--UGCLogSystem.LogTree(string.format("[MiniGameManager:OnRep_MiniInfo] self.CachedMiniInfo ="), self.CachedMiniInfo)
end
--UGCLogSystem.LogTree(string.format("[MiniGameManager:OnRep_MiniInfo] self.CachedMiniInfo End ="), self.CachedMiniInfo)
-- 检查是否有多余的
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);
--UGCLogSystem.LogTree(string.format("[MiniGameManager:OnRep_MiniInfo] self.CachedMiniInfo Final ="), self.CachedMiniInfo)
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;