GlobalFunctions = GlobalFunctions or {} GlobalFunctions.IsServer = nil GlobalFunctions.IsShipping = nil function UE.LogTag() if GlobalFunctions.IsServer == nil then GlobalFunctions.IsServer = UGCGameSystem.IsServer() end local LogStr = "[UGCLog]" if GlobalFunctions.IsServer == true then LogStr = LogStr .. "[Server]" else LogStr = LogStr .. "[Client]" end if GameDataManager and UE.IsValid(GameDataManager.GetLocalPlayerState()) then LogStr = LogStr .. "[" .. GameDataManager.GetLocalPlayerState().PlayerKey .. "]" end return LogStr end function UE.Print(Log) print(Log) end function UE.Log(Fmt, ...) local LogStr = UE.LogTag()..string.format(Fmt, ...) UE.Print(LogStr) end function UE.LogError(Fmt, ...) local LogStr = UE.LogTag().."[Error]"..string.format(Fmt, ...) UE.Print(LogStr) end function UE.LogUGC(Fmt, ...) local LogStr = UE.LogTag()..string.format(Fmt, ...) ugcprint(LogStr) end function GlobalFunctions.GetAttributeDisplayType(InAttributeName) for Name, Config in pairs(GlobalConfigs.Attributes) do if Name == InAttributeName then return Config.Type end end return EAttributeDisplayType.Int end ---获取武器蓝图路径 ---@return WeaponClassPath string @蓝图路径 ---@param ID int function GlobalFunctions.GetWeaponClassPath(ID) local WeaponData = Tables.Weapon[ID] if WeaponData ~= nil then return WeaponData.ClassPath end return nil end ---获取武器名称 ---@return WeaponName string @武器名称 ---@param ID int function GlobalFunctions.GetWeaponName(ID) local WeaponData = Tables.Weapon[ID] if WeaponData ~= nil then return WeaponData.WeaponName end return nil end ---发送自定义Action ---生效范围:S ---@param EventName string @事件名称 ---@param EventWaitTime int @事件等待时间 function GlobalFunctions.SendEventNextSecond(EventName, EventWaitTime) if EventName == "" then UE.Log("[GlobalFunctions.SendEventNextSecond] Not SendEvent") return end local GameState = UGCGameSystem.GameState if not GameState then return end if GameState.ActionHandles == nil then GameState.ActionHandles = {} GameState.ActionHandleIndex = 0 end GameState.ActionHandleIndex = GameState.ActionHandleIndex + 1 local HandleIndex = GameState.ActionHandleIndex UE.Log("[GlobalFunctions.SendEventNextSecond] SendEvent: %s, WaitTime: %s", EventName, tostring(EventWaitTime)) local ActionHandle = { Delegate = nil, Timer = nil, } ActionHandle.Delegate = ObjectExtend.CreateDelegate(GameState, function() if type(EventWaitTime) == "number" and EventWaitTime > 0 then UGCGameSystem.SendModeCustomEvent(EventName, EventWaitTime) else UGCGameSystem.SendModeCustomEvent(EventName) end if GameState.ActionHandles[HandleIndex] and GameState.ActionHandles[HandleIndex].Delegate then ObjectExtend.DestroyDelegate(GameState.ActionHandles[HandleIndex].Delegate) GameState.ActionHandles[HandleIndex].Delegate = nil end if GameState.ActionHandles[HandleIndex] and GameState.ActionHandles[HandleIndex].Timer then KismetSystemLibrary.K2_ClearTimerHandle(GameState, GameState.ActionHandles[HandleIndex].Timer) GameState.ActionHandles[HandleIndex].Timer = nil end GameState.ActionHandles[HandleIndex] = nil end) ActionHandle.Timer = KismetSystemLibrary.K2_SetTimerDelegateForLua(ActionHandle.Delegate, GameState, 1, false) GameState.ActionHandles[HandleIndex] = ActionHandle end ------------------------------------------------------------------------------------ local RootPackagePath = UGCMapInfoLib.GetRootLongPackagePath() function 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 ------------------------------------------------------------------------------------ ---获取表元素个数 function table.getCount(t) if type(t) ~= "table" then return -1 end local Length = 0 for i, v in pairs(t) do Length = Length + 1 end return Length end ---获取表中所有的Key function table.getKeys(t) if type(t) ~= "table" then return {} end local keys = {} for k,v in pairs(t) do keys[#keys + 1] = k end return keys end ---获取对应元素的Index function table.getIndex(t, v) if type(t) ~= "table" then return nil end for index, value in pairs(t) do if value == v then return index end end return nil end ---获取表中是否有对应Key function table.hasKey(t, k) if type(t) ~= "table" then return false end for key, value in pairs(t) do if k == key then return true end end return false end ---按Key删除表中元素 function table.removeKey(t, k) if t == nil then return nil end local v = t[k] t[k] = nil return v end ---获取表中是否有对应的Value function table.hasValue(t, value) if t == nil then return false end for k, v in pairs(t) do if v == value then return true end end return false end ---按Value删除表中元素 function table.removeValue(t, value, removeAll) local deleteNum = 0 local i = 1 local max = table.getCount(t) while i <= max do if t[i] == value then table.remove(t,i) deleteNum = deleteNum + 1 i = i - 1 max = max - 1 if not removeAll then break end end i = i + 1 end return deleteNum end ---返回是否是空表 function table.isEmpty(t) if type(t) ~= "table" then return true end return next(t) == nil end function table.Swap(t, i, j) if type(t) ~= "table" then return end local temp = t[i] t[i] = t[j] t[j] = temp end -- 针对 t1, t2 做插值,注意:t1 是 t2 的子集 function table.Diff(t1, t2) local val = {} for i, v in pairs(t2) do if t1[i] == nil then val[i] = v end end return val end --- table随机(洗牌算法) function table.Rand(t) if type(t) ~= "table" then return false end for i = 1, #t - 1 do local SwapIndex = math.random(i + 1, #t) table.Swap(t, i, SwapIndex) end end ---@param header string ---@param tbl table ---@param maxIndent integer ---❉ 递归打印table,默认并且最多支持打印5层Table嵌套 function table.print(header, tbl, maxIndent) local logFunc = UE.Log local maxIndent = maxIndent or 5 maxIndent = math.max(1,maxIndent) maxIndent = math.min(5,maxIndent) if tbl == nil or type(tbl) ~= 'table' then logFunc("table.print input arg is not a table type!") return end logFunc(header) logFunc("========= content of table(\"" .. tostring(tbl) .."\") ===========") local function printInternal(t, prevKey, indent) local indent = indent if indent > maxIndent then logFunc(prevKey .. "Over " .. maxIndent .." indents,omit print...") return end for key, value in pairs(t) do local printKey = prevKey .. "." .. tostring(key) logFunc(printKey .. " = " .. tostring(value)) if key ~= "_outer" and type(value) == 'table' then if next(value) == nil then logFunc(printKey .. " = " .. "{ }") else printInternal(value, printKey, indent + 1) end end end end printInternal(tbl, "", 0) end ---clamp ---@param v number @number ---@param Min number @min ---@param Max number @max ---@return number @clamp v between Min and Max function math.clamp(v, Min, Max) Min = math.min(Min, Max) Max = math.max(Min, Max) if v < Min then return Min end if v > Max then return Max end return v end ---clamp ---@param a number @First number to compare ---@param b number @Second number to compare ---@param Tolerance number @Maximum allowed difference for considering them as 'nearly equal' ---@return boolean @true if a and b are nearly equal function math.isNearlyEqual(a, b, Tolerance) if Tolerance == nil then Tolerance = 0.01 end return math.abs(a - b) <= Tolerance end --- @param n integer 正整数 function math.pow(x, n) local val = x for i = 1, n do val = val * val end return val end ---字符串分割 function string.split(InStr, sep) local sep, fields = sep or "\t",{} local pattern = string.format("([^%s]+)", sep) InStr:gsub(pattern, function(c) fields[#fields+1] = c end) return fields end ---字符串直接转Number function string.splitToNumber(InStr, sep) local sep, fields = sep or "\t",{} local pattern = string.format("([^%s]+)", sep) InStr:gsub(pattern, function(c) fields[#fields+1] = tonumber(c) end) return fields end ---------------------------------For Items--------------------------------- ---11111 ---对于武器配件来说 ---第一位:大类 1 ---第二位:物品类型 1~5 ---第三位:所属武器类型 1~6 ---第四位:物品品质 1~4 ---第五位:物品伤害类型 0 --- ---对于技能书来说 ---第一位:大类 2 ---第二、三位:技能类型 01~99 ---第四位:品质 1~4 ---第五位:伤害类型 0 --- ---对于石头来说 ---第一位:大类 3 ---第二位:具体分类 1~2 ---第三四五位:保留字段 000 --- ---以下是武器配件的方法 ---获取品质,对应 Tables.QualityInfo function GetItemQualityLevel(InItemId) return (InItemId // 10) % 10 - 1 end ---获取物品所属武器类型,注意第一个是手枪,因此不需要 - 1 function GetItemWeaponTypeByItemId(InItemId) return (InItemId // 100) % 10 end ---获取物品类型,此处返回的是 1-5,如果要对应 Enum,需要再 - 1 function GetItemTypeByItemId(InItemId) local val = InItemId // 10000 -- 对应的是 EItemType if val == 1 then return (InItemId // 1000) % 10 - 1 elseif val == 2 then return EItemType.SkillBook elseif val == 3 then if InItemId // 1000 == 31 then return EItemType.ScouringStone elseif InItemId // 1000 == 32 then return EItemType.SubstituteStone end end print(string.format("[GetItemTypeByItemId] 此时 ItemId 有问题,ItemId = %d", InItemId)) end function GetSkillIdByItemId(InItemId) if InItemId < 20000 or InItemId > 29999 then return nil end return InItemId % 10000 // 100 end ---获取物品大类,都是对应 Enum: EDropItemSet function GetItemGrantTypeById(InItemId) return (InItemId // 10000) - 1 end function GetItemDamageTypeByItemId(InItemId) return (InItemId % 10) end function IsWeaponPartItem(InItemId) if InItemId == nil then return false end local Id = InItemId // 10000 return Id == EDropItemSet.WeaponParts + 1 end function IsSkillBookItem(InItemData) local Id = InItemData.ItemID // 10000 return Id == EDropItemSet.SkillBooks + 1 end function IsStoneItem(InItemData) local Id = InItemData.ItemID // 10000 return Id == EDropItemSet.Stones + 1 end function GenerateSkillBookData(SkillType) local RateTable = { [1] = {Min = 1, Max = 85}, [2] = {Min = 86, Max = 98}, [3] = {Min = 99, Max = 100}, } local Rand = math.random(1, 100) local ResultQuality = -1 for Quality, Rates in pairs(RateTable) do if Rand >= Rates.Min and Rand <= Rates.Max then ResultQuality = Quality break end end local StartSkillName = ESkillName.Counter local EndSkillName = ESkillName.Bombing if SkillType ~= nil then --刷出制定类型的技能(主动/被动) if SkillType == ESkillType.Passive then EndSkillName = ESkillName.Scabbing elseif SkillType == ESkillType.Active then StartSkillName = ESkillName.DeathStrike end end local SkillNamePool = {} for i = StartSkillName, EndSkillName do table.insert(SkillNamePool, i) end local ResultSkillName = SkillNamePool[math.random(1, #SkillNamePool)] local ItemData = { -- 此处需要修改,中间两位是具体生成的 ItemID = 20000 + ResultQuality * 10 + ResultSkillName * 100, ItemType = EItemType.SkillBook, Quality = ResultQuality, Count = 1, } UE.Log("DropItem: ItemType = %d, ItemType = %d, Quality = %d", ItemData.ItemID, ItemData.ItemType, ItemData.Quality) return ItemData end function GenerateWeaponPartData() local WeaponPartTypeRateTable = { [EItemType.Muzzle] = {Min = 1, Max = 20}, [EItemType.Grip] = {Min = 21, Max = 40}, [EItemType.Mag] = {Min = 41, Max = 60}, [EItemType.Stock] = {Min = 61, Max = 80}, [EItemType.Scope] = {Min = 81, Max = 100}, } local Rand1 = math.random(1, 100) local ResultItemType = -1 for ItemType, Rates in pairs(WeaponPartTypeRateTable) do if Rand1 >= Rates.Min and Rand1 <= Rates.Max then ResultItemType = ItemType break end end local QualityRateTable = { [1] = {Min = 1, Max = 95}, [2] = {Min = 96, Max = 99}, [3] = {Min = 100, Max = 100}, } local Rand2 = math.random(1, 100) local ResultQuality = -1 for Quality, Rates in pairs(QualityRateTable) do if Rand2 >= Rates.Min and Rand2 <= Rates.Max then ResultQuality = Quality break end end local WeaponClassTypeRateTable = { [EWeaponClassType.WT_ShotGun] = {Min = 1, Max = 4}, [EWeaponClassType.WT_MachineGun] = {Min = 5, Max = 8}, [EWeaponClassType.WT_SubmachineGun] = {Min = 9, Max = 12}, [EWeaponClassType.WT_ShooterRifle] = {Min = 13, Max = 16}, [EWeaponClassType.WT_AssaultRifle] = {Min = 17, Max = 20}, [EWeaponClassType.WT_Sniper] = {Min = 21, Max = 24}, } local Rand3 = math.random(1, 24) local ResultWeaponClassType = -1 for WeaponClassType, Rates in pairs(WeaponClassTypeRateTable) do if Rand3 >= Rates.Min and Rand3 <= Rates.Max then ResultWeaponClassType = WeaponClassType break end end local ItemData = { ItemID = 10000 + (ResultItemType + 1) * 1000 + ResultWeaponClassType * 100 + ResultQuality * 10, ItemType = ResultItemType, Quality = ResultQuality, Count = 1, WeaponClassType = ResultWeaponClassType } UE.Log("DropItem: ItemType = %d, ItemType = %d, Quality = %d, WeaponClassType = %d", ItemData.ItemID, ItemData.ItemType, ItemData.Quality, ItemData.WeaponClassType) return ItemData end function GenerateStoneData() local RateTable = { [EItemType.SubstituteStone] = {Min = 1, Max = 100}, [EItemType.ScouringStone] = {Min = -1, Max = -100}, } local Rand = math.random(1, 100) local ResultItemType = -1 for ItemType, Rates in pairs(RateTable) do if Rand >= Rates.Min and Rand <= Rates.Max then ResultItemType = ItemType break end end local ItemData = { ItemID = ResultItemType == EItemType.ScouringStone and 31000 or 32000, ItemType = ResultItemType, Quality = 1, Count = 1, } UE.Log("DropItem: ItemType = %d, ItemType = %d, Quality = %d", ItemData.ItemID, ItemData.ItemType, ItemData.Quality) return ItemData end function GenerateDropItemData() local RateTable = { [EDropItemSet.SkillBooks] = {Min = 1, Max = 95}, -- 默认不需要这个 --[EDropItemSet.WeaponParts] = {Min = -100, Max = -10}, [EDropItemSet.Stones] = {Min = 96, Max = 100}, } local Rand = math.random(1, 100) local ResultItemSet = -1 for ItemSet, Rates in pairs(RateTable) do if Rand >= Rates.Min and Rand <= Rates.Max then ResultItemSet = ItemSet break end end if ResultItemSet == EDropItemSet.WeaponParts then return GenerateWeaponPartData() elseif ResultItemSet == EDropItemSet.SkillBooks then return GenerateSkillBookData() else return GenerateStoneData() end --return GenerateSkillBookData() end --创建随机词条 function RandomWeaponProperty(InVal) -- 从200 中进行随机 math.randomseed(KismetSystemLibrary.GetGameTimeInSeconds(InVal) + math.random()) --这是计算 200 local Val = math.random(1,200) local WeaponMainPropIndex = 0 for i = 1, 16 do if Val > Tables.WeaponPropertyConfig[i].ProbabilityMin and Val <= Tables.WeaponPropertyConfig[i].ProbabilityMax then WeaponMainPropIndex = i break end end local MinVal = Tables.WeaponPropertyConfig[WeaponMainPropIndex].RandomMin local MaxVal = Tables.WeaponPropertyConfig[WeaponMainPropIndex].RandomMax math.randomseed(KismetSystemLibrary.GetGameTimeInSeconds(InVal)) --返回属性的具体值 local c = math.random() * (MaxVal - MinVal) + MinVal return WeaponMainPropIndex, c end --- @return boolean 是否可以随机到 function math.RandomValue(InPercent) if InPercent > 1 then InPercent = InPercent * 0.01 end local RandomNum = math.random() if RandomNum < InPercent then return true end return false end function table.logTree(InTable, Addtions) -- 首先检测一下是否是table if Addtions == nil then Addtions = '' end local RetStr = Addtions if type(InTable) == 'table' then for i, v in pairs(InTable) do RetStr = RetStr .. "k: " .. tostring(i) .. '\t'; RetStr = RetStr .. "v: " if type(v) == 'table' then RetStr = RetStr .. '\ttype:table\n' RetStr = RetStr .. table.logTree(v, "\t" .. Addtions) RetStr = RetStr .. '\n' else RetStr = RetStr .. tostring(v) .. '\t'; end -- RetStr = RetStr ..'\n' end else RetStr = tostring(InTable) end return RetStr .. '\n'; end