特效工程

This commit is contained in:
lantiannb 2025-01-09 13:36:39 +08:00
parent eee043b70d
commit 47093c4269
91 changed files with 3642 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

@ -0,0 +1,71 @@
[Root]
ProjectDisplayName=FX_Preview
ProjectDescription=FX_Preview
ProjectName=FX_Preview
ProjectTrueName=476869D89E45FE63A6DBF94A8DF5E10CF1E4A168214DF9FA013EFC1D81AC60CF
ProjectShortPath=/FX_Preview/
StartMapName=/FX_Preview/UGCmap
MapMode=0
bIsBigWorld=0
Version=1.29.13.13030
UpdateVersion=5
GameModePath=/FX_Preview/Asset/Blueprint/UGCGameMode.UGCGameMode_C
DefaultLevelDirectorPath=/Asset/Blueprint/UGCLevelDirector.UGCLevelDirector_C
[MatchSetting]
NumberOfTeams=1
TeamPlayers=1
bEnableChat=0
bEnableRoomChat=0
ChannelName=全部
RoomName=全部
bEnablePrivateChat=0
bEnableTeamChat=0
bShowMessage=0
bMessageDisappear=0
MessageLifetime=0.0
MaxMessageLines=6
bEnableSystemChannel=0
bEnableChatBubble=0
BubbleLifetime=10
MatchMethod=0
InitialScore=2000
MinScore=0
MaxScore=4000
RankDensity=100
BeyondRankTime=10
BeyondRankNum=10
TeamScoreCalculation=0
bUseMultiModeMatchSetting=0
MultiModeSettingNum=0
[MiniMap]
ZoomRatios=100
SliderExpandRatios=100
UserDefineMapPath=0
[SwitchesInMaps]
SwitchesInMaps=((Key="r.Mobile.EnableIBL",Value=0),(Key="s.StreamableDelegateLimitCount",Value=0),(Key="s.StreamableDelegateLimitTime",Value=0.001),(Key="r.mobile.HZBOcclusion",Value=0),(Key="r.mobile.allowsoftwareocclusion",Value=1),(Key="AnimDynamicStateFlipSmoothFrame",Value=5))
[PlayBinding]
PlayBindingArray=[]
[JobOption]
LastJobId=-1
LastWindowsJobId=-1
LastAndroidJobId=-1
LastIOSJobId=-1
PakOnly=0
LastSkipBake=False
LastTargetPlatform=LinuxServer
[UGCUploadOption]
PlatformIndex=0
SkipBake=False
TargetPlatform=LinuxServer+WindowsNoEditor+Android_ETC2+IOS+OpenHarmony_ETC2
[DebugSettings]
bRoomOB=0
TeamPlayers=1,0;1,0;1,0;

View File

@ -0,0 +1,42 @@
---@class BP_PreViewFXActor_C:AActor
---@field DynamicTextRender UDynamicTextRenderComponent
---@field DefaultSceneRoot USceneComponent
---@field MuzzleParticle UParticleSystem
---@field KillParticle UParticleSystem
---@field BulletParticle UParticleSystem
---@field HitParticle UParticleSystem
---@field KillParticleOffsetTF FTransform
--Edit Below--
local BP_PreViewFXActor = {}
--[[
function BP_PreViewFXActor:ReceiveBeginPlay()
BP_PreViewFXActor.SuperClass.ReceiveBeginPlay(self)
end
--]]
--[[
function BP_PreViewFXActor:ReceiveTick(DeltaTime)
BP_PreViewFXActor.SuperClass.ReceiveTick(self, DeltaTime)
end
--]]
--[[
function BP_PreViewFXActor:ReceiveEndPlay()
BP_PreViewFXActor.SuperClass.ReceiveEndPlay(self)
end
--]]
--[[
function BP_PreViewFXActor:GetReplicatedProperties()
return
end
--]]
--[[
function BP_PreViewFXActor:GetAvailableServerRPCs()
return
end
--]]
return BP_PreViewFXActor

View File

@ -0,0 +1,32 @@
---@class UGCGameMode_C:BP_UGCGameBase_C
--Edit Below--
local UGCGameMode = {};
-- 射击枪械槽类型
ShootWeaponEnums = {
ESurviveWeaponPropSlot.SWPS_MainShootWeapon1,
ESurviveWeaponPropSlot.SWPS_MainShootWeapon2,
ESurviveWeaponPropSlot.SWPS_SubShootWeapon,
};
function UGCGameMode:ReceiveBeginPlay()
UGCEventSystem.SetTimerLoop(UGCGameSystem.GameState, function()
local AllPlayerPawn = UGCGameSystem.GetAllPlayerPawn()
for i, PlayerPawn in pairs(AllPlayerPawn) do
for k, ShootWeaponEnum in pairs(ShootWeaponEnums) do
local Weapon = UGCWeaponManagerSystem.GetWeaponBySlot(PlayerPawn, ShootWeaponEnum)
if UE.IsValid(Weapon) then
UGCGunSystem.EnableClipInfiniteBullets(Weapon, true)
end
end
end
end, 0.5
)
end
-- function UGCGameMode:ReceiveTick(DeltaTime)
-- end
-- function UGCGameMode:ReceiveEndPlay()
-- end
return UGCGameMode;

View File

@ -0,0 +1,44 @@
---@class UGCGameState_C:BP_UGCGameState_C
--Edit Below--
UGCGameSystem.UGCRequire('Script.Common.ue_enum_custom')
UGCGameSystem.UGCRequire('Script.Global.Global')
local UGCGameState = {};
function UGCGameState:ReceiveBeginPlay()
self.IsShowDeadBox = false;
UGCEventSystem.AddListener(EventEnum.PlayerDeathInfo, self.RespawnPlayer, self)
end
function UGCGameState:RespawnPlayer(DeadPlayerKey)
UGCEventSystem.SetTimer(self, function() UGCGameSystem.RespawnPlayer(DeadPlayerKey) end, 4)
end
function UGCGameState:GetPreViewFXActor()
if not UE.IsValid(self.PreViewActor) then
self.PreViewActor = UGCSystemLibrary.GetUniqueInstanceFromPath(UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/SceneActor/BP_PreViewFXActor.BP_PreViewFXActor_C'))
end
return self.PreViewActor
end
function UGCGameState:SpawnParticleAtPos(Pos)
local TempPreViewActor = self:GetPreViewFXActor()
if UE.IsValid(TempPreViewActor) then
Pos = {
X = Pos.X + TempPreViewActor.KillParticleOffsetTF.Translation.X,
Y = Pos.Y + TempPreViewActor.KillParticleOffsetTF.Translation.Y,
Z = Pos.Z + TempPreViewActor.KillParticleOffsetTF.Translation.Z,
}
local FXScale = {X = TempPreViewActor.KillParticleOffsetTF.Scale3D.X, Y = TempPreViewActor.KillParticleOffsetTF.Scale3D.Y, Z = TempPreViewActor.KillParticleOffsetTF.Scale3D.Z}
GameplayStatics.SpawnEmitterAtLocation(self, TempPreViewActor.KillParticle, Pos, {Roll = 0, Pitch = 0, Yaw = 0}, FXScale, true)
end
end
-- function UGCGameState:ReceiveTick(DeltaTime)
-- end
-- function UGCGameState:ReceiveEndPlay()
-- end
return UGCGameState;

View File

@ -0,0 +1,177 @@
---@class UGCPlayerPawn_C:BP_UGCPlayerPawn_C
---@field StartItemID TArray<int32>
--Edit Below--
local UGCPlayerPawn = {}
-- 关闭盒子掉落
function UGCPlayerPawn:IsSkipSpawnDeadTombBox(EventInstigater)
return true
end
function UGCPlayerPawn:ReceiveBeginPlay()
UGCPlayerPawn.SuperClass.ReceiveBeginPlay(self)
if UGCGameSystem.IsServer() then
self.OnDeath:Add(self.OnDeathCallBack, self)
UGCEventSystem.SetTimer(self, function()
if UE.IsValid(self) then
for i, v in pairs(self.StartItemID) do
UGCLogSystem.Log("[UGCPlayerPawn_ReceiveBeginPlay] ID:%s", tostring(v))
UGCBackPackSystem.AddItem(self, v, 1)
end
end
end, 5)
else
end
if self.CheckFXHandle == nil then
-- 这里防止未设置成功做的校验
self.CheckFXHandle = UGCEventSystem.SetTimerLoop(self, self.UpdateFX, 2)
end
local TempRescueOtherComp = self:GetCharacterRescueOtherComponent()
local TempPreViewActor = UGCGameSystem.GameState:GetPreViewFXActor()
if UE.IsValid(TempRescueOtherComp) and UE.IsValid(TempPreViewActor) then
-- 配置倒地粒子 没有用这个方法
--TempRescueOtherComp.ShouldAddParticleWhenEnterLastBreath = true
--TempRescueOtherComp.ParticleTemplateToAddWhenEnterLastBreath = TempPreViewActor.KillParticle
UGCLogSystem.Log("[UGCPlayerPawn_ReceiveBeginPlay] Succeed")
end
end
--[[
function UGCPlayerPawn:ReceiveTick(DeltaTime)
UGCPlayerPawn.SuperClass.ReceiveTick(self, DeltaTime)
end
--]]
function UGCPlayerPawn:ReceiveEndPlay()
if UGCGameSystem.IsServer() then
self.OnDeath:Remove(self.OnDeathCallBack, self)
end
if self.CheckFXHandle then
UGCEventSystem.StopTimer(self.CheckFXHandle)
self.CheckFXHandle = nil
end
UGCPlayerPawn.SuperClass.ReceiveEndPlay(self)
end
--[[
function UGCPlayerPawn:GetReplicatedProperties()
return
end
--]]
--[[
function UGCPlayerPawn:GetAvailableServerRPCs()
return
end
--]]
-- 射击枪械槽类型
ShootWeaponEnums = {
ESurviveWeaponPropSlot.SWPS_MainShootWeapon1,
ESurviveWeaponPropSlot.SWPS_MainShootWeapon2,
ESurviveWeaponPropSlot.SWPS_SubShootWeapon,
};
function UGCPlayerPawn:OnPostGetWeapon(Weapon)
-- self:UpdateFX()
UGCLogSystem.Log("[UGCPlayerPawn_OnPostGetWeapon]")
local TempPreViewActor = UGCGameSystem.GameState:GetPreViewFXActor()
local Effect = Weapon:GetShootWeaponEffectComponent()
if UE.IsValid(TempPreViewActor) and UE.IsValid(Effect) and UE.IsValid(TempPreViewActor.MuzzleParticle) then
Effect.MuzzleFX = TempPreViewActor.MuzzleParticle
UGCLogSystem.Log("[UGCPlayerPawn_OnPostGetWeapon] Succeed")
end
end
function UGCPlayerPawn:UpdateFX()
UGCLogSystem.Log("[UGCPlayerPawn_UpdateFX]")
local TempPreViewActor = UGCGameSystem.GameState:GetPreViewFXActor()
if UE.IsValid(TempPreViewActor) then
for i, v in pairs(ShootWeaponEnums) do
local Weapon = UGCWeaponManagerSystem.GetWeaponBySlot(self, v);
if UE.IsValid(Weapon) then
local Effect = Weapon:GetShootWeaponEffectComponent()
if UE.IsValid(Effect) and UE.IsValid(TempPreViewActor.MuzzleParticle) then
Effect.MuzzleFX = TempPreViewActor.MuzzleParticle
UGCLogSystem.Log("[UGCPlayerPawn_UpdateFX] Succeed")
end
end
end
end
end
---@param DamageInfo FDamageInfoCollection
---@return VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue uint, uint, int, EDamageType, bool, float, float
function UGCPlayerPawn:GetDamageInfoCollectionInfo(DamageInfo)
local CauserController = DamageInfo.Instigator
local WeaponID = -1
local CauserKey = CauserController and CauserController.PlayerKey or -1
local VictimKey = self.PlayerKey
local CauserItemID = DamageInfo.CauserItemID
--- 近战投掷、投掷手雷
if CauserItemID then
WeaponID = CauserItemID
end
UGCLogSystem.Log("[UGCPlayerPawn_GetDamageInfoCollectionInfo] WeaponID:%d", WeaponID)
local Distance = 0.
if CauserController and CauserController.Pawn then
Distance = VectorHelper.GetDistance(self:K2_GetActorLocation(), CauserController.Pawn:K2_GetActorLocation())
end
local IsHeadShotDamage = (DamageInfo.Hit.BoneName == "head")
return VictimKey, CauserKey, WeaponID, DamageInfo.DamageType, IsHeadShotDamage, Distance, DamageInfo.Damage
end
---@param DamageInfo FDamageInfoCollection
function UGCPlayerPawn:PlayerDead(DamageInfo)
UGCLogSystem.LogTree("[UGCPlayerPawn_PlayerDead] DamageInfo:", UE.ToTable(DamageInfo))
local VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue = self:GetDamageInfoCollectionInfo(DamageInfo)
--UGCSendRPCSystem.RPCEvent(nil, EventEnum.PlayerDeathInfo, VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue)
--UGCEventSystem.SendEvent(EventEnum.PlayerDeathInfo, VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue)
UGCGameSystem.GameState:SetPlayerIsAlive(VictimKey, nil)
end
---@param DamageInfo FDamageInfoCollection
---@param ReturnValue float
function UGCPlayerPawn:PlayerInjury(DamageInfo)
local VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue = self:GetDamageInfoCollectionInfo(DamageInfo)
UGCEventSystem.SendEvent(EventEnum.PlayerInjuryInfo, VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue)
UGCSendRPCSystem.RPCEvent(CauserKey, EventEnum.PlayerInjuryInfo, VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue)
end
function UGCPlayerPawn:OnDeathCallBack(DeadCharacter,Killer,DamageCauser,KillingHitInfo,KillingHitImpulseDir,KillingHitDamageTypeID,DamageTypeClass,IsHeadShotDamage)
local CauserKey = Killer and Killer.PlayerKey
local WeaponID = -1
local DamageType = EDamageType.UGCCustomDamageType + 1
UGCLogSystem.Log("[UGCPlayerPawn_TestOnDeath] PlayerKey:%s, CauserKey:%s", tostring(self.PlayerKey), tostring(CauserKey))
UGCSendRPCSystem.RPCEvent(nil, EventEnum.PlayerDeathInfo, self.PlayerKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, 0, 0)
UGCEventSystem.SendEvent(EventEnum.PlayerDeathInfo, self.PlayerKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, 0, 0)
-- 发送RPC倒地粒子
local SelfPos = self:K2_GetActorLocation()
SelfPos = {
X = SelfPos.X,
Y = SelfPos.Y,
Z = SelfPos.Z,
}
UnrealNetwork.CallUnrealRPC_Multicast(UGCGameSystem.GameState, "SpawnParticleAtPos", SelfPos);
end
return UGCPlayerPawn

View File

@ -0,0 +1,4 @@
-- auto exported UENUM while compiling
-- sorted by enum name asc

View File

@ -0,0 +1,56 @@
EventEnum = {
-- DefaultEvent
DSStartUp = 1001, -- 服务器启动
PlayerLogin = 1003, -- 玩家加入房间 PlayerKey
PlayerExit = 1004, -- 玩家离开房间 PlayerKey
-- GameState
GameStateChange = 2001, -- 游戏模式改变 CustomEnum.EGameState
WaitPlayerJoin = 2002, -- 等待玩家加入
GamePlay = 2003, -- 游戏开始
GameEnd = 2004, -- 游戏结束
RoundBegining = 2005, -- 回合开始
RoundEnd = 2006, -- 回合结束
RoundReadyFinish = 2007, -- 回合准备阶段结束
-- PlayerEvent
PlayerDeathInfo = 3001, -- 死亡信息 VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue uint, uint, int, int, bool, float, float
PlayerInjuryInfo = 3002, -- 受伤信息 VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue uint, uint, int, int, bool, float, float
PlayerPossessed = 3003, -- 玩家受控 PlayerKey
PlayerBeginPlay = 3004, -- 玩家受控 PlayerPawn
BulletHitCallBack = 3005, -- 玩家射出的子弹命中物体或玩家的回调 (PlayerPawn:UGCPlayerPawn, ShootWeapon:ASTExtraShootWeapon,Bullet:ASTExtraShootWeaponBulletBase,HitInfo:FHitResult)
PlayerTeamChange = 3006, -- 玩家的队伍改变 PC, TeamID
-- PlayerPawn同步参数更新 更新传入Pawn及其同步变量值
UpdateCanObtainIncreaseCount = 4001,
UpdateNowCanSelectIncrease = 4002,
UpdateOwnedIncrease = 4003,
UpdateToGodSchedule = 4004,
-- PlayerEvent End
UpdatePlayerStartList = 10001, -- 通知出生点控制器进行更新出生点指针
AchievementSettlement = 10002, -- 成就事件游戏结算
UpdateTeamScore = 10003, -- 队伍得分信息更新
UpdatePlayerScoreData = 10004, -- 玩家得分信息更新 通过UGCGameSystem.GameState.PlayerScoreDatas 获取玩家得分信息
AddTip = 10005, -- 添加提提示 TipStr TipType
GameWillBegin = 10006, -- 游戏即将开始
PlayerIsAliveIsChange = 10007, -- 玩家存活列表改变
UpdatePlayerInfo = 10008, -- 玩家个人信息更新
PlayerWeaponCombinationUpdate = 11001, -- 玩家可选的武器配置列表更新 [PlayerKey] = CombinationType
PlayerSelectedWeaponIndexUpdate = 11002, -- 玩家选择的武器配置索引更新 [PlayerKey] = Index
--- SelectMap
LoadMap = 20001, -- 关卡加载 MapConifg.MapType
SelectMapCallBack = 20002, -- 地图选择服务器的回调 bSucceed, MapType
SelectDefaultWeaponCallBack = 20003, -- 默认武器选择回调 bSucceed, WeaponID
RandomSelectVoteMap = 20004,
UpdateMapKey = 20005, -- 随机出的地图索引 MapKey
}

View File

@ -0,0 +1,13 @@
-- 需要包含的头目录
local Prefix = "Script.Global.FunctionExtension."
require(Prefix .. 'MathExtension')
require(Prefix .. 'StringExtension')
require(Prefix .. 'TableExtension')
require(Prefix .. 'TableHelper')
require(Prefix .. 'VectorHelper')
require(Prefix .. 'QuatHelper')

View File

@ -0,0 +1,38 @@
---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
--- 在圆中随机生成一个点
function math.RandomCirclePoint(Radius, Center)
local angle = math.random() * 2 * math.pi;
local tr = Radius * math.sqrt(math.random());
local x = Center.X + tr * math.cos(angle);
local y = Center.Y + tr * math.sin(angle);
return { X = x, Y = y };
end

View File

@ -0,0 +1,63 @@
QuatHelper = {}
-- 四元数结构体
QuatHelper = {}
QuatHelper.__index = QuatHelper
-- 创建四元数
function QuatHelper.new(W, X, Y, Z)
return setmetatable({W = W, X = X, Y = Y, Z = Z}, QuatHelper)
end
function QuatHelper.RotToQuat(Rot)
return STExtraBlueprintFunctionLibrary.RotToQuat(Rot)
end
function QuatHelper.QuatToRot(q)
return STExtraBlueprintFunctionLibrary.QuatToRot(q)
end
-- 四元数乘法 (q1 * q2)
function QuatHelper.mul(q1, q2)
return QuatHelper.new(
q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z,
q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y,
q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X,
q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W
)
end
-- 四元数与向量乘法 (q * v)假设向量v是{x, y, z}
function QuatHelper.mulVec(q, v)
local qv = QuatHelper.new(0, v.x, v.y, v.z)
local q_conjugate = QuatHelper.conjugate(q)
local result = QuatHelper.mul(QuatHelper.mul(q, qv), q_conjugate)
return {x = result.X, y = result.Y, z = result.Z}
end
-- 四元数单位化
function QuatHelper.normalize(q)
local magnitude = math.sqrt(q.W * q.W + q.X * q.X + q.Y * q.Y + q.Z * q.Z)
return QuatHelper.new(q.W / magnitude, q.X / magnitude, q.Y / magnitude, q.Z / magnitude)
end
-- 四元数共轭
function QuatHelper.conjugate(q)
return QuatHelper.new(q.W, -q.X, -q.Y, -q.Z)
end
-- 四元数逆
function QuatHelper.inverse(q)
local conjugate = QuatHelper.conjugate(q)
local magnitude_squared = q.W * q.W + q.X * q.X + q.Y * q.Y + q.Z * q.Z
return QuatHelper.new(conjugate.W / magnitude_squared, conjugate.X / magnitude_squared, conjugate.Y / magnitude_squared, conjugate.Z / magnitude_squared)
end
-- 生成四元数字符串表示 (用于调试)
function QuatHelper.toString(q)
return string.format("(%f, %f, %f, %f)", q.W, q.X, q.Y, q.Z)
end
return QuatHelper;

View File

@ -0,0 +1,18 @@
---字符串分割
function string:split(sep)
--sep = sep or "\t"
local fields = {}
local pattern = string.format("([^%s]+)", sep)
self:gsub(pattern, function(c) fields[#fields+1] = c end)
return fields
end
---字符串直接转Number
function string.splitToNumber(InStr, sep)
--sep = sep or "\t"
local fields = {}
local pattern = string.format("([^%s]+)", sep)
InStr:gsub(pattern, function(c) fields[#fields+1] = tonumber(c) end)
return fields
end

View File

@ -0,0 +1,259 @@
-- 拷贝table
function table.DeepCopy(object)
-- 已经复制过的tablekey为复制源tablevalue为复制后的table
-- 为了防止table中的某个属性为自身时出现死循环
-- 避免本该是同一个table的属性在复制时变成2个不同的table(内容同,但是地址关系和原来的不一样了)
local lookup_table = {}
local function _copy(object)
if type(object) ~= 'table' then -- 非table类型都直接返回
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for k, v in pairs(object) do
new_table[_copy(k)] = _copy(v)
end
-- 这里直接拿mt来用是因为一般对table操作不会很粗暴的修改mt的相关内容
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
end
function table.NewLuaObj(InObj)
return setmetatable({}, {
__index = InObj,
__metatable = InObj,
})
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.Rand(t)
if type(t) ~= "table" or #t <= 0 then return nil end
return t[math.random(1, #t)]
end
function table.GetMaxValueResKey(t, fun)
if fun == nil then fun = function(p1, p2) return p1 < p2 end end
if type(t) ~= "table" or type(fun) ~= "function" or table.getCount(t) <= 0 then return end
local res = nil
for k, v in pairs(t) do
if not res or fun(t[res], v) then
res = k
end
end
return res
end
function table.FindKey(t, value)
if type(t) ~= "table" then return nil end
for k, v in pairs(t) do
if v == value then return k end
end
return nil
end
function table.GetMaxValue(t)
if type(t) ~= "table" then return nil end
local Res = nil
for k, v in pairs(t) do
if Res == nil then Res = v
elseif Res < v then Res = v
end
end
return Res
end
function table.Swap(t, i, k)
if type(t) ~= "table" then
return false
end
local temp = t[i]
t[i] = t[k]
t[k] = temp
end
--- 打乱整个table 洗牌算法
function table.Shuffle(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
--- 判断table相等
function table.tablesEqual(table1, table2)
-- 检查table1和table2是否为同一个table
if table1 == table2 then
return true
end
-- 检查table类型
if type(table1) ~= 'table' or type(table2) ~= 'table' then
return false
end
-- 检查table1中的键值对是否在table2中
for key, value in pairs(table1) do
if type(value) == 'table' then
if not tablesEqual(value, table2[key]) then
return false
end
else
if table2[key] ~= value then
return false
end
end
end
-- 检查table2中是否有table1中没有的键
for key in pairs(table2) do
if table1[key] == nil then
return false
end
end
return true
end
--- 判断table集合相等
function table.collectionsEqual(collection1, collection2)
local count1 = 0
local count2 = 0
-- 计算第一个集合的大小
for _ in pairs(collection1) do
count1 = count1 + 1
end
-- 计算第二个集合的大小
for _ in pairs(collection2) do
count2 = count2 + 1
end
-- 如果大小不同,则集合不同
if count1 ~= count2 then
return false
end
-- 检查collection1中的每个元素是否也在collection2中
for key1, value1 in pairs(collection1) do
local found = false
for key2, value2 in pairs(collection2) do
if value1 == value2 then
found = true
break
end
end
if not found then
return false
end
end
return true
end

View File

@ -0,0 +1,451 @@
TableHelper = TableHelper or {}
---@param obj table
---@return table
function TableHelper.DeepCopy(obj)
if obj == nil then
return {};
end
local InTable = {};
local function Func(obj)
if type(obj) ~= "table" then --判断表中是否有表
return obj;
end
local NewTable = {}; --定义一个新表
InTable[obj] = NewTable; --若表中有表则先把表给InTable再用NewTable去接收内嵌的表
for k,v in pairs(obj) do --把旧表的key和Value赋给新表
NewTable[Func(k)] = Func(v);
end
return setmetatable(NewTable, getmetatable(obj))--赋值元表
end
return Func(obj) --若表中有表,则把内嵌的表也复制了
end
---@param InSelf table
---@param InTable table
function TableHelper.CopyToTable(InSelf, InTable)
if InSelf == nil or InTable == nil then
return
end
for i, v in pairs(InTable) do
if type(v) == 'table' then
TableHelper.CopyToTable(InSelf[i], v);
else
InSelf[i] = v;
end
end
end
---@param Tab table
---@return table
function TableHelper.CopyTable(Tab)
local NewTab = {}
for k, v in pairs(Tab) do
NewTab[k] = v
end
return NewTab
end
---@param TableData table
---@return table
function TableHelper.DeepCopyTable(TableData)
if TableData == nil then
UGCLogSystem.LogError("表格为空,不能复制");
return {};
end
local TmpTab = {};
for k, v in pairs(TableData) do
if type(v) == "table" then
local SubTab = TableHelper.DeepCopyTable(v);
TmpTab[k] = SubTab;
-- elseif type(v) == "userdata" then
-- TmpTab[k] = v:Copy();
else
TmpTab[k] = v;
end
end
return TmpTab;
end
--- 返回值的下标,没有返回-1
---@param tab table
---@param val any
---@return bool, int32
function TableHelper.GetValueIndex(tab, val)
for k, v in pairs(tab) do
if v == val then
return true, k;
end
end
return false, -1;
end
---@param tab table
---@param val any
function TableHelper.RemoveByValue(tab, val)
for i, Val in pairs(tab) do
if Val == val then
table.remove(tab, i);
break;
end
end
end
function TableHelper.Contains(tab, val)
for i, Val in pairs(tab) do
if Val == val then
return true;
end
end
return false;
end
function TableHelper.GetName(Actor)
if UE.IsValid(Actor) then
return UE.GetPathName(Actor);
elseif Actor ~= nil then
return type(Actor)
end
return "[NullActor]";
end
function TableHelper.Length(InTable)
if InTable == nil then
return 0;
end
local Count = 0
for _ in pairs(InTable) do
Count = Count + 1;
end
return Count;
end
function TableHelper.AppendToTable(OriginalTable, NewTable)
if OriginalTable == nil or NewTable == nil then
return;
end
for k, v in pairs(NewTable) do
table.insert(OriginalTable, v);
end
end
function TableHelper.ArrayToLuaTable(Array)
local Tab = {};
for k, v in pairs(Array) do
Tab[k] = v;
end
return Tab;
end
function class(classname, super)
local superType = type(super)
local cls
if superType ~= "function" and superType ~= "table" then
superType = nil
super = nil
end
if superType == "function" or (super and super.__ctype == 1) then
-- inherited from native C++ Object
cls = {}
if superType == "table" then
-- copy fields from super
for k, v in pairs(super) do
cls[k] = v
end
cls.__create = super.__create
cls.super = super
else
cls.__create = super
cls.Ctor = function()
end
end
cls.__cname = classname
cls.__ctype = 1
function cls.New(...)
local instance = cls.__create(...)
-- copy fields from class to native object
for k, v in pairs(cls) do
instance[k] = v
end
instance.class = cls
instance:Ctor(...)
return instance
end
else
-- inherited from Lua Object
if super then
cls = {}
setmetatable(cls, {
__index = super
})
cls.super = super
else
cls = {
Ctor = function()
end
}
end
cls.__cname = classname
cls.__ctype = 2 -- lua
cls.__index = cls
function cls.New(...)
local instance = setmetatable({}, cls)
instance.class = cls
instance:Ctor(...)
return instance
end
end
return cls
end
-- 拷贝table
function table.DeepCopy(object)
-- 已经复制过的tablekey为复制源tablevalue为复制后的table
-- 为了防止table中的某个属性为自身时出现死循环
-- 避免本该是同一个table的属性在复制时变成2个不同的table(内容同,但是地址关系和原来的不一样了)
local lookup_table = {}
local function _copy(object)
if type(object) ~= 'table' then -- 非table类型都直接返回
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for k, v in pairs(object) do
new_table[_copy(k)] = _copy(v)
end
-- 这里直接拿mt来用是因为一般对table操作不会很粗暴的修改mt的相关内容
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
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.Rand(t)
if type(t) ~= "table" or #t <= 0 then return nil end
return t[math.random(1, #t)]
end
function table.GetMaxValueResKey(t, fun)
if fun == nil then fun = function(p1, p2) return p1 < p2 end end
if type(t) ~= "table" or type(fun) ~= "function" or table.getCount(t) <= 0 then return end
local res = nil
for k, v in pairs(t) do
if not res or fun(t[res], v) then
res = k
end
end
return res
end
function table.FindKey(t, value)
if type(t) ~= "table" then return nil end
for k, v in pairs(t) do
if v == value then return k end
end
return nil
end
function table.GetMaxValue(t)
if type(t) ~= "table" then return nil end
local Res = nil
for k, v in pairs(t) do
if Res == nil then Res = v
elseif Res < v then Res = v
end
end
return Res
end
function table.Swap(t, i, k)
if type(t) ~= "table" then
return false
end
local temp = t[i]
t[i] = t[k]
t[k] = temp
end
--- 打乱整个table 洗牌算法
function table.Shuffle(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
return true
end
function table.addTableNum(t, k, v)
if t[k] == nil then
t[k] = v
else
t[k] = t[k] + v
end
return t[k]
end
---------------------------------------------------------table print---------------------------------------------------------
-- log输出格式化
local function logPrint(str)
str = os.date("\nLog output date: %Y-%m-%d %H:%M:%S \n", os.time()) .. str
print(str)
end
-- key值格式化
local function formatKey(key)
local t = type(key)
if t == "number" then
return "[" .. key .. "]"
elseif t == "string" then
local n = tonumber(key)
if n then
return "[" .. key .. "]"
end
end
return key
end
return TableHelper;

View File

@ -0,0 +1,179 @@
VectorHelper = {}
function VectorHelper.Dot(v1, v2)
return v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z
end
function VectorHelper.Mul(v1, v2)
return Vector.New(v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z)
end
function VectorHelper.MulScalar(v1, S)
return Vector.New(v1.X * S, v1.Y * S, v1.Z * S)
end
function VectorHelper.MulScalar2D(v1, S)
return Vector.New(v1.X * S, v1.Y * S, 0)
end
function VectorHelper.MulNumber(v1, number)
return Vector.New(v1.X * number, v1.Y * number, v1.Z * number)
end
function VectorHelper.MulNumber2D(v1, number)
return Vector.New(v1.X * number, v1.Y * number, 0)
end
function VectorHelper.Sub(v1, v2)
return Vector.New(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z)
end
function VectorHelper.Sub2D(v1, v2)
return Vector.New(v1.X - v2.X, v1.Y - v2.Y, 0)
end
function VectorHelper.Add(v1, v2)
return Vector.New(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z)
end
function VectorHelper.Add2D(v1, v2)
return Vector.New(v1.X + v2.X, v1.Y + v2.Y, 0)
end
function VectorHelper.Div2DScalar(v1, s)
return Vector.New(v1.X / s , v1.Y / s, 0);
end
function VectorHelper.ToString(v)
return string.format("(%.2f,%.2f,%.2f)", v.X, v.Y, v.Z)
end
function VectorHelper.RotToString(v)
return string.format("(Roll = %.2f, Pitch = %.2f, Yaw = %.2f)", v.Roll, v.Pitch, v.Yaw)
end
function VectorHelper.ToStringInt2D(v)
if v == nil then
return "[X=Nil,Y=Nil]";
end
return string.format("[%d, %d]", v.X, v.Y);
end
function VectorHelper.ToIntString(v)
return "(" .. tostring(math.floor(v.X)) .. "," .. tostring( math.floor(v.Y)) .. "," .. tostring(math.floor(v.Z)) .. ")";
end
function VectorHelper.Cross(v1, v2)
return Vector.New(v1.Y * v2.Z - v2.Y * v1.Z,
v1.Z * v2.X - v2.Z * v1.X,
v1.X * v2.Y - v2.X * v1.Y)
end
function VectorHelper.GetDistance(vector1, vector2)
if vector1 == nil or vector2 == nil then return 0 end
if vector1.X == nil or vector2.X == nil then return 0 end
if vector1.Y == nil or vector2.Y == nil then return 0 end
if vector1.Z == nil or vector2.Z == nil then return 0 end
local disX = vector1.X - vector2.X
local disY = vector1.Y - vector2.Y
local disZ = vector1.Z - vector2.Z
return math.sqrt(disX ^ 2 + disY ^ 2 + disZ ^ 2)
end
function VectorHelper.GetDistance2D(vector1, vector2)
if vector1 == nil or vector2 == nil then return 0 end
if vector1.X == nil or vector2.X == nil then return 0 end
if vector1.Y == nil or vector2.Y == nil then return 0 end
local disX = vector1.X - vector2.X
local disY = vector1.Y - vector2.Y
return math.sqrt(disX ^ 2 + disY ^ 2)
end
function VectorHelper.LengthSquared(v)
return v.X ^ 2 + v.Y ^ 2 + v.Z ^ 2
end
function VectorHelper.LengthSquared2D(v)
return v.X ^ 2 + v.Y ^ 2
end
function VectorHelper.Length(v)
return math.sqrt(VectorHelper.LengthSquared(v))
end
function VectorHelper.Length2D(v)
return math.sqrt(VectorHelper.LengthSquared2D(v))
end
function VectorHelper.ToLuaTable(v)
return {X = v.X, Y = v.Y, Z = v.Z}
end
function VectorHelper.ToLuaTable2D(v)
return {X = v.X, Y = v.Y, Z = 0}
end
function VectorHelper.RotToLuaTable(v)
return {Roll=v.Roll, Pitch=v.Pitch, Yaw=v.Yaw}
end
function VectorHelper.ColorToVector(LinearColor)
return {X = LinearColor.R, Y = LinearColor.G, Z = LinearColor.B }
end
function VectorHelper.RotToString(v)
return string.format("Roll=%.2f, Pitch=%.2f, Yaw=%.2f", v.Roll, v.Pitch, v.Yaw);
end
function VectorHelper.GetMiddlePoint(vector1, vector2)
return {X = (vector1.X + vector2.X) / 2, Y = (vector1.Y + vector2.Y) / 2,Z = (vector1.Z + vector2.Z) / 2}
end
function VectorHelper.FromCpp(CppVector)
return {X = CppVector.X, Y = CppVector.Y, Z = CppVector.Z};
end
function VectorHelper.Equal(vector1, vector2)
return (vector1.X == vector2.X and vector1.Y == vector2.Y and vector1.Z == vector2.Z);
end
--计算两点之间连线与Y轴的夹角
function VectorHelper.GetAngleByPos(PosA,PosB)
local P = {};
P.X = PosB.X - PosA.X;
P.Y = PosB.Y - PosA.Y;
local Pi = 3.1415926;
local Dis = math.sqrt( (P.X * P.X) + (P.Y * P.Y));
local FAngle = math.acos (P.Y/ Dis);
if( P.X < 0) then
FAngle = 2 * Pi - FAngle;
end
local Angle = FAngle * 180 / Pi;
Angle = Angle > 0 and (90 - Angle) or (90 + math.abs(Angle));
return Angle;
end
function VectorHelper.RotZero()
return {Roll = 0, Pitch = 0, Yaw = 0}
end
function VectorHelper.VectorZero()
return {X = 0, Y = 0, Z = 0}
end
function VectorHelper.ScaleOne()
return {X = 1, Y = 1, Z = 1}
end
function VectorHelper.CosineValue(v1, v2)
return VectorHelper.Dot(v1, v2) / (VectorHelper.Length(v1) * VectorHelper.Length(v2))
end
return VectorHelper;

View File

@ -0,0 +1,9 @@
require('Script.Global.EventConfig')
--- 函数拓展
require('Script.Global.FunctionExtension.A_IncludeFunctionExtension')
--- 各系统功能文件 依赖函数拓展、事件系统、函数拓展
require('Script.Global.System.A_IncludeSystem')

View File

@ -0,0 +1,16 @@
-- 需要包含的头目录
local Prefix = "Script.Global.System."
-- 工具集
require(Prefix .. 'UGCSystemLibrary')
require(Prefix .. 'LevelStreamUtil')
require(Prefix .. 'SoundSystem')
require(Prefix .. 'UGCDelegate')
require(Prefix .. 'UGCDelegateMulticast')
require(Prefix .. 'UGCEventSystem')
require(Prefix .. 'UGCLogSystem')
require(Prefix .. 'UGCSendRPCSystem')
require(Prefix .. 'PlayerScoreSystem')
require(Prefix .. 'MyVehicleSystem')
require(Prefix .. 'MyWeaponSystem')

View File

@ -0,0 +1,143 @@
--require("Script.Common.UGCLog");
--require("Script.Common.TableHelper");
LevelStreamUtil = LevelStreamUtil or
{
LevelLoadCounter = 0;
LoadDelegate = nil;
LoadCompletedCallback = nil;
IsAsyncLoad = false;
LevelUnloadCounter = 0;
UnLoadDelegate = nil;
UnloadCompletedCallback = nil;
IsAsyncUnload = false;
LoadedLevels = {};
};
---@class CallbackStruct
---@field Object Object
---@field Func fun()
---@param LevelNameList string[]字符串关卡名列表
---@param CompletedCallback CallbackStruct 加载完成时的回调函静态函数
---@param bShouldBlockOnLoad bool 是否等待处理完成
--- LoadStreamLevel fun(WorldContextObject:UObject,LevelName:FName,bMakeVisibleAfterLoad:bool,bShouldBlockOnLoad:bool,LatentInfo:FLatentActionInfo)
function LevelStreamUtil.LoadStreamLevels(LevelNameList, CompletedCallback, bShouldBlockOnLoad)
--UGCLogSystem.Log("[Level] 加载关卡数量:%d CompletedCallback:%s", LevelNameList:Num(), UE.ToTable(CompletedCallback));
LevelStreamUtil.LevelLoadCounter = LevelStreamUtil.LevelLoadCounter + #LevelNameList;
LevelStreamUtil.LoadCompletedCallback = CompletedCallback;
LevelStreamUtil.IsAsyncLoad = not bShouldBlockOnLoad;
--UGCLogSystem.Log("[Level] 加载关卡 LoadCompletedCallback:%s", UE.ToTable(LevelStreamUtil.LoadCompletedCallback));
for k, v in pairs(LevelNameList) do
UGCLogSystem.Log("[Level] 加载关卡:%s", v);
table.insert(LevelStreamUtil.LoadedLevels, v);
LevelStreamUtil.LoadDelegate = ObjectExtend.CreateDelegate(UGCGameSystem.GameState, LevelStreamUtil.OnLoadCompleted, LevelStreamUtil);
GameplayStatics.LoadStreamLevel(UGCGameSystem.GameState, v, true, bShouldBlockOnLoad,
ObjectExtend.CreateLatentAction(LevelStreamUtil.LoadDelegate));
-- 强制加载完成
if bShouldBlockOnLoad then
GameplayStatics.FlushLevelStreaming(UGCGameSystem.GameState);
end
end
if bShouldBlockOnLoad then
UGCLogSystem.Log("[Level] 完成同步加载关卡");
-- LevelStreamUtil.LoadCompletedCallback();
LevelStreamUtil.LoadCompletedCallback.Func(LevelStreamUtil.LoadCompletedCallback.Object);
end
end
--- 加载结束异步回调
function LevelStreamUtil:OnLoadCompleted()
if not LevelStreamUtil.IsAsyncLoad then
return;
end
LevelStreamUtil.LevelLoadCounter = LevelStreamUtil.LevelLoadCounter - 1;
UGCLogSystem.Log("[Level] 加载关卡完成 剩余等待计数:[%d]", LevelStreamUtil.LevelLoadCounter);
if LevelStreamUtil.LevelLoadCounter == 0 then
ObjectExtend.DestroyDelegate(LevelStreamUtil.LoadDelegate);
LevelStreamUtil.LoadDelegate = nil;
UGCLogSystem.Log("[Level] 加载关卡完成 LoadCompletedCallback:%s", UE.ToTable(LevelStreamUtil.LoadCompletedCallback));
if LevelStreamUtil.LoadCompletedCallback ~= nil then
UGCLogSystem.Log("[Level] 完成异步加载关卡");
-- LevelStreamUtil.CompletedCallback();
-- 必须缓存用,不然会被加载子关卡的调用冲掉
local Callback = LevelStreamUtil.LoadCompletedCallback;
LevelStreamUtil.LoadCompletedCallback = nil;
Callback.Func(Callback.Object);
end
end
end
--- 根据传入的列表销毁相应的关卡
---@param LevelNameList string[]字符串关卡名列表
---@param UnloadCompletedCallback CallbackStruct 销毁完成时的回调函静态函数
---@param bShouldBlockOnLoad bool 是否等待处理完成
---UnloadStreamLevel fun(WorldContextObject:UObject,LevelName:FName,LatentInfo:FLatentActionInfo)
function LevelStreamUtil.UnLoadStreamLevels(LevelNameList, UnloadCompletedCallback, bShouldBlockOnLoad)
LevelStreamUtil.UnloadCompletedCallback = UnloadCompletedCallback;
LevelStreamUtil.LevelUnloadCounter = LevelStreamUtil.LevelUnloadCounter + #LevelNameList;
LevelStreamUtil.IsAsyncUnload = not bShouldBlockOnLoad;
for k, v in pairs(LevelNameList) do
UGCLogSystem.Log("[Level] 销毁关卡:%s", v);
-- TableHelper.RemoveByValue(LevelStreamUtil.LoadedLevels, v);
table.removeValue(LevelStreamUtil.LoadedLevels, v, true)
LevelStreamUtil.UnLoadDelegate = ObjectExtend.CreateDelegate(UGCGameSystem.GameState, LevelStreamUtil.UnLoadCompleted, LevelStreamUtil);
GameplayStatics.UnloadStreamLevel(UGCGameSystem.GameState, v,
ObjectExtend.CreateLatentAction(LevelStreamUtil.UnLoadDelegate));
-- 强制销毁完成
if bShouldBlockOnLoad then
GameplayStatics.FlushLevelStreaming(UGCGameSystem.GameState);
end
end
if bShouldBlockOnLoad then
UGCLogSystem.Log("[Level] 完成同步销毁关卡");
LevelStreamUtil.UnloadCompletedCallback.Func(LevelStreamUtil.UnloadCompletedCallback.Object);
end
end
--- 销毁结束异步回调
function LevelStreamUtil:UnLoadCompleted()
if not LevelStreamUtil.IsAsyncUnload then
return;
end
UGCLogSystem.Log("[Level] 销毁关卡完成[%d]", LevelStreamUtil.LevelUnloadCounter);
LevelStreamUtil.LevelUnloadCounter = LevelStreamUtil.LevelUnloadCounter - 1;
if LevelStreamUtil.LevelUnloadCounter == 0 then
ObjectExtend.DestroyDelegate(LevelStreamUtil.UnLoadDelegate);
LevelStreamUtil.UnLoadDelegate = nil;
if LevelStreamUtil.UnloadCompletedCallback ~= nil then
UGCLogSystem.Log("[Level] 完成异步销毁关卡");
-- LevelStreamUtil.UnloadCompletedCallback();
LevelStreamUtil.UnloadCompletedCallback.Func(LevelStreamUtil.UnloadCompletedCallback.Object);
LevelStreamUtil.UnloadCompletedCallback = nil;
end
end
end

View File

@ -0,0 +1,59 @@
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by LT.
--- DateTime: 2024/8/23 17:10
---
MyVehicleSystem = MyVehicleSystem or {}
MyVehicleSystem.VehicleClassName = "STExtraWheeledVehicle"
MyVehicleSystem.SpawnVehiclePointPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/SceneActor/BP_VehicleSpawnPoint.BP_VehicleSpawnPoint_C')
function MyVehicleSystem.GetVehicleBaseClass()
if MyVehicleSystem.VehicleBaseClass == nil then
MyVehicleSystem.VehicleBaseClass = ScriptGameplayStatics.FindClass(MyVehicleSystem.VehicleClassName)
end
return MyVehicleSystem.VehicleBaseClass
end
function MyVehicleSystem.GetSpawnVehiclePointClass()
if MyVehicleSystem.VehicleBaseClass == nil then
MyVehicleSystem.VehicleBaseClass = UE.LoadClass(MyVehicleSystem.SpawnVehiclePointPath)
end
return MyVehicleSystem.VehicleBaseClass
end
--- 保存当前场景中载具的信息
function MyVehicleSystem.SaveAllVehicleTF(MapIndex)
MyVehicleSystem.AllVehicleTF = {}
--local AllVehicles = {}
--AllVehicles = ScriptGameplayStatics.GetActorsOfClass(UGCGameSystem.GameState, MyVehicleSystem.GetVehicleBaseClass(), {})
--for i, VehicleInst in pairs(AllVehicles) do
-- MyVehicleSystem.AllVehicleTF[#MyVehicleSystem.AllVehicleTF + 1] = {VehicleID = VehicleInst.VehicleConfigID, Pos = VehicleInst:K2_GetActorLocation(), Rot = VehicleInst:K2_GetActorRotation(), Inst = VehicleInst}
--end
--UGCLogSystem.LogTree("[MyVehicleSystem_SaveAllVehicleTF]", MyVehicleSystem.AllVehicleTF)
MyVehicleSystem.AllVehicleTF = {}
local AllVehicleSpawnPoints = ScriptGameplayStatics.GetActorsOfClass(UGCGameSystem.GameState, MyVehicleSystem.GetSpawnVehiclePointClass(), {})
for i, v in pairs(AllVehicleSpawnPoints) do
UGCLogSystem.Log("[MyVehicleSystem_SaveAllVehicleTF] VehiclePath:%s", v.VehiclePath)
if MapIndex == nil or MapIndex == v.MapIndex then
MyVehicleSystem.AllVehicleTF[#MyVehicleSystem.AllVehicleTF + 1] = {VehiclePath = v.VehiclePath, Pos = v:K2_GetActorLocation(), Rot = v:K2_GetActorRotation(), Inst = nil}
end
end
UGCLogSystem.LogTree("[MyVehicleSystem_SaveAllVehicleTF]", MyVehicleSystem.AllVehicleTF)
end
--- 移除场景中的载具
function MyVehicleSystem.DestroyAllSavedVehicle()
for i, v in pairs(MyVehicleSystem.AllVehicleTF) do
if UE.IsValid(v.Inst) then
UGCVehicleSystem.DestroySelf(v.Inst)
end
end
end
--- 重置当前场景中的载具,需要先调移除
function MyVehicleSystem.ResetAllSavedVehicle()
for i, v in pairs(MyVehicleSystem.AllVehicleTF) do
MyVehicleSystem.AllVehicleTF[i].Inst = UGCVehicleSystem.SpawnVehicleNew(v.VehiclePath, v.Pos, v.Rot, true)
UGCLogSystem.Log("[MyVehicleSystem_ResetAllSavedVehicle] Inst:%s", tostring(MyVehicleSystem.AllVehicleTF[i].Inst))
end
end

View File

@ -0,0 +1,216 @@
--[[
---@field ItemID int32
---@field ItemName FString
---@field ItemType int32
---@field ItemSubType int32
---@field BPID int32
---@field Durability int32
---@field Electricity int32
---@field AIFullVaule int32
---@field Equippable bool
---@field Consumable bool
---@field AutoEquipAndDrop bool
---@field MaxCount int32
---@field WeightforOrder int32
---@field WeightforOrder2 int32
---@field UnitWeight_f float
---@field ItemBigIcon_n FName
---@field ItemSmallIcon_n FName
---@field ItemWhiteIcon_n FName
---@field ArmorySimpleDesc FString
---@field BackpackSimple FString
---@field ItemQuality int32
---@field PickUpSound FString
---@field DropSound FString
---@field EquipSound FString
---@field UnEquipSound FString
---@field PickUpBank FString
---@field DropBank FString
---@field EquipBank FString
---@field UnEquipBank FString
---@field KillWhiteIcon FString
---@field StTime int32
---@field ItemTypeBigWorld int32
---@field BigWorldBackpackTab_n FName
---@field IsVirtualItem bool
---@field Droppable bool
---@field HomeBackpackTab_n FName
---@field Rarelevel int32
---@field RarelevelEffPath FString
---@field CustomizedType FString
]]
MyWeaponSystem = MyWeaponSystem or {}
--- 异步加载Item小图标到Image画刷
function MyWeaponSystem.AsyncLoadItemSmallIconToBrush(InItemID, ImageWidget)
MyWeaponSystem.AsyncLoadItemIconToBrush(InItemID, ImageWidget, "ItemSmallIcon_n")
end
--- 异步加载Item大图标到Image画刷
function MyWeaponSystem.AsyncLoadItemBigIconToBrush(InItemID, ImageWidget)
MyWeaponSystem.AsyncLoadItemIconToBrush(InItemID, ImageWidget, "ItemBigIcon_n")
end
--- 异步加载Item白色剪影图标到Image画刷
function MyWeaponSystem.AsyncLoadItemWhiteIconToBrush(InItemID, ImageWidget)
MyWeaponSystem.AsyncLoadItemIconToBrush(InItemID, ImageWidget, "ItemWhiteIcon_n")
end
--- 异步加载Item图标到Image画刷
function MyWeaponSystem.AsyncLoadItemIconToBrush(InItemID, ImageWidget, TexKey)
local ItemInfo = UGCItemSystem.GetItemData(InItemID);
if ItemInfo then
UGCSystemLibrary.AsyncLoadAsset(ItemInfo[TexKey],
function(Tex)
if UE.IsValid(ImageWidget) then
ImageWidget:SetBrushFromTexture(Tex);
end
end , nil
,true)
end
end
--- 判断Item是否为武器的配件
function MyWeaponSystem.IsWeaponPartValid(InId)
if InId == nil then
return false;
end
return WeaponParts[InId] ~= nil;
end
--- 获取Item名
function MyWeaponSystem.GetItemName(InItemID)
if InItemID == nil then return "" end
if InItemID <= 0 then
return "拳击"
else
local ItemInfo = UGCItemSystem.GetItemData(InItemID);
if ItemInfo then
return ItemInfo.ItemName
end
end
UGCLogSystem.Log("[GetWeaponName]无法找到对应 Weapon ID: " .. InItemID)
return ""
end
--- 获取配件Item是否为武器可用Item
---@param WeaponID int
---@param PartItemID int
function MyWeaponSystem.PartIsWeaponCanBeUsed(WeaponID, PartItemID)
if WeaponSuits[WeaponID] == nil then
UGCLogSystem.LogError("[MyWeaponSystem_PartIsWeaponCanBeUsed]")
return false
end
for i, v in pairs(WeaponSuits[WeaponID]) do
for _, PartItemIDTemp in pairs(v) do
if PartItemIDTemp == PartItemID then
return true
end
end
end
return false
end
--- 获取武器最佳配件
function MyWeaponSystem.GetWeaponBastParts(InWeaponID)
if WeaponTable.RecommendedWeaponParts[InWeaponID] then
return WeaponTable.RecommendedWeaponParts[InWeaponID]
end
return {}
end
--- 获取武器可用配件
function MyWeaponSystem.GetWeaponCanUsePartFromPartType(WeaponID, PartType)
if WeaponSuits[WeaponID] == nil then return {} end
if WeaponSuits[WeaponID][PartType] == nil then return {} end
return WeaponSuits[WeaponID][PartType]
end
--- 将配件列表转化为配件字典 Key为PartType Value为ItemID
function MyWeaponSystem.PartListToPartMap(InPartList)
local Res = {}
for i, v in pairs(InPartList) do
if WeaponParts[v] then
Res[WeaponParts[v].Type] = v
end
end
return Res
end
function MyWeaponSystem.GetPartType(InPartItemID)
if WeaponParts[InPartItemID] then
return WeaponParts[InPartItemID].Type
end
return nil
end
Weapon_LastGetWeaponIDTime = -1.
Weapon_LastGetWeaponIDRes = {} -- PlayerKey = {}
--- 获取配件Item是否为武器可用Item
---@param PlayerKey uint
function MyWeaponSystem.GetPlayerShootWeaponIDs(PlayerKey)
local NowTime = KismetSystemLibrary.GetGameTimeInSeconds(UGCGameSystem.GameState)
if Weapon_LastGetWeaponIDTime == NowTime then
if Weapon_LastGetWeaponIDRes[PlayerKey] then
return Weapon_LastGetWeaponIDRes[PlayerKey]
end
else
Weapon_LastGetWeaponIDTime = NowTime
Weapon_LastGetWeaponIDRes = {}
end
local TargetPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey)
local Res = {}
if UE.IsValid(TargetPawn) then
for i, v in pairs(ShootWeaponEnums) do
local Weapon = UGCWeaponManagerSystem.GetWeaponBySlot(TargetPawn, v)
if Weapon then
Res[#Res + 1] = UGCWeaponManagerSystem.GetWeaponItemID(Weapon)
end
end
end
Weapon_LastGetWeaponIDRes[PlayerKey] = Res
return Res
end
function MyWeaponSystem.GetItemWeaponAmmunitionItemID(WeaponID)
return WeaponAmmunitionItem[WeaponID]
end
MyWeaponSystem.BackPackHandle1 = {}
MyWeaponSystem.BackPackHandle2 = {}
MyWeaponSystem.BackPackHandle3 = {}
MyWeaponSystem.BackPackHandle4 = {}
function MyWeaponSystem.UpdatePlayerBackPack(PlayerKey)
-- 默认武器
if MyWeaponSystem.BackPackHandle1[PlayerKey] then UGCEventSystem.StopTimer(MyWeaponSystem.BackPackHandle1[PlayerKey]) end
MyWeaponSystem.BackPackHandle1[PlayerKey] = UGCEventSystem.SetTimer(UGCGameSystem.GameState, function()
MyWeaponSystem.BackPackHandle1[PlayerKey] = nil
UGCGameSystem.GameState:UpdatePlayerWeapon(PlayerKey)
end, 1.)
-- 默认装备
if MyWeaponSystem.BackPackHandle2[PlayerKey] then UGCEventSystem.StopTimer(MyWeaponSystem.BackPackHandle2[PlayerKey]) end
MyWeaponSystem.BackPackHandle2[PlayerKey] = UGCEventSystem.SetTimer(UGCGameSystem.GameState, function()
MyWeaponSystem.BackPackHandle2[PlayerKey] = nil
local DefaultBackPack = TableHelper.DeepCopy(UGCGameSystem.GameState:GetPlayerBeBornParts(PlayerKey))
UGCGameSystem.GameState:PlayerAddItemInfo(PlayerKey, DefaultBackPack)
end, 2.)
-- 校验玩家的武器和配件1次
if MyWeaponSystem.BackPackHandle3[PlayerKey] then UGCEventSystem.StopTimer(MyWeaponSystem.BackPackHandle3[PlayerKey]) end
MyWeaponSystem.BackPackHandle3[PlayerKey] = UGCEventSystem.SetTimer(UGCGameSystem.GameState, function()
MyWeaponSystem.BackPackHandle3[PlayerKey] = nil
UGCGameSystem.GameState:CheckWeaponAndParts(PlayerKey)
end, 6.)
-- 校验玩家的武器和配件2次
if MyWeaponSystem.BackPackHandle4[PlayerKey] then UGCEventSystem.StopTimer(MyWeaponSystem.BackPackHandle4[PlayerKey]) end
MyWeaponSystem.BackPackHandle4[PlayerKey] = UGCEventSystem.SetTimer(UGCGameSystem.GameState, function()
MyWeaponSystem.BackPackHandle4[PlayerKey] = nil
UGCGameSystem.GameState:CheckWeaponAndParts(PlayerKey)
end, 8.)
-- 补满武器弹夹
UGCEventSystem.SetTimer(UGCGameSystem.GameState, function()
UGCSystemLibrary.PlayerFullBullet(PlayerKey)
end, 3.)
end

View File

@ -0,0 +1,303 @@
--[[
使
1GameState的
PlayerScoreSystem.RegisterInfo(InScoreList) InScoreList PlayerScoreSystem.Config.ScoreList
2
PlayerScoreSystem.InitPlayerScoreData(PlayerKey)
3GameState内
PlayerScoreSystem.BindChangeScoreDataCallBack(Func, Obj)
(1)GameState加入同步参数PlayerScoreDatas
(2)GameState的BeginPlay函数内加入
if UGCGameSystem.IsServer() then
-- 绑定更新积分的函数
PlayerScoreSystem.BindChangeScoreDataCallBack(self.UpdateAllPlayerScoreDatas, self)
end
(3)UpdateAllPlayerScoreDatas函数
function UGCGameState:UpdateAllPlayerScoreDatas()
self.PlayerScoreDatas = PlayerScoreSystem.GetPlayerScoreDatas()
end
(4)UpdateAllPlayerScoreDatas函数
function UGCGameState:UpdateAllPlayerScoreDatas()
self.PlayerScoreDatas = PlayerScoreSystem.GetPlayerScoreDatas()
end
(5)OnRep_PlayerScoreDatas函数
function UGCGameState:OnRep_PlayerScoreDatas()
PlayerScoreSystem.SetPlayerScoreDatas(self.PlayerScoreDatas)
UGCEventSystem.SendEvent(EventEnum.UpdatePlayerScoreData)
end
-------------------------------------------------------------------------------------------
-----------
--- Server 重置所有玩家的积分信息
PlayerScoreSystem.ResetAllPlayerScoreData()
--- Server 增加玩家积分
PlayerScoreSystem.AddPlayerScoreData(PlayerKey, ScoreType, AddVal)
--- Server 设置玩家积分
PlayerScoreSystem.SetPlayerScoreDataFromType(PlayerKey, ScoreType, Val)
--- Server or Client 获取玩家积分信息
---@return number
PlayerScoreSystem.GetPlayerScoreDataFromType(PlayerKey, ScoreType)
--- Server or Client 获取玩家得分 返回: ∑得分类型×类型对应得分
---@return number
PlayerScoreSystem.GetPlayerScore(PlayerKey)
--- Server or Client 获取玩家排名 InPlayerKeys:所需排名的PlayerKeys,若为nil则全部一起排名
---@return "table {PlayerKey, ...}"
PlayerScoreSystem.GetRank(InPlayerKeys)
--- Server or Client 获取队伍的玩家排名
---@return "table {[TeamID] = {PlayerKey, ...}, ...}"
PlayerScoreSystem.GetTeamRank()
--- Server 刷新或重设PlayerScoreSystem内的玩家TeamID
PlayerScoreSystem.UpdatePlayerTeamID(PlayerKey, TeamID)
-- 特殊情况需要用的函数 -----------
--- Server 移除玩家得分信息 NeedNotify是否通知更新 这个比较少用用于有玩家退出时再进行补人的操作放在PlayerExit内调用
PlayerScoreSystem.RemovePlayerScoreInfo(PlayerKey, NeedNotify)
--- Server 清除退出的玩家得分信息
PlayerScoreSystem.ClearExitPlayer()
]]
PlayerScoreSystem = PlayerScoreSystem or {}
PlayerScoreSystem.Config = {}
-- Config ----------------------------------------------------------------
PlayerScoreSystem.Config.EScoreType = {
Kills = 1,
Assists = 2,
Deaths = 3,
Damage = 4,
}
--- Key值对应得分类型Value值对应该类型每点所获得的积分
PlayerScoreSystem.Config.ScoreList = {
[PlayerScoreSystem.Config.EScoreType.Kills] = 0;
[PlayerScoreSystem.Config.EScoreType.Assists] = 0;
[PlayerScoreSystem.Config.EScoreType.Deaths] = -1;
[PlayerScoreSystem.Config.EScoreType.Damage] = 10;
}
-- Config End ------------------------------------------------------------
-- Params ----------------------------------------------------------------
-- 得分类型对应的分数 [ScoreType] = Score
PlayerScoreSystem.ScoreList = {};
-- 得分类型
PlayerScoreSystem.ScoreType = {};
-- 玩家得分信息 [PlayerKey] = {[ScoreType] = Score, ...} 额外附加 TeamID(PlayerScoreSystem.PlayerScoreDatas[PlayerKey].TeamID)
PlayerScoreSystem.PlayerScoreDatas = {};
-- Params End ------------------------------------------------------------
--- 注册积分类型列表
---@param InScoreList 可参考PlayerScoreSystem.Config.ScoreList
function PlayerScoreSystem.RegisterInfo(InScoreList)
if type(InScoreList) ~= "table" then
UGCLogSystem.LogError("[PlayerScoreSystem_RegisterInfo] InScoreType 类型错误")
end
PlayerScoreSystem.ScoreType = table.getKeys(InScoreList)
PlayerScoreSystem.ScoreList = InScoreList
UGCLogSystem.LogTree("[PlayerScoreSystem_RegisterInfo] ScoreType", PlayerScoreSystem.ScoreType)
UGCLogSystem.LogTree("[PlayerScoreSystem_RegisterInfo] ScoreList", PlayerScoreSystem.ScoreList)
end
--- Server or Client
--- 获取得分信息
function PlayerScoreSystem.GetPlayerScoreDatas()
return PlayerScoreSystem.PlayerScoreDatas
end
--- Server
--- 设置全部的得分信息 此操作不进行函数回调因为有可能是GameState的参数传进来的所以有可能导致死循环
function PlayerScoreSystem.SetPlayerScoreDatas(InPlayerScoreDatas)
PlayerScoreSystem.PlayerScoreDatas = InPlayerScoreDatas
end
--- Server
--- 绑定GameState的更新函数简化其他操作所以只能绑一个
function PlayerScoreSystem.BindChangeScoreDataCallBack(Func, Obj)
PlayerScoreSystem.ChangeScoreDataCallBackFunc = Func
PlayerScoreSystem.ChangeScoreDataCallBackObj = Obj
end
--- Server
--- 通知回调
function PlayerScoreSystem.NotifyChangeScoreDataCallBack()
if PlayerScoreSystem.ChangeScoreDataCallBackFunc then
if PlayerScoreSystem.ChangeScoreDataCallBackObj then
PlayerScoreSystem.ChangeScoreDataCallBackFunc(PlayerScoreSystem.ChangeScoreDataCallBackObj)
else
PlayerScoreSystem.ChangeScoreDataCallBackFunc()
end
end
end
--- Server
--- 初始化玩家的积分信息,也可作为重置函数使用
function PlayerScoreSystem.InitPlayerScoreData(PlayerKey, IsReset)
if PlayerScoreSystem.PlayerScoreDatas[PlayerKey] == nil or IsReset then
-- 初始化列表
PlayerScoreSystem.PlayerScoreDatas[PlayerKey] = {}
-- 初始化信息
for i, v in pairs(PlayerScoreSystem.ScoreType) do
PlayerScoreSystem.PlayerScoreDatas[PlayerKey][v] = 0
end
-- 设置队伍ID
PlayerScoreSystem.PlayerScoreDatas[PlayerKey].TeamID = UGCPlayerStateSystem.GetTeamID(PlayerKey)
UGCLogSystem.Log("[PlayerScoreSystem_InitPlayerScoreData] TeamID:%s", tostring(PlayerScoreSystem.PlayerScoreDatas[PlayerKey].TeamID))
-- 更新函数回调
PlayerScoreSystem.NotifyChangeScoreDataCallBack()
end
end
--- Server
--- 刷新玩家TeamID
function PlayerScoreSystem.UpdatePlayerTeamID(PlayerKey, TeamID)
if TeamID then
PlayerScoreSystem.PlayerScoreDatas[PlayerKey].TeamID = TeamID
else
PlayerScoreSystem.PlayerScoreDatas[PlayerKey].TeamID = UGCPlayerStateSystem.GetTeamID(PlayerKey)
end
UGCLogSystem.Log("[PlayerScoreSystem_UpdatePlayerTeamID] TeamID:%s", tostring(PlayerScoreSystem.PlayerScoreDatas[PlayerKey].TeamID))
PlayerScoreSystem.NotifyChangeScoreDataCallBack()
end
--- Server
--- 校验玩家积分信息是否初始化
function PlayerScoreSystem.CheckPlayerScoreDataIsInit(PlayerKey)
if PlayerScoreSystem.PlayerScoreDatas[PlayerKey] == nil then
UGCLogSystem.LogError("[PlayerScoreSystem_CheckPlayerScoreDataIsInit] PlayerKey:%s, 玩家信息未注册", tostring(PlayerKey))
PlayerScoreSystem.InitPlayerScoreData(PlayerKey)
end
end
--- Server
--- 重置所有玩家的积分信息
function PlayerScoreSystem.ResetAllPlayerScoreData()
for PlayerKey, v in pairs(PlayerScoreSystem.PlayerScoreDatas) do
PlayerScoreSystem.InitPlayerScoreData(PlayerKey, true)
end
PlayerScoreSystem.NotifyChangeScoreDataCallBack()
end
--- Server
--- 添加玩家积分信息
function PlayerScoreSystem.AddPlayerScoreData(PlayerKey, ScoreType, AddVal)
PlayerScoreSystem.CheckPlayerScoreDataIsInit(PlayerKey)
PlayerScoreSystem.PlayerScoreDatas[PlayerKey][ScoreType] = PlayerScoreSystem.PlayerScoreDatas[PlayerKey][ScoreType] + AddVal
PlayerScoreSystem.NotifyChangeScoreDataCallBack()
end
--- Server
--- 移除玩家得分信息
function PlayerScoreSystem.RemovePlayerScoreInfo(PlayerKey, NeedNotify)
PlayerScoreSystem.PlayerScoreDatas[PlayerKey] = nil
if NeedNotify == nil or NeedNotify then
PlayerScoreSystem.NotifyChangeScoreDataCallBack()
end
end
--- Server
--- 清除退出的玩家得分信息
function PlayerScoreSystem.ClearExitPlayer()
local AllPlayerKey = table.getKeys(PlayerScoreSystem.PlayerScoreDatas)
for i, v in pairs(AllPlayerKey) do
if UGCGameSystem.GetPlayerControllerByPlayerKey(v) == nil then
PlayerScoreSystem.RemovePlayerScoreInfo(v, false)
end
end
PlayerScoreSystem.NotifyChangeScoreDataCallBack()
end
--- Server
--- 设置玩家积分信息
function PlayerScoreSystem.SetPlayerScoreDataFromType(PlayerKey, ScoreType, Val)
PlayerScoreSystem.CheckPlayerScoreDataIsInit(PlayerKey)
PlayerScoreSystem.PlayerScoreDatas[PlayerKey][ScoreType] = Val
PlayerScoreSystem.NotifyChangeScoreDataCallBack()
end
--- Server or Client
--- 获取玩家积分信息
function PlayerScoreSystem.GetPlayerScoreDataFromType(PlayerKey, ScoreType)
PlayerScoreSystem.CheckPlayerScoreDataIsInit(PlayerKey)
return PlayerScoreSystem.PlayerScoreDatas[PlayerKey][ScoreType]
end
--- Server or Client
--- 获取玩家得分
---@return number
function PlayerScoreSystem.GetPlayerScore(PlayerKey)
PlayerScoreSystem.CheckPlayerScoreDataIsInit(PlayerKey)
local Res = 0
for i, v in pairs(PlayerScoreSystem.PlayerScoreDatas[PlayerKey]) do
if PlayerScoreSystem.ScoreList[i] then
Res = Res + PlayerScoreSystem.ScoreList[i] * v
end
end
return Res
end
--- Server or Client
--- 获取玩家排名
---@param InPlayerKeys "所需排名的PlayerKeys,若为nil则全部一起排名"
---@return "table {PlayerKey, ...}"
function PlayerScoreSystem.GetRank(InPlayerKeys)
local AllPlayerKey = {}
if InPlayerKeys == nil or type(InPlayerKeys) ~= "table" then
AllPlayerKey = table.getKeys(PlayerScoreSystem.PlayerScoreDatas)
else
AllPlayerKey = InPlayerKeys
end
table.sort(AllPlayerKey, function(a, b) return PlayerScoreSystem.GetPlayerScore(a) > PlayerScoreSystem.GetPlayerScore(b) end)
return AllPlayerKey
end
--- Server or Client
--- 获取队伍的玩家排名
---@return "table {[TeamID] = {PlayerKey, ...}, ...}"
function PlayerScoreSystem.GetTeamRank()
local Res = {}
-- 获取队伍玩家PlayerKey
local TeamPlayers = {}
for PlayerKey, ScoreInfo in pairs(PlayerScoreSystem.PlayerScoreDatas) do
if TeamPlayers[ScoreInfo.TeamID] == nil then TeamPlayers[ScoreInfo.TeamID] = {} end
TeamPlayers[ScoreInfo.TeamID][#TeamPlayers[ScoreInfo.TeamID] + 1] = PlayerKey
end
-- 获取队伍内排名
for TeamID, PlayerKeys in pairs(TeamPlayers) do
Res[TeamID] = PlayerScoreSystem.GetRank(PlayerKeys)
end
return Res
end

View File

@ -0,0 +1,151 @@
SoundSystem = SoundSystem or {}
SoundSystem.ESound = {
Scoll = 1,
Click = 2,
Btn = 3,
Kill = 4,
Kill2 = 5,
Kill3 = 6,
Incentive = 7,
ActiveMechanism = 8,
MechanismKill = 9,
HookFire = 101,
HookImpulse = 102,
Impulse = 103,
Dissipate = 104,
OkLetsGo = 105,
IsReady = 201,
Clock = 202,
TrapOpen = 203,
GameStart = 204,
Impact = 205, -- 击打音效
BreakWind = 206, -- 破风
Star = 207, -- 获得星星
Pu = 208,
Shot_Boom = 209,
Boom2 = 210,
AddScore = 211,
Error = 212,
Right = 213,
Point = 214;
PickUpBuff = 215;
KillFX = 216;
Explosion = 217;
-- Piano
Piano_3dd = 1073,
Piano_6dd = 1076,
Piano_2ddd = 1082,
}
SoundSystem.EMusic = {
-- UGC Music
Music1 = 100001 ,
Music2 = 100002 ,
Music3 = 100003 ,
Music4 = 100004 ,
Music5 = 100005 ,
Music6 = 100006 ,
Music7 = 100007 ,
Music8 = 100008 ,
Music9 = 100009 ,
Music10 = 100010 ,
Music11 = 100011 ,
Music12 = 100012 ,
Music13 = 100013 ,
}
SoundSystem.MusicName = {
[SoundSystem.EMusic.Music1 ] = "盛夏空投", -- 节奏
[SoundSystem.EMusic.Music2 ] = "赛博纪元", -- 科技节奏
[SoundSystem.EMusic.Music3 ] = "魔鬼纵队", -- 幽灵的感觉
[SoundSystem.EMusic.Music4 ] = "勇气", -- 人声
[SoundSystem.EMusic.Music5 ] = "四圣降临", -- 叶问的感觉
[SoundSystem.EMusic.Music6 ] = "沙漠绿洲", -- 平静
[SoundSystem.EMusic.Music7 ] = "锦绣年画", -- 过年 年年有余的感觉
[SoundSystem.EMusic.Music8 ] = "电音嘉年华",--类似悬溺
[SoundSystem.EMusic.Music9 ] = "空投行动", -- 射击长时间玩法
[SoundSystem.EMusic.Music10] = "未来之城", -- 跑酷等
[SoundSystem.EMusic.Music11] = "大战在即",
[SoundSystem.EMusic.Music12] = "激战隆冬",
[SoundSystem.EMusic.Music13] = "声动光影",
}
SoundSystem.SoundList = {
[SoundSystem.ESound.Scoll] = '/Game/WwiseEvent/UI/Play_UI_Item_Change.Play_UI_Item_Change',
[SoundSystem.ESound.Click] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Click_2_1.AK_Click_2_1'),
[SoundSystem.ESound.Btn] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Button_1.AK_Button_1'),
[SoundSystem.ESound.Kill] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/Audio_Kill.Audio_Kill'),
[SoundSystem.ESound.Kill2] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Kill2_1.AK_Kill2_1'),
[SoundSystem.ESound.Kill3] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Kill3_1.AK_Kill3_1'),
[SoundSystem.ESound.Incentive] = '/Game/WwiseEvent/UI/Play_UI_Champion.Play_UI_Champion',
[SoundSystem.ESound.ActiveMechanism] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_ActiveMechanism_1.AK_ActiveMechanism_1'),
[SoundSystem.ESound.MechanismKill] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_MechanismKill_1.AK_MechanismKill_1'),
[SoundSystem.ESound.HookFire] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/Ak_HookFire_1.Ak_HookFire_1'),
[SoundSystem.ESound.HookImpulse] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/Ak_HookImpulse_1.Ak_HookImpulse_1'),
[SoundSystem.ESound.Impulse] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/Ak_Impulse_1.Ak_Impulse_1'),
[SoundSystem.ESound.Dissipate] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Dissipate_1.AK_Dissipate_1'),
[SoundSystem.ESound.OkLetsGo] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_OkLetsGo_1.AK_OkLetsGo_1'),
[SoundSystem.ESound.IsReady] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_IsReady_1.AK_IsReady_1'),
[SoundSystem.ESound.Clock] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/T_Clock_1.T_Clock_1'),
[SoundSystem.ESound.TrapOpen] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_OpenDoor_1.AK_OpenDoor_1'),
[SoundSystem.ESound.GameStart] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_GameStart_1.AK_GameStart_1'),
[SoundSystem.ESound.Impact] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Impact_1.AK_Impact_1'),
[SoundSystem.ESound.BreakWind] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_BreakWind_1.AK_BreakWind_1'),
[SoundSystem.ESound.Star] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Star_1.AK_Star_1'),
[SoundSystem.ESound.Pu] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_PU_1.AK_PU_1'),
[SoundSystem.ESound.Shot_Boom] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AT_Shot_Boom_1.AT_Shot_Boom_1'),
[SoundSystem.ESound.Boom2] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Boom2_1.AK_Boom2_1'),
[SoundSystem.ESound.AddScore] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_AddScore_1.AK_AddScore_1'),
[SoundSystem.ESound.Error] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Error_1.AK_Error_1'),
[SoundSystem.ESound.Right] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Right_1.AK_Right_1'),
[SoundSystem.ESound.Point] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Point_1.AK_Point_1'),
[SoundSystem.ESound.PickUpBuff] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_PickUpBuff_1.AK_PickUpBuff_1');
[SoundSystem.ESound.KillFX] ='/Game/WwiseEvent/UI/Play_UI_KillEffect.Play_UI_KillEffect';
[SoundSystem.ESound.Explosion] ='/Game/WwiseEvent/Weapon_Player/Weapon_UCAV/Play_Weapon_UCAV_Explosion.Play_Weapon_UCAV_Explosion';
[SoundSystem.ESound.Piano_3dd] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Piano_3dd_1.AK_Piano_3dd_1'),
[SoundSystem.ESound.Piano_6dd] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Piano_6dd_1.AK_Piano_6dd_1'),
[SoundSystem.ESound.Piano_2ddd] = UGCGameSystem.GetUGCResourcesFullPath('Asset/WwiseEvent/AK_Piano_2ddd_1.AK_Piano_2ddd_1'),
[SoundSystem.EMusic.Music1 ] = '/Game/WwiseEvent/Music/Music_Main/Play_Music_Summer_Theme_CG014.Play_Music_Summer_Theme_CG014',
[SoundSystem.EMusic.Music2 ] = '/Game/WwiseEvent/Music/Music_Main/Play_Music_Cyberpunk_Theme.Play_Music_Cyberpunk_Theme',
[SoundSystem.EMusic.Music3 ] = '/Game/WwiseEvent/Music/Music_Main/Play_Music_Halloween.Play_Music_Halloween',
[SoundSystem.EMusic.Music4 ] = '/Game/WwiseEvent/Music/Music_Auto/Play_Music_Auto_Courage.Play_Music_Auto_Courage',
[SoundSystem.EMusic.Music5 ] = '/Game/WwiseEvent/Music/Music_Main/Play_Music_MythicalCreatures_CG011.Play_Music_MythicalCreatures_CG011',
[SoundSystem.EMusic.Music6 ] = '/Game/WwiseEvent/Music/Music_Main/Play_Music_SS6_Theme.Play_Music_SS6_Theme',
[SoundSystem.EMusic.Music7 ] = '/Game/WwiseEvent/Music/Music_Main/Play_CG021_Music_Gardens_SpringFestival_Theme.Play_CG021_Music_Gardens_SpringFestival_Theme',
[SoundSystem.EMusic.Music8 ] = '/Game/WwiseEvent/Music/Music_Main/Play_Music_717Summer_EDM.Play_Music_717Summer_EDM',
[SoundSystem.EMusic.Music9 ] = '/Game/WwiseEvent/Music/Music_Main/Play_CG018_Music_Celebration_Theme.Play_CG018_Music_Celebration_Theme',
[SoundSystem.EMusic.Music10] = '/Game/WwiseEvent/Music/Music_Main/Play_CG019_Music_FutureCity_Theme.Play_CG019_Music_FutureCity_Theme',
[SoundSystem.EMusic.Music11] = '/Game/WwiseEvent/Music/Music_Main/Play_Music_Snow_Theme_CG010.Play_Music_Snow_Theme_CG010',
[SoundSystem.EMusic.Music12] = '/Game/WwiseEvent/Music/Music_Main/Play_CG016_Music_Winter_Theme.Play_CG016_Music_Winter_Theme',
[SoundSystem.EMusic.Music13] = '/Game/WwiseEvent/Music/Music_Main/Play_Music_MovieStudio_Theme_CG015.Play_Music_MovieStudio_Theme_CG015',
}
function SoundSystem.PlaySound(SoundType, TargetLocation, TargetRotation)
if SoundSystem.SoundList[SoundType] ~= nil then
local AKSound = UGCSystemLibrary.LoadAsset(SoundSystem.SoundList[SoundType], true)
if TargetLocation then
if TargetRotation == nil then
TargetRotation = VectorHelper.RotZero()
end
return UGCSoundManagerSystem.PlaySoundAtLocation(AKSound, TargetLocation, TargetRotation)
else
return UGCSoundManagerSystem.PlaySound2D(AKSound)
end
end
end

View File

@ -0,0 +1,37 @@
--[[
[使]
========
local UGCDelegate = require("Script.Common.UGCDelegate");
local DelObj = UGCDelegate.New(self, self.SomeFunction);
========
DelObj:Execute(Par1, Par2, Par3);
--]]
---@class UGCDelegate
local UGCDelegate = LuaClass("UGCDelegate");
UGCDelegate.Object = nil;
UGCDelegate.Func = nil;
--- 构造函数
---@param InObject any
---@param InFunc function @函数变量
function UGCDelegate:ctor(InObject, InFunc)
self.Object = InObject;
self.Func = InFunc;
end
--- 调用回调函数
function UGCDelegate:Execute(...)
if self.Object ~= nil then
self.Func(self.Object, ...);
elseif self.Func ~= nil then
self.Func(...);
end
end
return UGCDelegate;

View File

@ -0,0 +1,66 @@
--[[
[使]
========
local UGCDelegateMulticast = require("Script.Common.UGCDelegateMulticast");
local DelObj = UGCDelegate.New(self, self.SomeFunction);
DelObj:Add(self, self.AnotherFunction);
========
DelObj:Broadcast(Par1, Par2, Par3);
--]]
---@class UGCDelegateMulticast
local UGCDelegateMulticast = LuaClass("UGCDelegateMulticast");
--- 绑定回调函数列表
UGCDelegateMulticast.EventsHandler = {};
--- 构造函数
---@param InObject any
---@param InFunc function @函数变量
function UGCDelegateMulticast:ctor(InObject, InFunc)
UGCDelegateMulticast:Add(InObject, InFunc);
end
--- 添加回调函数
---@param InObject any
---@param InFunc function @函数变量
function UGCDelegateMulticast:Add(InObject, InFunc)
table.insert(UGCDelegateMulticast.EventsHandler, {Object=InObject, Func=InFunc});
end
--- 移除回调函数
---@param InObject any
---@param InFunc function @函数变量
function UGCDelegateMulticast:Remove(InObject, InFunc)
for _, FuncData in pairs(UGCDelegateMulticast.EventsHandler) do
if FuncData.Object == InObject and FuncData.Func == InFunc then
FuncData.Object = nil;
FuncData.Func = nil;
end
end
end
--- 清除所有的回调绑定
function UGCDelegateMulticast:Clear()
self.EventsHandler = {};
end
--- 调用所有的回调函数
function UGCDelegateMulticast:Broadcast(...)
for _, FuncData in pairs(UGCDelegateMulticast.EventsHandler) do
if FuncData.Object ~= nil then
FuncData.Func(FuncData.Object, ...);
elseif FuncData.Func ~= nil then
FuncData.Func(...);
end
end
end
return UGCDelegateMulticast;

View File

@ -0,0 +1,108 @@
UGCEventSystem = UGCEventSystem or {}
UGCEventSystem.Events = {}
-- 添加监听
function UGCEventSystem.AddListener(EventType, Func, Object)
if EventType == nil or Func == nil or type(Func) ~= "function" then
UGCLogSystem.LogError("[UGCEventSystem_AddListener] EventType or Func is nil!")
return
end
local FuncData = {}
FuncData.Object = Object
FuncData.Func = Func
if UGCEventSystem.Events[EventType]==nil then
local NewEventFuncs={}
table.insert(NewEventFuncs ,FuncData)
UGCEventSystem.Events[EventType] = NewEventFuncs
--UGCLogSystem.Log("[UGCEventSystem_AddListener] EventType[%s], Func[%s]", tostring(EventType), tostring(Func))
else
table.insert(UGCEventSystem.Events[EventType], FuncData)
--UGCLogSystem.Log("[UGCEventSystem_AddListener] EventType[%s], Func[%s]", tostring(EventType), tostring(Func))
end
end
-- 移除监听
function UGCEventSystem.RemoveListener(EventType, Func, Object)
if EventType == nil or Func == nil then
UGCLogSystem.LogError("[UGCEventSystem_RemoveListener] EventType or Func is nil!")
return
end
if UGCEventSystem.Events[EventType] ~= nil then
for i = #UGCEventSystem.Events[EventType], 1, -1 do
local FuncData = UGCEventSystem.Events[EventType][i]
if FuncData.Func == Func and FuncData.Object == Object then
local result = table.remove(UGCEventSystem.Events[EventType], i)
UGCLogSystem.Log("[UGCEventSystem_RemoveListener] EventType[%s], Func[%s]", tostring(EventType), tostring(result))
break
end
end
else
UGCLogSystem.LogError("[UGCEventSystem_RemoveListener] EventFuncs[%s] is nil!", tostring(EventType))
end
end
-- 派发事件
function UGCEventSystem.SendEvent(EventType, ...)
UGCLogSystem.Log("[UGCEventSystem_SendEvent] EventType: %s", tostring(EventType))
if EventType ~= nil then
local EventFuncs = UGCEventSystem.Events[EventType];
if EventFuncs ~= nil then
for i, FuncData in pairs(EventFuncs) do
if FuncData.Object ~= nil then
FuncData.Func(FuncData.Object, ...)
else
FuncData.Func(...)
end
end
else
UGCLogSystem.LogError("[UGCEventSystem_SendEvent] EventFuncs[%s] is nil!", tostring(EventType))
end
end
end
--- SetTimer
---@param Obj UObject
---@param Fun fun()
---@param IntevalSeconds float
---@return TimerHandle
function UGCEventSystem.SetTimer(Obj, Fun, IntevalSeconds)
UGCLogSystem.Log("[UGCEventSystem_SetTimer] 设置定时器 %s:%s", UE.GetPathName(Obj), tostring(Fun))
local TimerDelegate = ObjectExtend.CreateDelegate(Obj, Fun, Obj)
local Handle = KismetSystemLibrary.K2_SetTimerDelegateForLua(TimerDelegate, Obj, IntevalSeconds, false)
local R = {}
R.Object = Obj
R.Handle = Handle
return R
end
--- SetTimerLoop
---@param Obj UObject
---@param Fun fun()
---@param IntevalSeconds float
---@return TimerHandle
function UGCEventSystem.SetTimerLoop(Obj, Fun, IntevalSeconds)
local TimerDelegate = ObjectExtend.CreateDelegate(Obj, Fun, Obj);
local Handle = KismetSystemLibrary.K2_SetTimerDelegateForLua(TimerDelegate, Obj, IntevalSeconds, true);
local R = {};
R.Object = Obj;
R.Handle = Handle;
UGCLogSystem.Log("[UGCEventSystem_SetTimerLoop] 设置循环定时器 %s:%s H:%s", UE.GetPathName(Obj), tostring(Fun), tostring(R));
return R;
end
--- StopTimer
---@param HandlePair TimerHandle
function UGCEventSystem.StopTimer(HandlePair)
if HandlePair == nil then
UGCLogSystem.LogError("[UGCEventSystem_StopTimer] HandlePair is nil")
else
UGCLogSystem.Log("[UGCEventSystem_StopTimer] 停止定时器 Object:%s Handle:%s", UE.GetPathName(HandlePair.Object), tostring(HandlePair.Handle));
KismetSystemLibrary.K2_ClearTimerHandle(HandlePair.Object, HandlePair.Handle);
end
end
return UGCEventSystem

View File

@ -0,0 +1,46 @@
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by LT.
--- DateTime: 2023/10/29 15:49
---
UGCLogSystem = UGCLogSystem or {}
UGCLogSystem.EnableLog = true
function UGCLogSystem.SetEnableLog(isEnable)
UGCLogSystem.EnableLog = isEnable
end
function UGCLogSystem.LogTag()
return "[UGCLogSystem] " .. (UGCGameSystem.IsServer() and "[Server]" or "[Client]")
end
function UGCLogSystem.Print(Log)
if not UGCLogSystem.EnableLog then return end
print(Log)
end
function UGCLogSystem.Log(Fmt, ...)
if not UGCLogSystem.EnableLog then return end
local LogStr = UGCLogSystem.LogTag()..string.format(Fmt, ...)
UGCLogSystem.Print(LogStr)
end
function UGCLogSystem.LogTree(Fmt, OutTable)
if not UGCLogSystem.EnableLog then return end
log_tree(Fmt, OutTable)
end
function UGCLogSystem.UGCLog(Fmt, ...)
if not UGCLogSystem.EnableLog then return end
ugcprint(string.format(Fmt, ...));
end
function UGCLogSystem.LogError(Fmt, ...)
if not UGCLogSystem.EnableLog then return end
local LogStr = UGCLogSystem.LogTag().."[LogicError]"..string.format(Fmt, ...)
UGCLogSystem.Print(LogStr)
end

View File

@ -0,0 +1,114 @@
--[[
:InitUGCSendRPCSystem
RPC InitUGCSendRPCSystem
InTargetObj内的目标RPC函数必须调用UGCSendRPCSystem.RPCFunc(...)
function UGCGameState:UGCSendRPCSystemFunc(...) UGCSendRPCSystem.RPCFunc(...) end
]]--
UGCSendRPCSystem = UGCSendRPCSystem or {}
UGCSendRPCSystem.DelegationObj = nil
UGCSendRPCSystem.DelegationFuncName = ""
---@param InTargetObj AActor*
---@param InUGCSendRPCSystemFuncName string
function UGCSendRPCSystem.InitUGCSendRPCSystem(InTargetObj, InUGCSendRPCSystemFuncName)
if UE.IsValid(InTargetObj) and type(InTargetObj[InUGCSendRPCSystemFuncName]) == "function" then
UGCSendRPCSystem.DelegationObj = InTargetObj
UGCSendRPCSystem.DelegationFuncName = InUGCSendRPCSystemFuncName
end
end
--- RPC自动发送 TargetPlayer为nil则广播到所有客户端为table则发送到包含的客户端为int32则发送到目标客户端
---@param RPCFuncName UGCSendRPCSystem的函数名称
---@param InTargetPlayer multi nil/table/int32
---@param ... any 事件输入的可变参数
function UGCSendRPCSystem.AutoTriggerRPC(RPCFuncName, InTargetPlayer, ...)
if not UGCSendRPCSystem.CheckUGCSendRPCSystem() then
UGCLogSystem.LogError("[UGCSendRPCSystem_AutoTriggerRPC] not initialized")
return false
end
if InTargetPlayer == nil then
if UGCGameSystem.IsServer() then
UnrealNetwork.CallUnrealRPC_Multicast(UGCSendRPCSystem.DelegationObj, UGCSendRPCSystem.DelegationFuncName, RPCFuncName, ...)
else
local TargetController = STExtraGameplayStatics.GetFirstPlayerController(UGCGameSystem.GameState)
if UE.IsValid(TargetController) then UnrealNetwork.CallUnrealRPC(TargetController, UGCSendRPCSystem.DelegationObj, UGCSendRPCSystem.DelegationFuncName, RPCFuncName, ...) end
end
elseif type(InTargetPlayer) == "number" then
local TargetController = nil
if UGCGameSystem.IsServer() then
TargetController = UGCGameSystem.GetPlayerControllerByPlayerKey(InTargetPlayer)
else
TargetController = STExtraGameplayStatics.GetFirstPlayerController(UGCGameSystem.GameState)
end
if UE.IsValid(TargetController) then UnrealNetwork.CallUnrealRPC(TargetController, UGCSendRPCSystem.DelegationObj, UGCSendRPCSystem.DelegationFuncName, RPCFuncName, ...) end
elseif type(InTargetPlayer) == "table" and UGCGameSystem.IsServer() then
for _, PlayerKey in pairs(InTargetPlayer) do
local TargetController = UGCGameSystem.GetPlayerControllerByPlayerKey(PlayerKey)
if UE.IsValid(TargetController) then UnrealNetwork.CallUnrealRPC(TargetController, UGCSendRPCSystem.DelegationObj, UGCSendRPCSystem.DelegationFuncName, RPCFuncName, ...) end
end
end
end
function UGCSendRPCSystem.RPCFunc(FuncName, ...) UGCSendRPCSystem[FuncName](...) end
function UGCSendRPCSystem.CheckUGCSendRPCSystem() return UE.IsValid(UGCSendRPCSystem.DelegationObj) end
------------------------------------------- Delegation Func -------------------------------------------
--- RPC委托调用事件
function UGCSendRPCSystem.RPCEvent(TargetPlayer, EventType, ...) UGCSendRPCSystem.AutoTriggerRPC("RPC_RPCEvent", TargetPlayer, EventType, ... ) end
function UGCSendRPCSystem.RPC_RPCEvent(EventType, ...) UGCEventSystem.SendEvent(EventType, ...) end
--- RPC委托触发Actor的函数
function UGCSendRPCSystem.ActorRPCNotify(TargetPlayer, TargetActor, FuncName, ...) UGCSendRPCSystem.AutoTriggerRPC("RPC_ActorRPCNotify", TargetPlayer, TargetActor, FuncName, ... ) end
function UGCSendRPCSystem.RPC_ActorRPCNotify(TargetActor, FuncName, ...)
if UE.IsValid(TargetActor) then
TargetActor[FuncName](TargetActor, ...)
else
UGCLogSystem.LogError("[UGCSendRPCSystem_RPC_ActorRPCNotify] Actor is nil. FuncName:%s", FuncName)
end
end
--- RPC委托触发模式编辑器的事件
function UGCSendRPCSystem.PlayActionEvent(TargetPlayer, EventName, ...) UGCSendRPCSystem.AutoTriggerRPC("RPC_PlayActionEvent", TargetPlayer, EventName, ... ) end
function UGCSendRPCSystem.RPC_PlayActionEvent(EventName, ...) UGCGameSystem.SendModeCustomEvent(EventName, ...) end
--- 客户端显示隐藏UI
function UGCSendRPCSystem.ClientShowUI(TargetPlayer, UIType, bShow, NeedClosePeerPanel, ...)
if UGCGameSystem.IsServer() then
if bShow == nil then bShow = true end
if NeedClosePeerPanel == nil then NeedClosePeerPanel = false end
UGCSendRPCSystem.AutoTriggerRPC("RPC_ClientShowUI", TargetPlayer, UIType, bShow, NeedClosePeerPanel, ... )
else
UGCLogSystem.LogError("[UGCSendRPCSystem_ClientShowUI] 仅服务器调用生效 UIType:%s", tostring(UIType))
end
end
function UGCSendRPCSystem.RPC_ClientShowUI(UIType, bShow, NeedClosePeerPanel, ...)
if bShow then WidgetManager:ShowPanel(UIType, NeedClosePeerPanel, ...) else WidgetManager:ClosePanel(UIType) end
end
function UGCSendRPCSystem.ExeStaticLogic(TargetPlayer, LogicType, FuncName, ...)
UGCSendRPCSystem.AutoTriggerRPC("RPC_ExeStaticLogic", TargetPlayer, LogicType, FuncName, ... )
end
function UGCSendRPCSystem.RPC_ExeStaticLogic(LogicType, FuncName, ...)
if table.hasValue(LogicConfig.ELogicType, LogicType) then
UGCLogSystem.Log("[UGCSendRPCSystem_RPC_ExeStaticLogic] FuncName:%s", FuncName)
local LogicStatic = require(LogicConfig.RequireList[LogicType])
UGCLogSystem.LogTree("[UGCSendRPCSystem_RPC_ExeStaticLogic] ", LogicStatic)
LogicStatic[FuncName](...)
else
UGCLogSystem.LogError("[UGCSendRPCSystem_RPC_ExeStaticLogic] LogicConfig.ELogicType[%s] is nil ", tostring(LogicType))
end
end

View File

@ -0,0 +1,760 @@
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)
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
---@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
--- 通过类名销毁物体
--- 拾取物"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
function UGCSystemLibrary.RespawnPlayer_V2(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
local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(PlayerKey)
if UE.IsValid(PC) then
-- UGCGameSystem.GameMode:RestartPlayer(PC)
local DefaultPawnClass = UGCGameSystem.GameMode:GetDefaultPawnClassForController(PC)
if DefaultPawnClass then
local Pawn = UGCGameSystem.SpawnActor(UGCGameSystem.GameState, DefaultPawnClass, VectorHelper.VectorZero(), VectorHelper.RotZero(), VectorHelper.ScaleOne())
PC:Possess(Pawn)
-- 将玩家重置到出生点
UGCEventSystem.SendEvent(EventEnum.ResetPlayerTransformToPlayerStart, PC, Pawn)
UGCLogSystem.Log("[UGCSystemLibrary_RespawnPlayer_V2] Finish")
else
UGCLogSystem.LogError("[UGCSystemLibrary_RespawnPlayer_V2]DefaultPawnClass is nil")
end
else
UGCLogSystem.LogError("[UGCSystemLibrary_RespawnPlayer_V2] [%s]PC is nil", tostring(PlayerKey))
end
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

View File

@ -0,0 +1,23 @@
local Action_PlayerDead = {
-- 可配置参数定义参数将显示在Action配置面板
-- 例:
-- MyIntParameter = 0
KillerPlayerKey = 0;
DeadPlayerKey = 0;
}
-- 触发器激活时将执行Action的Execute
function Action_PlayerDead:Execute(...)
return true
end
--[[
-- 需要勾选Action的EnableTick才会执行Update
-- 触发器激活后将在每个tick执行Action的Update直到self.bEnableActionTick为false
function Action_PlayerDead:Update(DeltaSeconds)
end
]]
return Action_PlayerDead

View File

@ -0,0 +1,23 @@
local Action_PlayerLeave = {
-- 可配置参数定义参数将显示在Action配置面板
-- 例:
-- MyIntParameter = 0
PlayerKey = 0;
}
-- 触发器激活时将执行Action的Execute
function Action_PlayerLeave:Execute(...)
ugcprint(string.format("[Action_PlayerLeave] Start settlement %d", self.PlayerKey));
UGCGameSystem.SendPlayerSettlement(self.PlayerKey);
return true
end
--[[
-- 需要勾选Action的EnableTick才会执行Update
-- 触发器激活后将在每个tick执行Action的Update直到self.bEnableActionTick为false
function Action_PlayerLeave:Update(DeltaSeconds)
end
]]
return Action_PlayerLeave

View File

@ -0,0 +1,16 @@
local Action_SendEvent =
{
SendEventName = "";
}
function Action_SendEvent:Execute()
print(string.format("Action_SendEvent:Execute SendEventName[%s]", self.SendEventName));
LuaQuickFireEvent(self.SendEventName, self);
return true;
end
return Action_SendEvent

View File

View File

@ -0,0 +1,90 @@
{
"BaseDir":"./",
"ShowWarnFlag": 1,
"ShareSymbolsFlag": 1,
"ReferMatchPathFlag": 0,
"GvalTipFlag": 1,
"IgnoreFileNameVarFlag": 1,
"ProjectFiles":[
],
"IgnoreModules":["hive", "import",
"TssManager", "GameFrontendHUD", "Vector", "Rotator", "bp_lobby", "Vector2D", "bp_global", "bp_authorization", "LobbyENV",
"InGameUIManager", "DSHUD", "Puffer", "BP_Platform", "LobbyG", "BP_MAP_ClubLogo", "BP_ARRAY_ClubLogo", "Instance",
"LinearColor", "LuaDebugHelper", "ScriptHelperServer", "ScriptHelperServer_WorldParallelism", "VSCodeLuaDebug",
"UE", "UAEUserWidget", "LogE", "Tss", "ObjectExtend" ,"UE_BUILD_SHIPPING","ImageManipulator","ImageDownloaderV2","ImageDownloaderV3","ImageEx","SlateBrush",
"DateTime","Timespan","KeepGameLiveInterface","Dolphin","BP_STRUCT_TeamUpFriendInfo","ComplaintFeedbackSummaryNotice","EncryptPakTest","DoReloadLua","LuaMemoryUI","BP_ARRAY_DynamicLevels","BP_ARRAY_lbsranktypetable",
"pakwhitelist","ConfigDownloader","extrapaklistneedmount","BP_ARRAY_Paradise","VideoConfigDownloader","TextBlock"
],
"IgnoreFileVars": [
{
"File": "client_entry.lua",
"Vars": ["UE_BUILD_SHIPPING", "Tss"]
}
,
{
"File": "util.lua",
"Vars": ["newestpakslist"]
}
],
"IgnoreReadFiles": [
],
"IgnoreErrorTypes": [
4,6,18
],
"IgnoreFileOrFloder": [
"lobby/on.*lua",
"tests/",
"robot/",
"coverage/"
],
"IgnoreFileErr": [
"lobby/gm1.lua",
"common/test.lua",
"Replay/Test.lua",
"test/luaunit.lua",
"improved_ingameui",
"ingame",
"Server",
"vsCodeDebugger",
"delete_lua"
],
"IgnoreFileErrTypes": [
{
"File": "gc_control.lua",
"Types": [3]
},
{
"File": "sandbox.lua",
"Types": [3]
}
],
"ProtocolVars": [
],
"AnntotateSets": [
{
"FuncName": "GetUIObject",
"ParamIndex": 2,
"SplitFlag": 0,
"PrefixStr": "",
"SuffixStr": ""
},
{
"FuncName": "KismetLibrary.New",
"ParamIndex": 1,
"SplitFlag": 1,
"PrefixStr": "",
"PrefixStrList": ["U", "A", ""],
"SuffixStr": ""
},
{
"FuncName": "CreateUIWidget",
"ParamIndex": 2,
"SplitFlag": 1,
"PrefixStr": "",
"SuffixStr": ""
}
]
}

BIN
FX_Preview/UGCmap.umap Normal file

Binary file not shown.

4
FX_Preview/WhiteList.ini Normal file
View File

@ -0,0 +1,4 @@
[WhiteList]
WhiteListUsrIdNum=0

View File

@ -0,0 +1,11 @@
{
"folders": [
{
"path": "Script"
},
{
"path": "..\\..\\Content\\LuaHelper"
}
],
"settings": {}
}