2025-01-04 23:00:19 +08:00

553 lines
22 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.

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