UGCSystemLibrary = UGCSystemLibrary or {} UGCSystemLibrary.IsServer = nil -- 缓存的资产 UGCSystemLibrary.CacheAsset = {} ------------------------------------------------ 获取本地信息 ------------------------------------------------ ---@return BP_UGCPlayerController_C function UGCSystemLibrary.GetLocalPlayerController() if not UE.IsValid(UGCSystemLibrary.LocalController) and UGCGameSystem.GameState then UGCSystemLibrary.LocalController = STExtraGameplayStatics.GetFirstPlayerController(UGCGameSystem.GameState) end return UGCSystemLibrary.LocalController end function UGCSystemLibrary.GetLocalPlayerKey() return UGCSystemLibrary.GetLocalPlayerController().PlayerKey end function UGCSystemLibrary.GetLocalPlayerPawn() return UGCGameSystem.GetPlayerPawnByPlayerKey(UGCSystemLibrary.GetLocalPlayerKey()) end function UGCSystemLibrary.GetGameTime() if UGCGameSystem.GameState then return KismetSystemLibrary.GetGameTimeInSeconds(UGCGameSystem.GameState) else return 0. end end ---------------------------------------------- 获取本地信息 End ---------------------------------------------- --- 通过资产路径去获取场景唯一实例 ---@param AssetPath string function UGCSystemLibrary.GetUniqueInstanceFromPath(AssetPath) local ObjClass = UE.LoadClass(AssetPath) return UGCSystemLibrary.GetUniqueInstanceFromClass(ObjClass) end --- 通过资产类去获取场景唯一实例 ---@param ObjClass UClass function UGCSystemLibrary.GetUniqueInstanceFromClass(ObjClass) if UE.IsValid(ObjClass) then local AllActor = ScriptGameplayStatics.GetActorsOfClass(UGCGameSystem.GameState, ObjClass) for i, v in pairs(AllActor) do return v end end return nil end local RootPackagePath = UGCMapInfoLib.GetRootLongPackagePath() function UGCSystemLibrary.GetFullPath(InPath) if type(InPath) ~= "string" then return "" end if #RootPackagePath > #InPath or string.sub(InPath, 1, #RootPackagePath) ~= RootPackagePath then InPath = RootPackagePath..InPath end return InPath end ------------------------------------------ Load ------------------------------------------ --- {URL = Asset} UGCSystemLibrary.DownloadImageAsset = {} --- 下载图像 function UGCSystemLibrary.DownloadImage(URL, bSaveAsset, CallBackFunc, Obj) if UE.IsValid(UGCSystemLibrary.DownloadImageAsset[URL]) then if Obj then CallBackFunc(Obj, UGCSystemLibrary.DownloadImageAsset[URL]) else CallBackFunc(UGCSystemLibrary.DownloadImageAsset[URL]) end else local ResHandle = AsyncTaskDownloadImage.DownloadImage(URL) --ResHandle.OnSuccess:Add(CallBackFunc, Obj) --ResHandle.OnFail:Add(CallBackFunc, Obj) ResHandle.OnSuccess:Add(CallBackFunc) ResHandle.OnFail:Add(CallBackFunc) if bSaveAsset then ResHandle.OnSuccess:Add( function(Texture) UGCSystemLibrary.DownloadImageAsset[URL] = Texture end ) end end end --- 下载图像至UImage ---@param Image UImage* ---@param URL string function UGCSystemLibrary.DownloadImageToUImage(Image, URL) UGCSystemLibrary.DownloadImage(URL, true, function(Texture) if UE.IsValid(Texture) then Image:SetBrushFromTextureDynamic(Texture) else UGCLogSystem.LogError("[UGCSystemLibrary_DownloadImageToUImage] Download Texture Failure. URL: %s", URL) end end ) end ---------------------------------------- Load End ---------------------------------------- function UGCSystemLibrary.BindBeginOverlapFunc(CollisionComponent, Func, Obj) CollisionComponent.OnComponentBeginOverlap:Add(Func, Obj) end function UGCSystemLibrary.BindEndOverlapFunc(CollisionComponent, Func, Obj) CollisionComponent.OnComponentEndOverlap:Add(Func, Obj) end function UGCSystemLibrary.formatTime(seconds, ShowMinutes, ShowHours, ShowRemainingSeconds) if ShowMinutes == nil then ShowMinutes = false end if ShowHours == nil then ShowHours = false end if ShowRemainingSeconds == nil then ShowRemainingSeconds = false end local hours = math.floor(seconds / 3600) local minutes = math.floor((seconds - hours * 3600) / 60) local remainingSeconds = seconds - hours * 3600 - minutes * 60 local ResTime = "" ResTime = ResTime .. ((hours > 0 or ShowHours) and string.format("%02d:", hours) or "") ResTime = ResTime .. ((minutes > 0 or hours > 0 or ShowHours or ShowMinutes) and string.format("%02d:", minutes) or "") ResTime = ResTime .. (ShowRemainingSeconds and string.format("%02.3f", remainingSeconds) or string.format("%02.0f", remainingSeconds)) return ResTime end ---@param AssetPath:string ---@param CallBackFunc:fun(LoadObject:UObject,resID:int32) ---@param Obj:table CallBackFunc拥有者 ---@param SaveAsset:bool 是否保存 function UGCSystemLibrary.AsyncLoadAsset(AssetPath, CallBackFunc, Obj, SaveAsset) if not UE.IsValid(UGCSystemLibrary.CacheAsset[AssetPath]) then local softObjPath = KismetSystemLibrary.MakeSoftObjectPath(AssetPath); STExtraBlueprintFunctionLibrary.GetAssetByAssetReferenceAsync(softObjPath, ObjectExtend.CreateDelegate(UGCGameSystem.GameState, function(LoadObject, resID) if CallBackFunc then if Obj ~= nil then CallBackFunc(Obj, LoadObject) else CallBackFunc(LoadObject) end end if UE.IsValid(LoadObject) and SaveAsset then UGCSystemLibrary.CacheAsset[AssetPath] = LoadObject end end), true); else if CallBackFunc then if Obj ~= nil then CallBackFunc(Obj, UGCSystemLibrary.CacheAsset[AssetPath]) else CallBackFunc(UGCSystemLibrary.CacheAsset[AssetPath]) end end end end ---@param AssetPath:string ---@param SaveAsset:bool 是否保存 function UGCSystemLibrary.LoadAsset(AssetPath, SaveAsset) if SaveAsset == nil then SaveAsset = true end if not UE.IsValid(UGCSystemLibrary.CacheAsset[AssetPath]) then local TargetAsset = UE.LoadObject(AssetPath) if SaveAsset and UE.IsValid(TargetAsset) then UGCSystemLibrary.CacheAsset[AssetPath] = TargetAsset end return TargetAsset else return UGCSystemLibrary.CacheAsset[AssetPath] end end --- 通过ItemID获取item类型 ---@param ItemID int ---@return ItemTypeID int function UGCSystemLibrary.GetItemTypeID(ItemID) return ItemID // 1000 end --- 输入PlayerKey获取活着的玩家,若玩家已死亡或者不存在PlayerKey对应的Pawn时则返回nil ---@param PlayerKey uint ---@return Pawn function UGCSystemLibrary.GetAlivePlayerPawnByPlayerKey(PlayerKey) local PlayerPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey) return (UE.IsValid(PlayerPawn) and PlayerPawn:IsAlive()) and PlayerPawn or nil end --- 最多循环加50次 UGCSystemLibrary.LoopAddItemCountMax = 50 UGCSystemLibrary.LoopAddItemHandle = nil UGCSystemLibrary.PlayerAddItemInfo = {} -- PlayerKey = {ItemID, Count, LoopNum} ---添加道具 ---生效范围:服务器 ---@return IsSucceed bool ---@param PlayerPawn PlayerPawn* @玩家角色 ---@param ItemID int @物品ID ---@param Count int @数量 function UGCSystemLibrary.AddItem(PlayerPawn, ItemID, Count) if UE.IsValid(PlayerPawn) then local bSucceed = UGCBackPackSystem.AddItem(PlayerPawn, ItemID, Count) if not bSucceed then UGCLogSystem.Log("[UGCSystemLibrary_AddItem]") if UGCSystemLibrary.PlayerAddItemInfo[PlayerPawn.PlayerKey] == nil then UGCSystemLibrary.PlayerAddItemInfo[PlayerPawn.PlayerKey] = {} end UGCSystemLibrary.PlayerAddItemInfo[PlayerPawn.PlayerKey][#UGCSystemLibrary.PlayerAddItemInfo[PlayerPawn.PlayerKey] + 1] = {ItemID = ItemID, Count = Count, LoopNum = 0} if UGCSystemLibrary.LoopAddItemHandle == nil then UGCSystemLibrary.LoopAddItemHandle = UGCEventSystem.SetTimerLoop(UGCGameSystem.GameState, function() local PlayerKeys = table.getKeys(UGCSystemLibrary.PlayerAddItemInfo) for _, PlayerKey in PlayerKeys do local ItemInfos = table.DeepCopy(UGCSystemLibrary.PlayerAddItemInfo[PlayerKey]) local TargetPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey) if UE.IsValid(TargetPawn) then for i = #ItemInfos, 1, 1 do bSucceed = UGCBackPackSystem.AddItem(TargetPawn, ItemInfos[i].ItemID, ItemInfos[i].Count) -- 成功加入或者超过添加次数则移除 if bSucceed then UGCSystemLibrary.PlayerAddItemInfo[PlayerKey][i] = nil else if ItemInfos[i].LoopNum >= UGCSystemLibrary.LoopAddItemCountMax then UGCLogSystem.LogError("[UGCSystemLibrary_AddItem] PlayerKey:%s,AddItem:%s Failue", tostring(PlayerKey), tostring(ItemInfos[i].ItemID)) else ItemInfos[i].LoopNum = ItemInfos[i].LoopNum + 1 end end end if #UGCSystemLibrary.PlayerAddItemInfo[PlayerKey] == 0 then UGCSystemLibrary.PlayerAddItemInfo[PlayerKey] = nil end else UGCSystemLibrary.PlayerAddItemInfo[PlayerKey] = nil end end if table.getCount(UGCSystemLibrary.PlayerAddItemInfo) == 0 then UGCEventSystem.StopTimer(UGCSystemLibrary.LoopAddItemHandle) end UGCLogSystem.Log("[UGCSystemLibrary_AddItem] Finish") end, 0.1 ) end end else UGCLogSystem.LogError("[UGCSystemLibrary_AddItem] PlayerPawn is nil") end end --- 判断物体是否可以看到玩家 ---@param ObjectContext 目标物体 ---@param EyePos 物体开始检测的位置 ---@param TargetPlayerPawn 目标玩家 ---@param LineTraceChannels 检测的通道,默认为{ECollisionChannel.ECC_WorldStatic, ECollisionChannel.ECC_WorldDynamic, ECollisionChannel.ECC_Pawn} function UGCSystemLibrary.CanSeePlayer(ObjectContext, EyePos, TargetPlayerPawn, LineTraceChannels) if not (UE.IsValid(ObjectContext) and UE.IsValid(TargetPlayerPawn)) then return end if LineTraceChannels == nil then LineTraceChannels = {ECollisionChannel.ECC_WorldStatic, ECollisionChannel.ECC_WorldDynamic, ECollisionChannel.ECC_Pawn} end -- UGCLogSystem.Log("[UGCSystemLibrary_CanSeePlayer] TargetPlayerPawn:%s", KismetSystemLibrary.GetObjectName(TargetPlayerPawn)) --local SkeletonSocketNames = {"head", "spine_01", "hand_l", "hand_r", "foot_r", "foot_l"} local PawnPos = TargetPlayerPawn:K2_GetActorLocation() local UpPawnPos = table.DeepCopy(PawnPos) local DownPawnPos = table.DeepCopy(PawnPos) UpPawnPos.Z = UpPawnPos.Z + 80 DownPawnPos.Z = DownPawnPos.Z - 80 --for i, SocketName in pairs(SkeletonSocketNames) do for i, EndPos in pairs({UpPawnPos, PawnPos, DownPawnPos}) do -- local BornSocketPos = TargetPlayerPawn.Mesh:GetSocketLocation(SocketName) --if BornSocketPos then ---@field LineTraceSingleForObjects fun(WorldContextObject:UObject,Start:FVector,End:FVector,ObjectTypes:ULuaArrayHelper,bTraceComplex:bool,ActorsToIgnore:ULuaArrayHelper,DrawDebugType:EDrawDebugTrace,OutHit:FHitResult,bIgnoreSelf:bool,TraceColor:FLinearColor,TraceHitColor:FLinearColor,DrawTime:float):bool,FHitResult local bSucceed, HitResult = KismetSystemLibrary.LineTraceSingleForObjects(ObjectContext, EyePos, EndPos, LineTraceChannels, false, {ObjectContext, }) if bSucceed then local HitActor = HitResult.Actor:Get() if HitActor == TargetPlayerPawn then return true else UGCLogSystem.Log("[UGCSystemLibrary_CanSeePlayer]HitActorName:%s", KismetSystemLibrary.GetObjectName(HitActor)) end end --else -- UGCLogSystem.LogError("[UGCSystemLibrary_CanSeePlayer] BornSocketPos is nil") --end end return false end function UGCSystemLibrary.GetAllPlayerKeys() local AllPC = UGCGameSystem.GetAllPlayerController() local Res = {} for i, v in pairs(AllPC) do Res[#Res + 1] = v.PlayerKey end return Res end --- Server执行设置第一人称FPP模式 function UGCSystemLibrary.SetFPPMode() UGCGameSystem.GameMode.IsGameModeFpp = 1 UGCGameSystem.GameState.IsFPPGameMode = true end --- Server获取在线玩家的PlayerKey function UGCSystemLibrary.GetOnlinePlayers() local AllController = UGCGameSystem.GetAllPlayerController() local Res = {} for i, v in pairs(AllController) do Res[#Res + 1] = v.PlayerKey end return Res end --- 通过类名销毁物体 --- 拾取物"PickUpWrapperActor" --- 死亡盒子"PlayerTombBox" function UGCSystemLibrary.RemoveActorFromClassName(ClassName) local PlayerTombBoxClass = ScriptGameplayStatics.FindClass(ClassName); if UE.IsValid(PlayerTombBoxClass) then UGCLogSystem.Log("[UGCSystemLibrary_RemoveActorFromClassName] %sClass is Valid", tostring(ClassName)) -- local PlayerTombBoxs = GameplayStatics.GetAllActorsOfClass(self, PlayerTombBoxClass, {}); local PlayerTombBoxs = ScriptGameplayStatics.GetActorsOfClass(UGCGameSystem.GameState, PlayerTombBoxClass, {}) --清空死亡盒子 for i, PlayerTombBox in ipairs(PlayerTombBoxs) do if PlayerTombBox ~= nil then PlayerTombBox:K2_DestroyActor(); end end else UGCLogSystem.LogError("[UGCSystemLibrary_RemoveActorFromClassName] %sClass is not Valid", tostring(ClassName)) end end --- Client --- 切换为自定义的跟随相机 --- @param Camera 摄像机 --- @param Arm 摄像机弹簧 function UGCSystemLibrary.ActivePlayerCameraByName(OwnerPawn, Camera, Arm) -- 自带的相机都不用了 UGCSystemLibrary.ForeachCamera(OwnerPawn, function(v) v:Deactivate(); end); UGCSystemLibrary.ForeachCameraArm(OwnerPawn, function(v) v:Deactivate(); end); if Camera then Camera:Activate(); end if Arm then Arm:Activate(); end end --- Client --- 设置玩家的摄像机为默认的摄像机 function UGCSystemLibrary.ActivePlayerDefaultCamera(OwnerPawn) -- 自带的相机都不用了 UGCSystemLibrary.ForeachCamera(function(v) v:Deactivate(); end); UGCSystemLibrary.ForeachCameraArm(function(v) v:Deactivate(); end); OwnerPawn.Camera:Activate(); OwnerPawn.CustomSpringArm:Activate(); end function UGCSystemLibrary.ForeachCamera(OwnerPawn, Callback) local ClassPath = "/Script/Engine.CameraComponent"; local Cls = LoadClass(ClassPath); local Comps = OwnerPawn:GetComponentsByClass(Cls); for _, v in pairs(Comps) do Callback(v); end end function UGCSystemLibrary.ForeachCameraArm(OwnerPawn, Callback) local ClassPath = "/Script/Engine.SpringArmComponent"; local Cls = LoadClass(ClassPath); local Comps = OwnerPawn:GetComponentsByClass(Cls); for _, v in pairs(Comps) do Callback(v); end end --- Server --- 从GameMode中获取玩家出生点控制器组件 function UGCSystemLibrary.GetPlayerStartManagerComponent() local PlayerStartManagerComponentClass = ScriptGameplayStatics.FindClass("PlayerStartManagerComponent"); if PlayerStartManagerComponentClass == nil then UGCLogSystem.LogError("[UGCSystemLibrary_GetPlayerStartManagerComponent] Error: Action_TeleportTeamPlayerToBornPoint:Execute PlayerStartManagerComponentClass is nil!") return nil; end return UGCGameSystem.GameMode:GetComponentByClass(PlayerStartManagerComponentClass); end --- Server --- 设置玩家是否可移动 function UGCSystemLibrary.SetPlayerIsMovable(PlayerController, IsMovable) if UE.IsValid(PlayerController) then UGCLogSystem.Log("[UGCSystemLibrary_SetPlayerIsMovable] PlayerController:%s", tostring(PlayerController.PlayerKey)) if IsMovable then -- 关闭电影模式,启用玩家移动 PlayerController:SetCinematicMode(false, false, false, true, false) else -- 开启电影模式,禁止玩家移动 PlayerController:SetCinematicMode(true, false, false, true, false) end else UGCLogSystem.LogError("[UGCSystemLibrary_SetPlayerIsMovable] PlayerController Is Not Valid") end end --- Server --- 设置所有玩家是否可移动 function UGCSystemLibrary.SetAllPlayerIsMovable(IsMovable) local TempPlayerControllers = UGCGameSystem.GetAllPlayerController(true) for _, PC in pairs(TempPlayerControllers) do UGCSystemLibrary.SetPlayerIsMovable(PC, IsMovable) end end --- Server --- 设置pawn是否可移动 function UGCSystemLibrary.SetPlayerPawnMovable(InPawn, IsMovable) UGCPawnSystem.DisabledPawnState(InPawn, EPawnState.Move, not IsMovable); UGCPawnSystem.DisabledPawnState(InPawn, EPawnState.Shoveling, not IsMovable); -- UGCPawnSystem.DisabledPawnState(InPawn, EPawnState.Jump, not IsMovable); UGCPawnSystem.DisabledPawnState(InPawn, EPawnState.GunFire, not IsMovable); UGCPawnSystem.DisabledPawnState(InPawn, EPawnState.HoldGrenade, not IsMovable); UGCPawnSystem.DisabledPawnState(InPawn, EPawnState.MeleeAttack, not IsMovable); end --- 补充满玩家的当前所有武器的子弹 function UGCSystemLibrary.FullAllWeaponBullet(PlayerPawn) if UE.IsValid(PlayerPawn) then for i, v in pairs(ShootWeaponEnums) do local Weapon = UGCWeaponManagerSystem.GetWeaponBySlot(PlayerPawn, v) if UE.IsValid(Weapon) then UGCGunSystem.EnableClipInfiniteBullets(Weapon, true) local MaxBulletNumInOneClip = UGCGunSystem.GetMaxBulletNumInOneClip(Weapon) Weapon:SetCurrentBulletNumInClipOnServer(MaxBulletNumInOneClip, true) end end end end --- 通过路径获取DataTable ---@param DataTablePath string ---@param ToNumberKey bool 是否将Key值转化为Number类型再返回 function UGCSystemLibrary.GetDataTableFromPath(DataTablePath, ToNumberKey) local ResDataTable = Gameplay.GetTable(DataTablePath) if ToNumberKey then local Res = {} for i, v in pairs(ResDataTable) do Res[tonumber(i)] = v end return Res else return ResDataTable end end --- 清除所有玩家的武器及配件 function UGCSystemLibrary.ClearAllPlayerWeapon() local AllPawn = UGCGameSystem.GetAllPlayerPawn() for i, PlayerPawn in pairs(AllPawn) do local AllItems = UGCBackPackSystem.GetAllItemData(PlayerPawn) for _, ItemInfo in pairs(AllItems) do local TypeID = UGCSystemLibrary.GetItemTypeID(ItemInfo.ItemID) UGCLogSystem.Log("[UGCSystemLibrary_ClearAllPlayerWeapon]ItemID:%s", tostring(ItemInfo.ItemID)) if TypeID > 100 and TypeID < 200 then UGCLogSystem.Log("[UGCSystemLibrary_ClearAllPlayerWeapon]TypeID:%s, ItemID:%s", tostring(TypeID), tostring(ItemInfo.ItemID)) UGCBackPackSystem.DropItem(PlayerPawn, ItemInfo.ItemID, ItemInfo.Count, true) end end end end --- 判断是否有玩家存活 function UGCSystemLibrary.HasAlivePlayer() local AllPK = UGCSystemLibrary.GetAllPlayerKeys() for i, PlayerKey in pairs(AllPK) do local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey) if UE.IsValid(Pawn) and Pawn:IsAlive() then return true end end return false end --- 获取存活的玩家数量 function UGCSystemLibrary.GetAlivePlayerCount() local Res = 0 local AllPK = UGCSystemLibrary.GetAllPlayerKeys() for i, PlayerKey in pairs(AllPK) do local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey) if UE.IsValid(Pawn) and Pawn:IsAlive() then Res = Res + 1 end end return Res end --- 获取其他队伍的ID ---@param TeamID uint 忽略的队伍ID ---@return TeamIDs table 其他队伍ID function UGCTeamSystem.GetOtherTeamIDs(TeamID) local TeamIDs = UGCTeamSystem.GetTeamIDs() local Res = {} for i, v in pairs(TeamIDs) do if v ~= TeamID then Res[#Res + 1] = v end end return Res end --- 获取其他队伍的玩家 ---@param TeamID uint 忽略的队伍ID ---@return PlayerKeys table 其他玩家PlayerKey function UGCTeamSystem.GetOtherTeamPlayerKeys(TeamID) local OtherTeamIDs = UGCTeamSystem.GetOtherTeamIDs(TeamID) local Res = {} for i, v in pairs(OtherTeamIDs) do local OtherPlayerKeys = UGCTeamSystem.GetPlayerKeysByTeamID(v) for _, PlayerKey in pairs(OtherPlayerKeys) do Res[#Res + 1] = PlayerKey end end return Res end --- 获取队伍成员PlayerKey ---@return PlayerKeys table 队伍玩家PlayerKey function UGCTeamSystem.GetTeammates(PlayerKey) local Res = {} local TeamID = UGCPlayerStateSystem.GetTeamID(PlayerKey) UGCLogSystem.Log("[UGCTeamSystem_GetTeammates] TeamID:%s", tostring(TeamID)) local Teammates = UGCTeamSystem.GetPlayerKeysByTeamID(TeamID) for i, v in pairs(Teammates) do Res[#Res + 1] = v end return Res end