diff --git a/FX_Preview/Asset/Blueprint/SceneActor/BP_PreViewFXActor.uasset b/FX_Preview/Asset/Blueprint/SceneActor/BP_PreViewFXActor.uasset new file mode 100644 index 00000000..b8c70e24 Binary files /dev/null and b/FX_Preview/Asset/Blueprint/SceneActor/BP_PreViewFXActor.uasset differ diff --git a/FX_Preview/Asset/Blueprint/UGCGameMode.uasset b/FX_Preview/Asset/Blueprint/UGCGameMode.uasset new file mode 100644 index 00000000..ec87816d Binary files /dev/null and b/FX_Preview/Asset/Blueprint/UGCGameMode.uasset differ diff --git a/FX_Preview/Asset/Blueprint/UGCGameState.uasset b/FX_Preview/Asset/Blueprint/UGCGameState.uasset new file mode 100644 index 00000000..c3926b56 Binary files /dev/null and b/FX_Preview/Asset/Blueprint/UGCGameState.uasset differ diff --git a/FX_Preview/Asset/Blueprint/UGCLevelDirector.uasset b/FX_Preview/Asset/Blueprint/UGCLevelDirector.uasset new file mode 100644 index 00000000..cb518c3e Binary files /dev/null and b/FX_Preview/Asset/Blueprint/UGCLevelDirector.uasset differ diff --git a/FX_Preview/Asset/Blueprint/UGCPlayerController.uasset b/FX_Preview/Asset/Blueprint/UGCPlayerController.uasset new file mode 100644 index 00000000..8abcbed3 Binary files /dev/null and b/FX_Preview/Asset/Blueprint/UGCPlayerController.uasset differ diff --git a/FX_Preview/Asset/Blueprint/UGCPlayerPawn.uasset b/FX_Preview/Asset/Blueprint/UGCPlayerPawn.uasset new file mode 100644 index 00000000..fa18b941 Binary files /dev/null and b/FX_Preview/Asset/Blueprint/UGCPlayerPawn.uasset differ diff --git a/FX_Preview/Asset/Blueprint/UGCPlayerState.uasset b/FX_Preview/Asset/Blueprint/UGCPlayerState.uasset new file mode 100644 index 00000000..3bbe3dfe Binary files /dev/null and b/FX_Preview/Asset/Blueprint/UGCPlayerState.uasset differ diff --git a/FX_Preview/Asset/FX/KillFX/P_Kill_Boom.uasset b/FX_Preview/Asset/FX/KillFX/P_Kill_Boom.uasset new file mode 100644 index 00000000..e8e3b007 Binary files /dev/null and b/FX_Preview/Asset/FX/KillFX/P_Kill_Boom.uasset differ diff --git a/FX_Preview/Asset/FX/KillFX/P_Kill_Boom_Write.uasset b/FX_Preview/Asset/FX/KillFX/P_Kill_Boom_Write.uasset new file mode 100644 index 00000000..9854f871 Binary files /dev/null and b/FX_Preview/Asset/FX/KillFX/P_Kill_Boom_Write.uasset differ diff --git a/FX_Preview/Asset/FX/MuzzleFX/Rifle/Color/ColorBase/P_MF_Rifle_Purple.uasset b/FX_Preview/Asset/FX/MuzzleFX/Rifle/Color/ColorBase/P_MF_Rifle_Purple.uasset new file mode 100644 index 00000000..e4b05dad Binary files /dev/null and b/FX_Preview/Asset/FX/MuzzleFX/Rifle/Color/ColorBase/P_MF_Rifle_Purple.uasset differ diff --git a/FX_Preview/Asset/FX/MuzzleFX/Rifle/Color/ColorStrengthen/P_MF_Rifle_S_Purple.uasset b/FX_Preview/Asset/FX/MuzzleFX/Rifle/Color/ColorStrengthen/P_MF_Rifle_S_Purple.uasset new file mode 100644 index 00000000..cfc3474d Binary files /dev/null and b/FX_Preview/Asset/FX/MuzzleFX/Rifle/Color/ColorStrengthen/P_MF_Rifle_S_Purple.uasset differ diff --git a/FX_Preview/Asset/FX/MuzzleFX/Rifle/P_MF_Rifle_Base.uasset b/FX_Preview/Asset/FX/MuzzleFX/Rifle/P_MF_Rifle_Base.uasset new file mode 100644 index 00000000..eb631fa3 Binary files /dev/null and b/FX_Preview/Asset/FX/MuzzleFX/Rifle/P_MF_Rifle_Base.uasset differ diff --git a/FX_Preview/Asset/UGCGameAttributeCache.uasset b/FX_Preview/Asset/UGCGameAttributeCache.uasset new file mode 100644 index 00000000..cb6dbcb4 Binary files /dev/null and b/FX_Preview/Asset/UGCGameAttributeCache.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_AvatarFrame_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_AvatarFrame_UIBP.uasset new file mode 100644 index 00000000..977927bb Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_AvatarFrame_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_CheckBoxButton.uasset b/FX_Preview/Asset/UMGTemplate/General_CheckBoxButton.uasset new file mode 100644 index 00000000..2530fe33 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_CheckBoxButton.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_GameFailure_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_GameFailure_UIBP.uasset new file mode 100644 index 00000000..adb94b81 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_GameFailure_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_GameTopBlueTips_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_GameTopBlueTips_UIBP.uasset new file mode 100644 index 00000000..dd5b27ba Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_GameTopBlueTips_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_GameTopRedTips_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_GameTopRedTips_UIBP.uasset new file mode 100644 index 00000000..b45dd8d8 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_GameTopRedTips_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_GameVictory_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_GameVictory_UIBP.uasset new file mode 100644 index 00000000..70152c16 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_GameVictory_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Ingame_BloodVolButton.uasset b/FX_Preview/Asset/UMGTemplate/General_Ingame_BloodVolButton.uasset new file mode 100644 index 00000000..20054f00 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Ingame_BloodVolButton.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Ingame_RingButton.uasset b/FX_Preview/Asset/UMGTemplate/General_Ingame_RingButton.uasset new file mode 100644 index 00000000..39ebeec0 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Ingame_RingButton.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Ingame_SquareButton.uasset b/FX_Preview/Asset/UMGTemplate/General_Ingame_SquareButton.uasset new file mode 100644 index 00000000..18393c8a Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Ingame_SquareButton.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_NoticeLeftKillTips_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_NoticeLeftKillTips_UIBP.uasset new file mode 100644 index 00000000..4f1f7203 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_NoticeLeftKillTips_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_NoticeTopTips_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_NoticeTopTips_UIBP.uasset new file mode 100644 index 00000000..98bcb8fa Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_NoticeTopTips_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Player_infoBar_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_Player_infoBar_UIBP.uasset new file mode 100644 index 00000000..af24c24c Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Player_infoBar_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_SecondLevelButton_1.uasset b/FX_Preview/Asset/UMGTemplate/General_SecondLevelButton_1.uasset new file mode 100644 index 00000000..f09b05d5 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_SecondLevelButton_1.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_SecondLevelButton_2.uasset b/FX_Preview/Asset/UMGTemplate/General_SecondLevelButton_2.uasset new file mode 100644 index 00000000..0d0f61b7 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_SecondLevelButton_2.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_SecondLevelButton_3.uasset b/FX_Preview/Asset/UMGTemplate/General_SecondLevelButton_3.uasset new file mode 100644 index 00000000..2d91b687 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_SecondLevelButton_3.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Shop/General_Currency_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_Shop/General_Currency_UIBP.uasset new file mode 100644 index 00000000..173ac410 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Shop/General_Currency_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopItem_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopItem_UIBP.uasset new file mode 100644 index 00000000..f8ff4be4 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopItem_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopMain_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopMain_UIBP.uasset new file mode 100644 index 00000000..fa95b2b0 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopMain_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopPlay_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopPlay_UIBP.uasset new file mode 100644 index 00000000..e49e2a1b Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopPlay_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopPreviewItem_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopPreviewItem_UIBP.uasset new file mode 100644 index 00000000..08bcb7a0 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Shop/General_ShopPreviewItem_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_SlideModeButton.uasset b/FX_Preview/Asset/UMGTemplate/General_SlideModeButton.uasset new file mode 100644 index 00000000..fa6b1f17 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_SlideModeButton.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_SwitchButton.uasset b/FX_Preview/Asset/UMGTemplate/General_SwitchButton.uasset new file mode 100644 index 00000000..03def755 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_SwitchButton.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_TMode_Discard_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_TMode_Discard_UIBP.uasset new file mode 100644 index 00000000..5b3d30df Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_TMode_Discard_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/General_Team_ScoreBoard_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/General_Team_ScoreBoard_UIBP.uasset new file mode 100644 index 00000000..98277531 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/General_Team_ScoreBoard_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_EditLocation.uasset b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_EditLocation.uasset new file mode 100644 index 00000000..11bcfcbe Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_EditLocation.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_ItemSelect.uasset b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_ItemSelect.uasset new file mode 100644 index 00000000..fa920e87 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_ItemSelect.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_ItemSelect_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_ItemSelect_UIBP.uasset new file mode 100644 index 00000000..120082c5 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_ItemSelect_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Main_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Main_UIBP.uasset new file mode 100644 index 00000000..0518bdaf Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Main_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Playerlist_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Playerlist_UIBP.uasset new file mode 100644 index 00000000..e70a029d Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Playerlist_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_PropsItem.uasset b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_PropsItem.uasset new file mode 100644 index 00000000..328bcba2 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_PropsItem.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Props_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Props_UIBP.uasset new file mode 100644 index 00000000..d2fbc13f Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Props_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Settlement_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Settlement_UIBP.uasset new file mode 100644 index 00000000..df5e69c9 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Peekaboo/Peekaboo_Settlement_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/ReuseList2.uasset b/FX_Preview/Asset/UMGTemplate/ReuseList2.uasset new file mode 100644 index 00000000..1b16968a Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/ReuseList2.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Settlement/Common_RankTitleInfo_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Settlement/Common_RankTitleInfo_UIBP.uasset new file mode 100644 index 00000000..8113bc3f Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Settlement/Common_RankTitleInfo_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Settlement/General_BattleDataList_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Settlement/General_BattleDataList_UIBP.uasset new file mode 100644 index 00000000..9053a87f Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Settlement/General_BattleDataList_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Settlement/General_BattleDetail_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Settlement/General_BattleDetail_UIBP.uasset new file mode 100644 index 00000000..88432784 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Settlement/General_BattleDetail_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Settlement/General_ListDataBG_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Settlement/General_ListDataBG_UIBP.uasset new file mode 100644 index 00000000..adf81361 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Settlement/General_ListDataBG_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Settlement/General_Team_ModeList_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Settlement/General_Team_ModeList_UIBP.uasset new file mode 100644 index 00000000..cf03da42 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Settlement/General_Team_ModeList_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Settlement/General_Team_ModeMain_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Settlement/General_Team_ModeMain_UIBP.uasset new file mode 100644 index 00000000..a3824701 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Settlement/General_Team_ModeMain_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Settlement/General_TitleBattleDetail_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Settlement/General_TitleBattleDetail_UIBP.uasset new file mode 100644 index 00000000..c44cf6d2 Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Settlement/General_TitleBattleDetail_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/Settlement/General_TopBG_UIBP.uasset b/FX_Preview/Asset/UMGTemplate/Settlement/General_TopBG_UIBP.uasset new file mode 100644 index 00000000..c337497b Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/Settlement/General_TopBG_UIBP.uasset differ diff --git a/FX_Preview/Asset/UMGTemplate/UGC_DragDropTextBox.uasset b/FX_Preview/Asset/UMGTemplate/UGC_DragDropTextBox.uasset new file mode 100644 index 00000000..b2b919ee Binary files /dev/null and b/FX_Preview/Asset/UMGTemplate/UGC_DragDropTextBox.uasset differ diff --git a/FX_Preview/DeleteFiles.txt b/FX_Preview/DeleteFiles.txt new file mode 100644 index 00000000..e69de29b diff --git a/FX_Preview/FX_Preview.ugcproj b/FX_Preview/FX_Preview.ugcproj new file mode 100644 index 00000000..f23cc67d --- /dev/null +++ b/FX_Preview/FX_Preview.ugcproj @@ -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; + + diff --git a/FX_Preview/Script/Blueprint/SceneActor/BP_PreViewFXActor.lua b/FX_Preview/Script/Blueprint/SceneActor/BP_PreViewFXActor.lua new file mode 100644 index 00000000..48dd2f37 --- /dev/null +++ b/FX_Preview/Script/Blueprint/SceneActor/BP_PreViewFXActor.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/Blueprint/UGCGameMode.lua b/FX_Preview/Script/Blueprint/UGCGameMode.lua new file mode 100644 index 00000000..087404d3 --- /dev/null +++ b/FX_Preview/Script/Blueprint/UGCGameMode.lua @@ -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; \ No newline at end of file diff --git a/FX_Preview/Script/Blueprint/UGCGameState.lua b/FX_Preview/Script/Blueprint/UGCGameState.lua new file mode 100644 index 00000000..ad2396ea --- /dev/null +++ b/FX_Preview/Script/Blueprint/UGCGameState.lua @@ -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; diff --git a/FX_Preview/Script/Blueprint/UGCPlayerPawn.lua b/FX_Preview/Script/Blueprint/UGCPlayerPawn.lua new file mode 100644 index 00000000..219892a1 --- /dev/null +++ b/FX_Preview/Script/Blueprint/UGCPlayerPawn.lua @@ -0,0 +1,177 @@ +---@class UGCPlayerPawn_C:BP_UGCPlayerPawn_C +---@field StartItemID TArray +--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 \ No newline at end of file diff --git a/FX_Preview/Script/Common/ue_enum_custom.lua b/FX_Preview/Script/Common/ue_enum_custom.lua new file mode 100644 index 00000000..d2f63222 --- /dev/null +++ b/FX_Preview/Script/Common/ue_enum_custom.lua @@ -0,0 +1,4 @@ +-- auto exported UENUM while compiling + +-- sorted by enum name asc + diff --git a/FX_Preview/Script/Global/EventConfig.lua b/FX_Preview/Script/Global/EventConfig.lua new file mode 100644 index 00000000..54d15814 --- /dev/null +++ b/FX_Preview/Script/Global/EventConfig.lua @@ -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 + + + +} \ No newline at end of file diff --git a/FX_Preview/Script/Global/FunctionExtension/A_IncludeFunctionExtension.lua b/FX_Preview/Script/Global/FunctionExtension/A_IncludeFunctionExtension.lua new file mode 100644 index 00000000..7331ef84 --- /dev/null +++ b/FX_Preview/Script/Global/FunctionExtension/A_IncludeFunctionExtension.lua @@ -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') + + + diff --git a/FX_Preview/Script/Global/FunctionExtension/MathExtension.lua b/FX_Preview/Script/Global/FunctionExtension/MathExtension.lua new file mode 100644 index 00000000..50491239 --- /dev/null +++ b/FX_Preview/Script/Global/FunctionExtension/MathExtension.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/Global/FunctionExtension/QuatHelper.lua b/FX_Preview/Script/Global/FunctionExtension/QuatHelper.lua new file mode 100644 index 00000000..a21c50cc --- /dev/null +++ b/FX_Preview/Script/Global/FunctionExtension/QuatHelper.lua @@ -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; \ No newline at end of file diff --git a/FX_Preview/Script/Global/FunctionExtension/StringExtension.lua b/FX_Preview/Script/Global/FunctionExtension/StringExtension.lua new file mode 100644 index 00000000..949bdab2 --- /dev/null +++ b/FX_Preview/Script/Global/FunctionExtension/StringExtension.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/Global/FunctionExtension/TableExtension.lua b/FX_Preview/Script/Global/FunctionExtension/TableExtension.lua new file mode 100644 index 00000000..a329866e --- /dev/null +++ b/FX_Preview/Script/Global/FunctionExtension/TableExtension.lua @@ -0,0 +1,259 @@ +-- 拷贝table +function table.DeepCopy(object) + -- 已经复制过的table,key为复制源table,value为复制后的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 \ No newline at end of file diff --git a/FX_Preview/Script/Global/FunctionExtension/TableHelper.lua b/FX_Preview/Script/Global/FunctionExtension/TableHelper.lua new file mode 100644 index 00000000..8e5bf23d --- /dev/null +++ b/FX_Preview/Script/Global/FunctionExtension/TableHelper.lua @@ -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) + -- 已经复制过的table,key为复制源table,value为复制后的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; \ No newline at end of file diff --git a/FX_Preview/Script/Global/FunctionExtension/VectorHelper.lua b/FX_Preview/Script/Global/FunctionExtension/VectorHelper.lua new file mode 100644 index 00000000..9f581187 --- /dev/null +++ b/FX_Preview/Script/Global/FunctionExtension/VectorHelper.lua @@ -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; \ No newline at end of file diff --git a/FX_Preview/Script/Global/Global.lua b/FX_Preview/Script/Global/Global.lua new file mode 100644 index 00000000..c881ff2f --- /dev/null +++ b/FX_Preview/Script/Global/Global.lua @@ -0,0 +1,9 @@ + +require('Script.Global.EventConfig') + +--- 函数拓展 +require('Script.Global.FunctionExtension.A_IncludeFunctionExtension') +--- 各系统功能文件 依赖函数拓展、事件系统、函数拓展 +require('Script.Global.System.A_IncludeSystem') + + diff --git a/FX_Preview/Script/Global/System/A_IncludeSystem.lua b/FX_Preview/Script/Global/System/A_IncludeSystem.lua new file mode 100644 index 00000000..307a38b8 --- /dev/null +++ b/FX_Preview/Script/Global/System/A_IncludeSystem.lua @@ -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') diff --git a/FX_Preview/Script/Global/System/LevelStreamUtil.lua b/FX_Preview/Script/Global/System/LevelStreamUtil.lua new file mode 100644 index 00000000..9072362e --- /dev/null +++ b/FX_Preview/Script/Global/System/LevelStreamUtil.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/Global/System/MyVehicleSystem.lua b/FX_Preview/Script/Global/System/MyVehicleSystem.lua new file mode 100644 index 00000000..648f4b4c --- /dev/null +++ b/FX_Preview/Script/Global/System/MyVehicleSystem.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/Global/System/MyWeaponSystem.lua b/FX_Preview/Script/Global/System/MyWeaponSystem.lua new file mode 100644 index 00000000..df5069ef --- /dev/null +++ b/FX_Preview/Script/Global/System/MyWeaponSystem.lua @@ -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 diff --git a/FX_Preview/Script/Global/System/PlayerScoreSystem.lua b/FX_Preview/Script/Global/System/PlayerScoreSystem.lua new file mode 100644 index 00000000..6d7ea6d9 --- /dev/null +++ b/FX_Preview/Script/Global/System/PlayerScoreSystem.lua @@ -0,0 +1,303 @@ +--[[ +使用说明 + +1、注册积分类型列表,放在GameState的 +PlayerScoreSystem.RegisterInfo(InScoreList) 其中InScoreList 可参考PlayerScoreSystem.Config.ScoreList + +2、在玩家加入时添加 +PlayerScoreSystem.InitPlayerScoreData(PlayerKey) + +3、绑定得分表的更新函数,更新函数内可以设置同步参数,参数放置GameState内 +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 + + + + + + diff --git a/FX_Preview/Script/Global/System/SoundSystem.lua b/FX_Preview/Script/Global/System/SoundSystem.lua new file mode 100644 index 00000000..67656c5a --- /dev/null +++ b/FX_Preview/Script/Global/System/SoundSystem.lua @@ -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 + diff --git a/FX_Preview/Script/Global/System/UGCDelegate.lua b/FX_Preview/Script/Global/System/UGCDelegate.lua new file mode 100644 index 00000000..f8fefa21 --- /dev/null +++ b/FX_Preview/Script/Global/System/UGCDelegate.lua @@ -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; \ No newline at end of file diff --git a/FX_Preview/Script/Global/System/UGCDelegateMulticast.lua b/FX_Preview/Script/Global/System/UGCDelegateMulticast.lua new file mode 100644 index 00000000..e3565835 --- /dev/null +++ b/FX_Preview/Script/Global/System/UGCDelegateMulticast.lua @@ -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; \ No newline at end of file diff --git a/FX_Preview/Script/Global/System/UGCEventSystem.lua b/FX_Preview/Script/Global/System/UGCEventSystem.lua new file mode 100644 index 00000000..d354ff6c --- /dev/null +++ b/FX_Preview/Script/Global/System/UGCEventSystem.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/Global/System/UGCLogSystem.lua b/FX_Preview/Script/Global/System/UGCLogSystem.lua new file mode 100644 index 00000000..1a1393ee --- /dev/null +++ b/FX_Preview/Script/Global/System/UGCLogSystem.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/Global/System/UGCSendRPCSystem.lua b/FX_Preview/Script/Global/System/UGCSendRPCSystem.lua new file mode 100644 index 00000000..0d47b995 --- /dev/null +++ b/FX_Preview/Script/Global/System/UGCSendRPCSystem.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/Global/System/UGCSystemLibrary.lua b/FX_Preview/Script/Global/System/UGCSystemLibrary.lua new file mode 100644 index 00000000..079f8213 --- /dev/null +++ b/FX_Preview/Script/Global/System/UGCSystemLibrary.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/gamemode/Action_PlayerDead.lua b/FX_Preview/Script/gamemode/Action_PlayerDead.lua new file mode 100644 index 00000000..5d8b7829 --- /dev/null +++ b/FX_Preview/Script/gamemode/Action_PlayerDead.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/gamemode/Action_PlayerLeave.lua b/FX_Preview/Script/gamemode/Action_PlayerLeave.lua new file mode 100644 index 00000000..33b69e92 --- /dev/null +++ b/FX_Preview/Script/gamemode/Action_PlayerLeave.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/gamemode/Action_SendEvent.lua b/FX_Preview/Script/gamemode/Action_SendEvent.lua new file mode 100644 index 00000000..aaff8780 --- /dev/null +++ b/FX_Preview/Script/gamemode/Action_SendEvent.lua @@ -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 \ No newline at end of file diff --git a/FX_Preview/Script/gamemode/readme.txt b/FX_Preview/Script/gamemode/readme.txt new file mode 100644 index 00000000..e69de29b diff --git a/FX_Preview/Script/luahelper.json b/FX_Preview/Script/luahelper.json new file mode 100644 index 00000000..7d7d8bb7 --- /dev/null +++ b/FX_Preview/Script/luahelper.json @@ -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": "" + } + ] +} \ No newline at end of file diff --git a/FX_Preview/UGCmap.umap b/FX_Preview/UGCmap.umap new file mode 100644 index 00000000..6eb32240 Binary files /dev/null and b/FX_Preview/UGCmap.umap differ diff --git a/FX_Preview/WhiteList.ini b/FX_Preview/WhiteList.ini new file mode 100644 index 00000000..4d601fac --- /dev/null +++ b/FX_Preview/WhiteList.ini @@ -0,0 +1,4 @@ +[WhiteList] +WhiteListUsrIdNum=0 + + diff --git a/FX_Preview/workspace.code-workspace b/FX_Preview/workspace.code-workspace new file mode 100644 index 00000000..2c70c2f4 --- /dev/null +++ b/FX_Preview/workspace.code-workspace @@ -0,0 +1,11 @@ +{ + "folders": [ + { + "path": "Script" + }, + { + "path": "..\\..\\Content\\LuaHelper" + } + ], + "settings": {} +} \ No newline at end of file