---@type table ---@private UE.CachedClasses = {}; --- 组件位置 UE.ComponentPath = { Camera = "/Script/Engine.CameraComponent", SpringArm = "/Script/Engine.SpringArmComponent", }; UE.ResetClassPath = { "PlayerTombBox", -- 玩家死亡盒子基类 "PickUpWrapperActor", -- 可拾取物的基类 "EliteProjectile", -- 投掷物的基类 }; ---@param InInfo PlayerAccountInfo ---@return PlayerAccountInfo function UE.HandleAccountInfo(InInfo) return { UID = InInfo.UID, PlayerName = InInfo.PlayerName, TeamID = InInfo.TeamID, --Gender = InInfo.Gender, -- 暂时用不到的先不用 --PlatformGender = InInfo.PlatformGender, --PlayerLevel = InInfo.PlayerLevel, --SegmentLevel = InInfo.SegmentLevel, IconURL = InInfo.IconURL, }; end function UE.InitKDA() return { Kill = 0, Dead = 0, Assist = 0, } end function UE.GetPlayerName(PlayerKey) local Info = UE.GetAccountInfo(PlayerKey); if Info then return UE.GetAccountInfo(PlayerKey).PlayerName; end UGCLogSystem.Log("[UE.GetPlayerName] 无法找到 PlayerKey = %s", tostring(PlayerKey)); return ""; end function UE.GetPlayerUID(PlayerKey) local Info = UE.GetAccountInfo(PlayerKey); if Info then return UE.GetAccountInfo(PlayerKey).UID; end UGCLogSystem.Log("[UE.GetPlayerName] 无法找到 PlayerKey = %s", tostring(PlayerKey)); return nil; end function UE.GetTeamID(PlayerKey) local Info = UE.GetAccountInfo(PlayerKey); if Info then return Info.TeamID end UGCLogSystem.Log("[UE.GetPlayerName] 无法找到 PlayerKey = %s", tostring(PlayerKey)); return nil; end function UE.GetPlayerIconURL(PlayerKey) local Info = UE.GetAccountInfo(PlayerKey); if Info then return UE.GetAccountInfo(PlayerKey).IconURL; end UGCLogSystem.Log("[UE.GetPlayerName] 无法找到 PlayerKey = %s", tostring(PlayerKey)); return nil; end ---@return table function UE.InitArchiveData() return { GameTimes = 0, Weapons = {}, } end ---@param InClass UClass ---@param InTable table 获得的 ---@param InFunc fun(InIndex:int32, InActor:AActor): bool ---@return table function UE.FindActorsByClass(InClass, InTable, InFunc) if InTable == nil then InTable = {}; end local AllActors = {}; if InClass == nil then InClass = UE.GetActorClass(); end GameplayStatics.GetAllActorsOfClass(UGCGameSystem.GameState, InClass, AllActors); for i, v in pairs(AllActors) do if InFunc == nil or InFunc(i, v) then table.insert(InTable, v); end end return InTable; end ---@param InTable table ---@param InTag FName ---@param InFunc fun(InActor: AActor): bool ---@return table function UE.FindActorsByTag(InTag, InTable, InFunc) if table.isEmpty(InTable) then InTable = {}; end local AllActors = {}; GameplayStatics.GetAllActorsWithTag(UGCGameSystem.GameState, InTag, AllActors); for i, v in pairs(AllActors) do if InFunc == nil or InFunc(v) then table.insert(InTable, v); end end return InTable; end function UE.GetActorClass() return UGCGameSystem.GameState.ActorClass; end ---@param InTag FName ---@param InFunc fun(InActor: AActor): bool ---@return table function UE.FindActorByTag(InTag, InFunc) local AllActors = {}; GameplayStatics.GetAllActorsWithTag(UGCGameSystem.GameState, InTag, AllActors); for i, v in pairs(AllActors) do if InFunc == nil or InFunc(v) then return v; end end return nil; end ---@param InClass UClass ---@param InFunc fun(InIndex:int32, InActor:AActor): bool ---@return AActor function UE.FindActorByClass(InClass, InFunc) local Table = {}; UE.FindActorsByClass(InClass, Table, InFunc); if table.isEmpty(Table) then return nil; end return Table[1]; end ---@type table UE.GlobalCachedActor = {}; ---@param InClass UClass ---@return nil | AActor function UE.FindOrCreateActorByClass(InClass, bDestroyOther) print(string.format('[UE.FindOrCreateActorByClass] 开始执行, ClassName = %s', UE.GetName(InClass))); if InClass == nil then return nil; end local CachedActor = UE.GlobalCachedActor[InClass]; if CachedActor ~= nil and UE.IsValid(CachedActor) then return CachedActor; end local Actors = {} UE.FindActorsByClass(InClass, Actors); local Actor = nil; for i, v in pairs(Actors) do Actor = v; if Actor ~= v and bDestroyOther then v:K2_DestroyActor(); end end if Actor ~= nil then UE.GlobalCachedActor[InClass] = Actor; return Actor; end return UE.CreateActor(InClass); end ---@param ClassPath string 类路径 ---@return UClass | nil function UE.CachedLoadClass(ClassPath) if UE.CachedClasses[ClassPath] == nil then UE.CachedClasses[ClassPath] = UE.LoadClass(ClassPath); end if UE.CachedClasses[ClassPath] == nil then print(string.format('[UE.CachedLoadClass] Error Cant Load Class By Path: %s', ClassPath)); return nil; end return UE.CachedClasses[ClassPath]; end function UE.CreateActor(InClass, InCount, InOuter) if InOuter == nil then InOuter = UGCGameSystem.GameState; end if InCount == nil then InCount = 1 end local Actors = {}; for i = 1, InCount do table.insert(Actors, UE.SpawnActor(InClass, InOuter)) end if InCount == 1 then return Actors[1]; end return Actors; end ---@param InClass UClass ---@param Loc FVector ---@param Rot FRotator ---@param Scale FVector function UE.SpawnActor(InClass, InOuter, Loc, Rot, Scale) Loc = Loc or VectorHelper.MakeVector1(0); Rot = Rot or VectorHelper.MakeRotator(VectorHelper.MakeVector1(0)); Scale = Scale or VectorHelper.MakeVector1(1); InOuter = InOuter or GameState; return UGCGameSystem.SpawnActor(GameState, InClass, Loc, Rot, Scale, InOuter); end --- 玩家重生 ---@param InPlayerKey PlayerKey ---@param InTime float function UE.RespawnPlayer(InPlayerKey, InTime) local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(InPlayerKey); if Pawn then Pawn:K2_DestroyActor(); end if InTime == 0 or InTime == nil then UGCGameSystem.RespawnPlayer(InPlayerKey); else UGCEventSystem.SetTimer(GameState, function() UGCGameSystem.RespawnPlayer(InPlayerKey); end, InTime); end end --- 获取当前时间 function UE.GetCurrentTime() return KismetSystemLibrary.GetGameTimeInSeconds(UGCGameSystem.GameState); end ---@param InPlayerKey PlayerKey ---@return PlayerAccountInfo function UE.GetAccountInfo(InPlayerKey) if InPlayerKey == nil then return UGCGameSystem.GameState.PlayerDatas.AccountInfo; end return UGCGameSystem.GameState.PlayerDatas.AccountInfo[InPlayerKey]; end --- 移动玩家到某个地方 ---@param InPawn UGCPlayerPawn_C ---@param Location FVector ---@param Rotation FRotator function UE.MovePlayerToLocation(InPawn, Location, Rotation) if InPawn == nil then return end InPawn:bShouldDumpCallstackWhenMovingfast_Tofalse() InPawn:SetClientLocationOrRotation(Location, Rotation, true, Rotation ~= nil, false); InPawn:bShouldDumpCallstackWhenMovingfast_ToTrue() end --- 激活对应的 Camera ---@param InPawn UGCPlayerPawn_C ---@param InCamera UCameraComponent ---@param InArm USpringArmComponent function UE.ActiveCamera(InPawn, InCamera, InArm) if InPawn == nil then return end UE.ForeachComponent(InPawn, UE.ComponentPath.Camera, function(c) c:Deactivate() end) UE.ForeachComponent(InPawn, UE.ComponentPath.SpringArm, function(c) c:Deactivate() end) InCamera:Activate(); InArm:Activate(); table.func(InPawn, "SetCurrentCamera", InCamera, InArm); end --- 遍历 Actor 上面的所有组件 ---@param InActor AActor ---@param InComponent UActorComponent ---@param cb fun(c: UActorComponent) function UE.ForeachComponent(InActor, InComponent, cb) local Path = UE.ComponentPath[InComponent] == nil and InComponent or UE.ComponentPath[InComponent]; for i, v in pairs(InActor:GetComponentsByClass(LoadClass(Path))) do cb(v); end end ---@param InComponent USceneComponent ---@param InFunc fun(Component:USceneComponent) function UE.ForeachChildrenComponent(InComponent, InFunc) if InComponent == nil then return; end local ChildCount = InComponent:GetNumChildrenComponents(); for i = 1, ChildCount do local Component = InComponent:GetChildComponent(i - 1); if Component then InFunc(Component); end end end ---清空地图上的 Wrapper function UE.ClearWrappers(bWeapon, bPart, bBullet, bEquipment, bSkin, bSupplies) local AllActors = {}; local Func = function(b) if b == nil then return true end return b; end bWeapon = Func(bWeapon); bPart = Func(bPart); bBullet = Func(bBullet); bEquipment = Func(bEquipment); bSkin = Func(bSkin); bSupplies = Func(bSupplies); UE.FindActorsByClass(GameState:GetWrapperClass(), AllActors, function(InIndex, InActor) if InActor.DefineID == nil then return true; end local ItemId = InActor.DefineID.TypeSpecificID; if ItemId == nil or (not InActor.DefineID.bValidItem) then return true; end UGCLogSystem.Log("[UE.ClearWrappers] ItemId = %s", tostring(ItemId)); local Type = GetCustomItemType(ItemId); if (bWeapon and Type == ECustomItemType.Weapon) or (bPart and Type == ECustomItemType.Part) or (bBullet and Type == ECustomItemType.Bullet) or (bEquipment and Type == ECustomItemType.Equipment) or (bSkin and Type == ECustomItemType.Skin) or (bSupplies and Type == ECustomItemType.Supplies) then InActor:K2_DestroyActor() end end); end --- 组件朝向玩家 ---@param InComponent USceneComponent ---@param InActor AActor ---@param Lock string 锁定的轴,如果是 Y 轴:那么就相当于让组件对着玩家 function UE.ComponentTowardActor(InComponent, InActor, Lock) if InComponent == nil then return ; end local Rot = KismetMathLibrary.Conv_VectorToRotator(VectorHelper.Sub(InActor:K2_GetActorLocation(), InComponent:GetOwner():K2_GetActorLocation())); if Lock ~= nil then if Lock == 'Z' or Lock == 'Yaw' then Rot = { Roll = Rot.Roll, Pitch = Rot.Pitch, Yaw = 0 }; elseif Lock == 'Y' or Lock == 'Pitch' then Rot = { Roll = Rot.Roll, Pitch = 0, Yaw = Rot.Yaw }; elseif Lock == 'X' or Lock == 'Roll' then Rot = { Roll = 0, Pitch = Rot.Pitch, Yaw = Rot.Yaw }; end end InComponent:K2_SetWorldRotation(Rot); end --- 获取服务器时间 function UE.GetServerTime() if UGCGameSystem.GameState then return UGCGameSystem.GameState:GetServerTime(); end return nil end ---@param InTable table ---@param InFunc fun(InActor:AActor):bool function UE.DestroyTable(InTable, InFunc) if table.isEmpty(InTable) then return ; end for i, v in pairs(InTable) do if InFunc == nil or InFunc(v) then v:K2_DestroyActor(); end end InTable = {}; end function UE.IsPlayerPawn(InPawn) return UE.IsA(InPawn, ObjectPath.UGCPlayerPawn) end ---@param InPawn UGCPlayerPawn_C function UE.IsValidPawn(InPawn) return InPawn ~= nil and UE.IsValid(InPawn) and InPawn:IsAlive(); end ---@param TeamId int32 ---@param OutPawns table ---@param InFunc fun(InPawn:UGCPlayerPawn_C):bool function UE.GetValidPawnsByTeamID(TeamId, OutPawns, InFunc) local PlayerKeys = UGCTeamSystem.GetPlayerKeysByTeamID(TeamId); if OutPawns == nil then OutPawns = {}; end for i, PlayerKey in pairs(PlayerKeys) do local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey); if UE.IsValidPawn(Pawn) then if InFunc == nil or (type(InFunc) == 'function') then table.insert(OutPawns, Pawn); end end end return OutPawns; end function UE.GetOtherTeamIDs(TeamID) local TeamIds = UGCTeamSystem.GetTeamIDs(); local Ret = {}; for i, v in pairs(TeamIds) do if v ~= TeamID then table.insert(Ret, v); end end return Ret; end ---@param TeamID int32 ---@param OutPawns table ---@param InFunc fun(InPawn:UGCPlayerPawn_C):bool function UE.GetOtherPawnsByTeamID(TeamID, OutPawns, InFunc) local AllTeamIds = UE.GetOtherTeamIDs(TeamID); if OutPawns == nil then OutPawns = {}; end for _i, TeamId in pairs(AllTeamIds) do local PlayerKeys = UGCTeamSystem.GetPlayerKeysByTeamID(TeamId) UE.GetValidPawnsByTeamID(TeamId, OutPawns, InFunc); end return OutPawns; end function UE.ReturnToLobby() NetUtil.SendPkg("giveup_enter_game"); LobbySystem.ReturnToLobby(); end function UE.LoadClass1(Path, cb) local Class = UE.LoadClass(Path); if cb ~= nil then cb(Class); end return Class end UE.AsyncCachedItems = {}; ---@param Path string ---@param cb fun(TargetClass: UClass) function UE.AsyncLoadClass(Path, cb) if cb == nil then return end if UE.AsyncCachedItems[Path] then cb(UE.AsyncCachedItems[Path]); return ; end CommonUtils:AsyncLoadClass(UGCGameSystem.GameState, Path, function(TargetClass) if TargetClass and UE.IsValid(TargetClass) then cb(TargetClass); end end) end ---@param Path string ---@param cb fun(TargetClass: UClass) function UE.AsyncLoadClass_Cached(Path, cb) if UE.AsyncCachedItems[Path] ~= nil then if cb then cb(UE.AsyncCachedItems[Path]); end return ; end if cb == nil then return end CommonUtils:AsyncLoadClass(UGCGameSystem.GameState, Path, function(TargetClass) if TargetClass and UE.IsValid(TargetClass) then UE.AsyncCachedItems[Path] = TargetClass; if cb then cb(UE.AsyncCachedItems[Path]); end end end) end ---@param Path string ---@param cb fun(TargetObject: UObject) function UE.AsyncLoadObject(Path, cb) if cb == nil then return end if UE.AsyncCachedItems[Path] then cb(UE.AsyncCachedItems[Path]); return ; end CommonUtils:AsyncLoadObject(UGCGameSystem.GameState, Path, function(TargetObject) if TargetObject and UE.IsValid(TargetObject) then cb(TargetObject); end end) end ---@param Path string ---@param cb fun(TargetObject: UObject) function UE.AsyncLoadObject_Cached(Path, cb) if UE.AsyncCachedItems[Path] ~= nil then if cb then cb(UE.AsyncCachedItems[Path]); end return ; end CommonUtils:AsyncLoadObject(UGCGameSystem.GameState, Path, function(TargetObject) if TargetObject and UE.IsValid(TargetObject) then UE.AsyncCachedItems[Path] = TargetObject; if cb then cb(TargetObject); end end end) end function UE.AsyncLoadObj(Path, cb) CommonUtils:AsyncLoadObject(UGCGameSystem.GameState, Path, function(TargetObject) if TargetObject and UE.IsValid(TargetObject) then if cb then cb(TargetObject); end end end) end ---@param InFunc fun(PlayerKey:PlayerKey) function UE.ForeachAllPlayerKeys(InFunc) for PlayerKey, Info in pairs(GameState.PlayerDatas.AccountInfo) do InFunc(PlayerKey) end end ---@param InFunc fun(Pawn:UGCPlayerPawn_C) function UE.ForeachAllPawns(InFunc) for i, Pawn in pairs(UGCGameSystem.GetAllPlayerPawn()) do if UE.IsValidPawn(Pawn) then InFunc(Pawn); end end end ---@param InPlayerKey PlayerKey ---@param InFunc fun(Pawn:UGCPlayerPawn_C) function UE.ForeachSelfTeam(InPlayerKey, InFunc, bWithoutSelf) if InFunc == nil then return end local LocalPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(InPlayerKey); local LocalTeamId = UGCPawnAttrSystem.GetTeamID(LocalPawn); for i, Pawn in pairs(UGCGameSystem.GetAllPlayerPawn()) do if UE.IsValidPawn(Pawn) then if Pawn.PlayerKey == InPlayerKey then if not bWithoutSelf then InFunc(Pawn); end else local TeamId = UGCPawnAttrSystem.GetTeamID(Pawn); if TeamId == LocalTeamId then InFunc(Pawn); end end end end end function UE.IsSameTeam(PlayerKey1, PlayerKey2) return UGCPlayerStateSystem.GetTeamID(PlayerKey1) == UGCPlayerStateSystem.GetTeamID(PlayerKey2); end ---@param InPlayerKey PlayerKey ---@param InFunc fun(Pawn:UGCPlayerPawn_C) function UE.ForeachEnemyTeam(InPlayerKey, InFunc) if InFunc == nil then return end local LocalPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(InPlayerKey); local LocalTeamId = UGCPawnAttrSystem.GetTeamID(LocalPawn); for i, Pawn in pairs(UGCGameSystem.GetAllPlayerPawn()) do if UE.IsValidPawn(Pawn) then local TeamId = UGCPawnAttrSystem.GetTeamID(Pawn); if TeamId ~= LocalTeamId then InFunc(Pawn); end end end end ---@param InFunc fun(PC:UGCPlayerController_C) function UE.ForeachAllPCs(InFunc) for i, PC in pairs(UGCGameSystem.GetAllPlayerController()) do if PC and UE.IsValid(PC) then InFunc(PC); end end end UE.WrapperClass = nil; function UE.GetWrapperClass() if UE.WrapperClass == nil then UE.WrapperClass = ScriptGameplayStatics.FindClass("PickUpWrapperActor") end return UE.WrapperClass; end ---@param InComponent UShapeComponent ---@param Func fun(InPawn:UGCPlayerPawn_C) ---@param InOwner AActor function UE.BeginOverlap(InComponent, Func, InOwner) if Func == nil then return ; end InComponent.OnComponentBeginOverlap:Add(function(Self, OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult) if OtherActor ~= nil and UE.IsPlayerPawn(OtherActor) then UGCLogSystem.Log("[UE.BeginOverlap] OtherActor = %s, InOwner = %s", UE.GetName(OtherActor), UE.GetName(InOwner)); Func(InOwner, OtherActor) end end, InOwner); end ---@param InComponent UShapeComponent ---@param Func fun(InPawn:UGCPlayerPawn_C) ---@param InOwner AActor function UE.EndOverlap(InComponent, Func, InOwner) if Func == nil then return ; end InComponent.OnComponentEndOverlap:Add(function(Self, OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex) if OtherActor ~= nil and UE.IsPlayerPawn(OtherActor) then UGCLogSystem.Log("[UE.EndOverlap] OtherActor = %s, InOwner = %s", UE.GetName(OtherActor), UE.GetName(InOwner)); Func(InOwner, OtherActor); end end, InOwner); end ---@type table> UE.SpawnedEmitters = {}; ---@param Particle UParticleSystem ---@param Pawn UGCPlayerPawn_C ---@return UParticleSystemComponent function UE.SpawnEmitterAttached(Particle, Pawn, Offset) if Offset == nil then Offset = VectorHelper.VectorZero() end if type(Particle) == 'string' then Particle = ObjectPath[Particle]; end local Emitter = GameplayStatics.SpawnEmitterAttached(Particle, Pawn.Mesh, "", Offset, VectorHelper.RotZero(), Pawn:GetActorScale3D(), EAttachLocation.SnapToTargetIncludingScale, true); if UE.SpawnedEmitters[Pawn.PlayerKey] == nil then UE.SpawnedEmitters[Pawn.PlayerKey] = {}; end table.insert(UE.SpawnedEmitters[Pawn.PlayerKey], Emitter); return Emitter; end ---@param Particle UParticleSystem ---@param Location FVector function UE.SpawnEmitterAtLocation(Particle, Location) if type(Particle) == 'string' then Particle = ObjectPath[Particle]; end return GameplayStatics.SpawnEmitterAtLocation(GameState, Particle, Location, VectorHelper.RotZero(), VectorHelper.ScaleOne(), true); end ---@param Pawn UGCPlayerPawn_C function UE.ResetPlayerBenefit(Pawn) -- 重置玩家血量 Pawn:SetMaxHealth(100); -- 重置速度 UGCPawnAttrSystem.SetSpeedScale(Pawn, 1); -- 重置伤害 Pawn:SetDamageScale(1); -- 重置护甲 Pawn:SetArmor(0); -- 重置跳跃 UGCPawnAttrSystem.SetJumpZVelocity(Pawn, 443.); -- 设置能量 UGCPawnAttrSystem.SetEnergy(Pawn, 100); -- 设置信号值 UGCPawnAttrSystem.SetSignal(Pawn, 100); end --- 移除场景上的物品 function UE.ClearSceneObjects() for i, v in pairs(UE.ResetClassPath) do local Class = ScriptGameplayStatics.FindClass(v); if UE.IsValid(Class) then local Actors = {}; UE.FindActorsByClass(Class, Actors); for c, Actor in pairs(Actors) do Actor:K2_DestroyActor(); end end end end --- 在 List 中查找满足条件的 Actor ---@param InList table ---@param Func fun(Actor:AActor):bool function UE.FindActorInList(InList, Func) for i, v in pairs(InList) do if Func(v) then return v; end end return nil; end --- 查找距离 Target 最近 Distance 的 Actor, 并随机返回一个 ---@param InList table ---@param Target AActor ---@param Distance float function UE.FindNearestActors(InList, Target, Distance) UGCLogSystem.Log("[UE.FindNearestActors] 执行") local MinDis = math.maxinteger; if Distance == nil then Distance = 0; end local Actors = {}; UGCLogSystem.LogTree(string.format("[UE.FindNearestActors] InList ="), InList) for i, v in pairs(InList) do local Dis = VectorHelper.GetActorDis2D(v, Target); if Dis < Distance then table.insert(Actors, v); end end UGCLogSystem.LogTree(string.format("[UE.FindNearestActors] Actors"), Actors) if not table.isEmpty(Actors) then local PlayerStart = Actors[math.random(#Actors)]; UGCLogSystem.Log("[UE.FindNearestActors] PlayerStart = %s", UE.GetName(PlayerStart)); return PlayerStart; end UGCLogSystem.Log("[UE.FindNearestActors] 111") return nil; end