UGCSystemLibrary = UGCSystemLibrary or {} UGCSystemLibrary.IsServer = nil -- 缓存的资产 UGCSystemLibrary.CacheAsset = {} ------------------------------------------------ 获取本地信息 ------------------------------------------------ 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 UGCSystemLibrary.DownloadImageCache = {} --- 下载图像至UImage ---@param Image UImage* ---@param URL string ---@param IsSave boolean function UGCSystemLibrary.DownloadImageToUImage(Image, URL, IsSave) if UE.IsValid(UGCSystemLibrary.DownloadImageCache[URL]) then Image:SetBrushFromTextureDynamic(UGCSystemLibrary.DownloadImageCache[URL]) else UGCSystemLibrary.DownloadImage(URL, true, function(Texture) if UE.IsValid(Texture) then Image:SetBrushFromTextureDynamic(Texture) if IsSave then UGCSystemLibrary.DownloadImageCache[URL] = Texture end else UGCLogSystem.LogError("[UGCSystemLibrary_DownloadImageToUImage] Download Texture Failure. URL: %s", URL) end end ) end end ---------------------------------------- Load End ---------------------------------------- -- OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult 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 --- 通过路径获取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 --- 通过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 --- 通过类名销毁物体 --- 拾取物"PickUpWrapperActor" --- 死亡盒子"PlayerTombBox" --- 已投出的投掷物 "EliteProjectile" function UGCSystemLibrary.RemoveActorFromClassName(ClassName) local PlayerTombBoxClass = ScriptGameplayStatics.FindClass(ClassName); if UE.IsValid(PlayerTombBoxClass) then 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 --- 清除PickUpActor 忽略传入的ItemID function UGCSystemLibrary.ClearPickUpActor(IgnoreItemIDs) if IgnoreItemIDs == nil then IgnoreItemIDs = {} end local PickUpActorClass = ScriptGameplayStatics.FindClass("PickUpWrapperActor"); if UE.IsValid(PickUpActorClass) then local PickUpActors = ScriptGameplayStatics.GetActorsOfClass(UGCGameSystem.GameState, PickUpActorClass, {}) -- for i, PickUpActor in ipairs(PickUpActors) do if PickUpActor ~= nil then local ItemID = PickUpActor.DefineID.TypeSpecificID -- UGCLogSystem.Log("[UGCSystemLibrary_ClearPickUpActor]ItemID:%s", tostring(ItemID)) if not table.hasValue(IgnoreItemIDs, ItemID) then PickUpActor:K2_DestroyActor(); end end end else UGCLogSystem.LogError("[UGCSystemLibrary_ClearPickUpActor] PickUpWrapperActor Class is not Valid") end end -- [PlayerKey] = {Handle, RespawnGameTime} UGCSystemLibrary.RespawnPlayerHandlesInfo = {} -- 重置玩家 function UGCSystemLibrary.RespawnPlayer(PlayerKey, Time) -- 不进行瞬时重生,防止同一帧重复调用 if Time == nil then Time = 0.1 end local NowTime = UGCSystemLibrary.GetGameTime() local RespawnHandleInfo = UGCSystemLibrary.RespawnPlayerHandlesInfo[PlayerKey] if RespawnHandleInfo then -- 若多次调用则仅采用长的复活时间 if Time + NowTime <= RespawnHandleInfo.RespawnGameTime then return end end -- 删除之前的复活Handle if UGCSystemLibrary.RespawnPlayerHandlesInfo[PlayerKey] then UGCEventSystem.StopTimer(UGCSystemLibrary.RespawnPlayerHandlesInfo[PlayerKey].Handle) end UGCSystemLibrary.RespawnPlayerHandlesInfo[PlayerKey] = {} -- 构建新的符合Handle UGCSystemLibrary.RespawnPlayerHandlesInfo[PlayerKey].Handle = UGCEventSystem.SetTimer(UGCGameSystem.GameState, function() UGCSystemLibrary.RespawnPlayerHandlesInfo[PlayerKey] = nil local PlayerPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey) if UE.IsValid(PlayerPawn) then PlayerPawn:K2_DestroyActor() end UGCGameSystem.RespawnPlayer(PlayerKey) end, Time) UGCSystemLibrary.RespawnPlayerHandlesInfo[PlayerKey].RespawnGameTime = Time + NowTime 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.SetAllPawnMovable(IsMovable) local AllPawn = UGCGameSystem.GetAllPlayerPawn() for i, v in pairs(AllPawn) do UGCSystemLibrary.SetPlayerPawnMovable(v, IsMovable) end 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 --------------------------------------------- 准备状态 --------------------------------------------- --[[ 需要在Pawn内的ReceivePossessed函数中加入 function UGCPlayerPawn:ReceivePossessed(NewController) if UGCSystemLibrary.GetIsPreparationState() then UGCSystemLibrary.SetPlayerPawnMovable(self, false) end end ]] -- 准备时间 UGCSystemLibrary.PreparationTime = 0; -- 是否为准备阶段 UGCSystemLibrary.IsPreparationState = false; --- Server --- 进入准备状态 function UGCSystemLibrary.EnterPreparationState() UGCSystemLibrary.IsPreparationState = true if UGCEventSystem.PreparationStateHandle then UGCEventSystem.StopTimer(UGCEventSystem.PreparationStateHandle) end UGCEventSystem.PreparationStateHandle = UGCEventSystem.SetTimer(UGCGameSystem.GameState, function() UGCSystemLibrary.SetAllPawnMovable(true) UGCSystemLibrary.IsPreparationState = false UGCEventSystem.PreparationStateHandle = nil end, UGCSystemLibrary.PreparationTime) end function UGCSystemLibrary.GetIsPreparationState() return UGCSystemLibrary.IsPreparationState end function UGCSystemLibrary.SetPreparationTime(InPreparationTime) if InPreparationTime >= 0 then UGCSystemLibrary.PreparationTime = InPreparationTime end end ------------------------------------------- 准备状态 End ------------------------------------------- --- 获取所有的PlayerKey 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 --- 给玩家的所有武器补满当前弹夹子弹 function UGCSystemLibrary.PlayerFullBullet(InPlayerKey) local TargetPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(InPlayerKey) if UE.IsValid(TargetPawn) then --补满子弹 TargetPawn:SetAllWeaponBulletNumToMaxOnServer(true, false) for i, v in pairs(ShootWeaponEnums) do local Weapon = UGCWeaponManagerSystem.GetWeaponBySlot(TargetPawn, v) if UE.IsValid(Weapon) then UGCGunSystem.EnableClipInfiniteBullets(Weapon, true) local MaxBulletNumInOneClip = UGCGunSystem.GetMaxBulletNumInOneClip(Weapon) Weapon:SetCurrentBulletNumInClipOnServer(MaxBulletNumInOneClip, true) -- 玩家离开换弹状态 if UE.IsValid(TargetPawn) then UGCPawnSystem.LeavePawnState(TargetPawn, EPawnState.Roload) end end end end end --- 重置和平里的击杀和助攻数 function UGCSystemLibrary.ResetAllPlayerKillsAndAssists() local AllPS = UGCGameSystem.GetAllPlayerState() for i, PS in pairs(AllPS) do PS.Kills = 0 PS.Assists = 0 PS.KillPlayerNum = 0 DOREPONCE(PS,"Kills") DOREPONCE(PS,"Assists") DOREPONCE(PS,"KillPlayerNum") end end --- 获取当天为一年中的第几天 function UGCSystemLibrary.GetDayOfYear() local now = os.time() local year = os.date("*t", now).year local startOfYear = os.time{year = year, month = 1, day = 1} local days = os.difftime(now, startOfYear) / (24 * 60 * 60) return math.floor(days) + 1 -- 加1是因为Lua里月份和天数是从1开始计数的 end --- 获取现实时间秒 function UGCSystemLibrary.GatRealTimeSeconds() return os.time() end --- 获取UTF-8字符串的长度 function UGCSystemLibrary.utf8len(s) local len = 0 local i = 1 local c = string.byte(s, i) while c do if c > 0 and c <= 127 then i = i + 1 elseif c >= 194 and c <= 223 then i = i + 2 elseif c >= 224 and c <= 239 then i = i + 3 elseif c >= 240 and c <= 244 then i = i + 4 else return nil -- invalid UTF-8 end len = len + 1 c = string.byte(s, i) end return len end --- 裁剪UTF-8字符串 function UGCSystemLibrary.utf8sub(s, startChar, numChars) local startIndex = 1 while startChar > 1 do local c = string.byte(s, startIndex) if not c then return "" end if c > 0 and c <= 127 then startIndex = startIndex + 1 elseif c >= 194 and c <= 223 then startIndex = startIndex + 2 elseif c >= 224 and c <= 239 then startIndex = startIndex + 3 elseif c >= 240 and c <= 244 then startIndex = startIndex + 4 else return "" -- invalid UTF-8 end startChar = startChar - 1 end local currentIndex = startIndex while numChars > 0 and currentIndex <= #s do local c = string.byte(s, currentIndex) if not c then break end if c > 0 and c <= 127 then currentIndex = currentIndex + 1 elseif c >= 194 and c <= 223 then currentIndex = currentIndex + 2 elseif c >= 224 and c <= 239 then currentIndex = currentIndex + 3 elseif c >= 240 and c <= 244 then currentIndex = currentIndex + 4 else break -- invalid UTF-8 end numChars = numChars - 1 end return s:sub(startIndex, currentIndex - 1) end function UGCSystemLibrary.remove_punctuation(s) -- 定义要移除的标点符号 local punctuation = { ["。"] = true, [","] = true, ["!"] = true, ["?"] = true, ["."] = true, [","] = true, ["!"] = true, ["?"] = true, [";"] = true, [":"] = true, [";"] = true, [":"] = true, ["、"] = true, ["("] = true, [")"] = true, ["("] = true, [")"] = true, ["【"] = true, ["】"] = true, ["["] = true, ["]"] = true, ["“"] = true, ["”"] = true, ["\""] = true, ["'"] = true, ["\n"] = true, ["\r"] = true, } local result = {} local i = 1 local c = string.byte(s, i) while c do local char_len = 1 if c > 0 and c <= 127 then char_len = 1 elseif c >= 194 and c <= 223 then char_len = 2 elseif c >= 224 and c <= 239 then char_len = 3 elseif c >= 240 and c <= 244 then char_len = 4 else return "" -- invalid UTF-8 end local char = s:sub(i, i + char_len - 1) print(char .. "--") if not punctuation[char] then table.insert(result, char) end i = i + char_len c = string.byte(s, i) end return table.concat(result) end --- 移除标点符号 function UGCSystemLibrary.remove_character(s, char_to_remove) local result = {} local i = 1 local c = string.byte(s, i) while c do local char_len = 1 if c > 0 and c <= 127 then char_len = 1 elseif c >= 194 and c <= 223 then char_len = 2 elseif c >= 224 and c <= 239 then char_len = 3 elseif c >= 240 and c <= 244 then char_len = 4 else return "" -- invalid UTF-8 end UGCLogSystem.Log("[UGCSystemLibrary_remove_character] c:%s", c) local char = s:sub(i, i + char_len - 1) if char ~= char_to_remove then UGCLogSystem.Log("[UGCSystemLibrary_remove_character] Add") table.insert(result, char) end i = i + char_len c = string.byte(s, i) end return table.concat(result) end --- 概率函数,输入为概率列表,输出为依据概率随机出来的索引 function UGCSystemLibrary.RandomIndex(probabilities) local sum = 0 local cumulative = {} -- 计算概率总和,并构建累积概率列表 for i, prob in ipairs(probabilities) do sum = sum + prob cumulative[i] = sum end -- 生成一个0到sum之间的随机数 local randomValue = math.random() * sum -- 根据随机数选择对应的索引 for i, cumProb in ipairs(cumulative) do if randomValue <= cumProb then return i end end 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