UGCProjects/TwoOnTwo/Script/Global/System/UGCSystemLibrary.lua
2025-02-02 16:26:56 +08:00

722 lines
27 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 = {}
------------------------------------------------ 获取本地信息 ------------------------------------------------
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