From c48a9deb6605204ebb886ecced6f5adccc0e3623 Mon Sep 17 00:00:00 2001 From: Ggafrik <906823881@qq.com> Date: Wed, 23 Jul 2025 23:54:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0-=E6=A8=A1=E5=9E=8B+=E5=8A=A8?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E9=80=9A=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- excel/anim.xlsx | Bin 0 -> 16323 bytes excel/equipment.xlsx | Bin 9619 -> 9768 bytes excel/global.xlsx | Bin 22112 -> 22172 bytes .../Base/BehaviourClient.luau | 40 ++++++ src/ReplicatedStorage/Base/UIWindow.luau | 8 ++ src/ReplicatedStorage/Json/Animation.json | 3 + src/ReplicatedStorage/Json/Equipment.json | 32 ++--- src/ReplicatedStorage/Json/Param.json | 3 +- .../Modules/BehavioursClient/SwordWave.luau | 4 + .../Modules/EffectDispatcher.luau | 5 +- src/ReplicatedStorage/Tools/Utils.luau | 7 + src/ServerStorage/Proxy/EquipmentProxy.luau | 14 +- .../Proxy/PlayerFightProxy/init.luau | 2 +- src/ServerStorage/Proxy/PlayerInfoProxy.luau | 1 - .../ClientMain/DefaultUIClose.luau | 6 + .../ClientMain/MeleeMobAlign.luau | 127 +++++++++--------- .../ClientMain/PerformanceClient/init.luau | 1 + .../ClientMain/WeaponModel.luau | 85 ++++++++++++ .../UI/InstanceScripts/Money.client.luau | 57 ++++++++ .../AttributeLvupShow.luau | 24 ++-- .../UI/Windows/AttributeLvupWindow/init.luau | 14 ++ .../UI/Windows/ChaWindow/init.luau | 19 +-- .../UI/Windows/TipsWindow/init.luau | 63 +++++++++ 23 files changed, 413 insertions(+), 102 deletions(-) create mode 100644 excel/anim.xlsx create mode 100644 src/ReplicatedStorage/Json/Animation.json create mode 100644 src/StarterPlayerScripts/ClientMain/DefaultUIClose.luau create mode 100644 src/StarterPlayerScripts/ClientMain/WeaponModel.luau create mode 100644 src/StarterPlayerScripts/UI/InstanceScripts/Money.client.luau create mode 100644 src/StarterPlayerScripts/UI/Windows/TipsWindow/init.luau diff --git a/excel/anim.xlsx b/excel/anim.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..52ebc72280a03b014f146dc4d5df39291832e83b GIT binary patch literal 16323 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 bCjQUZtt1EaW`h6#;@gMv&5T3%|JeIKgAayM literal 0 HcmV?d00001 diff --git a/excel/equipment.xlsx b/excel/equipment.xlsx index 1a1e49ee4c974a747b4ba9e39908f4a09297f65a..8488c3a0aac4e65990f6412e38d202c8b66db9f2 100644 GIT binary patch delta 3206 zcmZ8jc{CJk7au0eOxBE@OqLOe7+GHX77ZG^?E4zB4SE^F2xDJHBl{pk#S~>ovMc+N zE!ia{A=|t$eAV}Ur*ppNk9(f;{O<2Q=iYmM=lt-74~FuefA|8}_& z+e!2om7yyf49n!UXvPAX4K^kF*50dBn|mu|FZ_WgpI)ij}{3h=am7c&69$5u1Jkkbf>&>>< zRf9nE3jw^P?Bd2+hBI-D`EH=Sja1A17^_UfMX;1(ejl{uA;7gW7`E`2iNhsaV}x{5 zTYJ_gCBM6@BZMw7YwaCE%$l3CC!^^KavSS zeWJ!_G_6i+c`s-iA#XWN60q9*JP?N3U4wqAh@n|ke70ih1@{;kZF1c~OtfLb#qFw2hek@9Szavm zLp3vu`r&qtnpYc7nkOOqC5aR6q~QYDPdyjGG*Ng(Zo%{mLd<02?-y=Esuy& zj}Y&>c_EwC7`HBAJ%{s&MQ1*_OUO^465#GLa1SlJJ9hoG3>C7@IDt#|Z^C;?%UQRS z0%cOG;m^{VIA)%zB$X?LS|(dOKRn6Ep90PEtBWLiB*fdFHF8{BsV|#ln<7@vUsyaU z_FKQ9C9gSp-NaSN+mqKtDU3-GaqZg~z1?Z!boYBlvrep5h1D~gl{XavEhjE-_7wZ# zsb5`!XOUmcQNh#}%LmJ?3)I^QPHjhpj^2eIoV=AzqZ(UZjvOdBYN(0k@-c+FKaiO&qc9^3yJez!JTw5z+alP~VW&D&Q%R+`IeoTG%(;@nx>U zwXph4SjRdGdxgcAP~=51+g0So#xr=Q| z;OwJ|-J=@vGY{L9e8-gfp4k*q^(g@mSAqCl#wUotXfd5KOuYv>83OAcAnno-!w@w`RC>S^)HCk70 zL95MUCKT^I>FLzhXj!C@?gkj7oV|RFX;9i;j$HKS|?g~8C3U}7X-`SFaYEMR0yoQ8xwA-Vtv zdVmo|hUZwyg-V`oRdTv|nB`WaFyIWz22&Bj=8-gt+xEh0;Ft4cKZTGr^BAuxU=>fiO>+0GRTxaU1k(&+<>nPh z&>!CJQ7mUKLEjxKedRSegPPIB%6qUstIyKcft}D}xOBB}5DE0}3<2e@zy2>U$gY$^ zgeicvJ+J@l^TOBz_TP>A77H9OX`193iz3XqBvkn6F2Kd4a9FnLF~*Y44lv_YYnGpL zc-RliuDEPSC`!X-zCFj)rMVi#!u>$&%2o2!1T`_nwP$iR=~Ru$6Pn*rskdUsgE858 z(-+2mJ}@x=0Fa;ZiSUyN@pcLJa5oPP_6hI`k&f{9Yq*CrT)o26vxQwKU9}faTN!9J zv}47RxOWyE1rA31SB!|p&Bl^L{%7>8*>g~=DZ~w-!dE!y6yY+8Lsw|e?Wdzz9-0H~ z(7nvPsl⋙^+mk+wOJ0!KG9T$2GMW1Pkd3vyHCz9I&KPJmFewx1MG>)Dsd(Oj73A zWni!$imz~$IMmd^?E&wq`YnnsiV<9E-bnRlYd-X`N>m*TWZR+d5l&hntys96V*@|V z{AdwDw574S@peiel=-WxzGEybLwdvJZJX-2j!t8j^j|v0cnAuN zwkNY#p|*=y(!VT53hJg44iHOp{F#%Y4^SWwuW4+NMP0?$AI_#z-9-6NMJ8~yqYK^P6j z6d88~62D-4%=%!<1Uy^FOwt`Jws#f2wqiFvFDrc6*v{kVkZU^7v!^$5_;dL1E1wtd z`(YGXw+*Y0I9*w==8o07n!ZuPCYIcbq;!e)d@HSV7U$6#a%&&CvgPWwyDf9igfkFn zMhGq{FAB+b_4|iKv_32RqD+9DNZu}{qMGD+9A_DWS8{X)rGwUZzQvXnJpJj+xvLEYr@oa-sMV;4tONhS2ZsA4MBhv2l@dWml9 z`0x4i8acNtL}l|5cZ5?viP@M18;;LJYV1!PsZUO4_RgH1<3P56@C~ByeCf|$*HR;B zA-t^=aJS-r-Ns)~W8l9AKUKtx27zA?xy=8^eE>v0mzE%_}@c%;ngKG%jzlg#FesA%olC5b00QNuV&zsJ9yp)(4O*`IKOoTpL HRQZ)#KW~hN6y{Z%`Qk4=!A@trs zqzclDAP5Lgzj^b`d;8bm~=UXH4A7%)q-T9oX(B^+CYPqO;$cf8J#exHyxiBY%# zFq*_?0*!;3Yz3eTqzv$?DljqY5D53u|fvo%QpRpg@|D%kVs|pGix80W#}!*3!X(jJpNVkI8*1 zI3eg+Cs=}va10^yg{meM%^WPlVEg^j(H*(ZY-0BBQS>vS6%4Z$@b0CaQ5w%^W~V?J zeOhTev{@7TI}3U5T$Bw*wv9{icuE%r6WU>en>HMq(P+=$VYH3&%WV4ULBsK9fI4?&V84fTMor-h2v>D`IE;wGd*{R2M{$sRV;C7buXj@ zXR%$V{h+uedGH;^Yyqmu?ns3(JPu#*v0J0x44CFN07H1XLcwDRDHpYqN6oMC$3#+2F7 zkXPj8SlFh`C+E2y1c#H)F$p%Agb8cO3$8_i_=v&#>(AA=$N+#@W&i*Jz_#+TU~8%A zQHA8_w`G-u^UY;lj~t`yItk-9ZYfq*Er0o5o|2+2%Ln58nYrpy$WN_)AABy}`qTM6QIm=Q?bCJJT1>k6z!Er@Z zNmfU^KB@M^)*Iec7}68Pz^d55aaaH2L|+p%}D+(=o87xtxG;-KXM1d61P))s_r)=DE~ zMMB$4A<3d5kRYpR~<(v=?SZZf_|Zu_?JW|2PX_a|`pYDD)D`x1hyuG`X)fahZhoiRDA6}3^BWg<&1<3iacyqr(#>c*$HKEwDQdnD?TM+h3PL0KSN79A zm(tl1KJiq@#F+@Z78xMt%Gx-sgS|ag>MsGT zeCPS&RsX) zDlbq#6-2O&Dg{FB`DPi|2rc9Q#2k_)7N%gtW@zK@*4vL`z%B|vgoS@tuh~tXhb-Ud z+0}ms2%q0Koj-z4(matVBC#?go-kv}_enc$)&P6iG+1a8nm3~f{`KG@q@SHQ*FTv* z^q$=}D8yNE6@yU?{7dhvt1f%0eOEVt-{cV+nl-FXHBMqF#o|rZdd!4)0$m(J2*N;zca8 zoD$iq;hu8ihjuHb$gL>yPl?WHm{B5TgM5wt6r-7#`!&vvW{&4|D@NX?qrh0u60_yl6Fly>{pPrpj8Mx;?wv%ea~#D0g8u-G!)X^Dj8Y!0Ea# zP?c62^)&b5NAcA(RkQv4bi0HA<~D#?#LjNBHf$J9@wP%#e}FiGDv{ha$9Ox8e9f*s zC%gLA^{8=^-7r)p-H3eTm#U@V6|!sgLOuL1?izNxwvYueIf^aHVAStLtM`?C9Ohwy zDC(AYDVGvsB2#uq#S(0p*25n8F3*1AdrpIXq$%?O&v~ii?k*{WBe8^wtMR0$8#i=+ zAL0l2d7Qq2m9{AkkC=*$k1`7R;Z7oBdNjDjr@WKZ5mP9C>Y6#^W#F5YBqcW5y`d=C z^HIA|m9IIVyrox8~H4LHgb*rPARc1r)&mDL*7n0BwGPJRm8#3ni zG|7LTj9?z$OBd_F6t)~+g2*UHcVMhEvSTw1pNJ2qW@|6>fA%!ZM?c7Mu}7K(Q~r@W zw^-!c?YklC(w)JtNyMG8&TWC|y&Bfl~@$A_4D~4h9%wzr+`!y9x{=z#FGA z<9V-liNYOARKk6(VPh6Ksz`Wt@@Rvdms8X3xV4Sl*iD6>awhCXRA@NPH5lL7ay-2t zZS&yBJ2(5R*7 zs>+ibGCc@IU$Fk|XYCNDKFNQ#W-eY6B5kZ6FP!!N=lP%C|6dEmw(zPGkI`dE_>`z) zAOJw1yO^(Ekh?QBiH{lf|C;)j^v9WF{i85`*gv=TM|2j%008~};(#hPY&)L_h0Nk`E8sy diff --git a/excel/global.xlsx b/excel/global.xlsx index d41e52dbfdab9df3a35bebcd42d4d08c9e4b5a32..df27037ea216c7e23f749f9643a96d0441c79455 100644 GIT binary patch delta 3888 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 delta 3888 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 diff --git a/src/ReplicatedStorage/Base/BehaviourClient.luau b/src/ReplicatedStorage/Base/BehaviourClient.luau index 3fabf58..5d515cb 100644 --- a/src/ReplicatedStorage/Base/BehaviourClient.luau +++ b/src/ReplicatedStorage/Base/BehaviourClient.luau @@ -6,6 +6,10 @@ local ReplicatedStorage = game:GetService("ReplicatedStorage") --> Dependencies local EffectDispatcher = require(ReplicatedStorage.Modules.EffectDispatcher) +local Utils = require(ReplicatedStorage.Tools.Utils) + +--> Json +local JsonAnimation = require(ReplicatedStorage.Json.Animation) -------------------------------------------------------------------------------- @@ -19,15 +23,51 @@ function BehaviourClient:Init(CasterPlayer: Player, CastInfo: table, DelayTime: self.ShowTask = nil self.EffectDispatcher = EffectDispatcher + self.Animations = {} return self end +function BehaviourClient:LoadAnimationByName(AnimationName: string) + local AnimationData = Utils:GetSpecialKeyDataFromJson(JsonAnimation, "name", AnimationName) + if not AnimationData then warn("Animation not found") return end + + -- 如果已经加载过,则直接返回 + if self.Animations[AnimationName] then return self.Animations[AnimationName] end + + local Humanoid = self.Character:FindFirstChild("Humanoid") + if not Humanoid then warn("Humanoid not found") return end + local Animator = Humanoid:FindFirstChild("Animator") + if not Animator then warn("Animator not found") return end + + local Animation = Instance.new("Animation") + Animation.AnimationId = "rbxassetid://" .. AnimationData.rbxId + + local AnimationTrack = Animator:LoadAnimation(Animation) + AnimationTrack.Priority = Enum.AnimationPriority[AnimationData.priority] + + self.Animations[AnimationName] = AnimationTrack + Animation:Destroy() + + return AnimationTrack +end + +function BehaviourClient:GetAnimationByName(AnimationName: string) + return self.Animations[AnimationName] +end + function BehaviourClient:Show(CasterPlayer: Player, CastInfo: table, DelayTime: number, CastState: boolean) end -- 销毁 function BehaviourClient:Destroy() + if self.Animations then + for _, AnimationTrack in self.Animations do + AnimationTrack:Destroy() + end + self.Animations = nil + end + if self.ShowTask then task.cancel(self.ShowTask) self.ShowTask = nil diff --git a/src/ReplicatedStorage/Base/UIWindow.luau b/src/ReplicatedStorage/Base/UIWindow.luau index 8a4cc50..185263c 100644 --- a/src/ReplicatedStorage/Base/UIWindow.luau +++ b/src/ReplicatedStorage/Base/UIWindow.luau @@ -13,6 +13,8 @@ local Utils = require(ReplicatedStorage.Tools.Utils) local LocalPlayer = game.Players.LocalPlayer local FolderPlayerGui = LocalPlayer:WaitForChild("PlayerGui") +local FolderStarterPlayerScripts = game.StarterPlayer:WaitForChild("StarterPlayerScripts") +local FolderUIInstanceScripts = FolderStarterPlayerScripts:WaitForChild("UI"):WaitForChild("InstanceScripts") -------------------------------------------------------------------------------- @@ -46,6 +48,7 @@ function UIWindow:AutoInjectVariables() if typeof(varName) == "string" then local firstChar = string.sub(varName, 1, 1) local sixChar = string.sub(varName, 1, 6) + local sevenChar = string.sub(varName, 1, 7) local target if firstChar == "_" then @@ -53,6 +56,11 @@ function UIWindow:AutoInjectVariables() local prefab = Utils:FindInDescendantsUI(self.UIRoot, varName) target = UIList:Init(prefab) target.TopUI = self + elseif sevenChar == "__money" then + target = Utils:FindInDescendantsUI(self.UIRoot, varName) + -- 把脚本放到预制体下 + local newScript = FolderUIInstanceScripts:FindFirstChild("Money"):Clone() + newScript.Parent = target else -- _开头,递归查找 target = Utils:FindInDescendantsUI(self.UIRoot, varName) diff --git a/src/ReplicatedStorage/Json/Animation.json b/src/ReplicatedStorage/Json/Animation.json new file mode 100644 index 0000000..7f1d70f --- /dev/null +++ b/src/ReplicatedStorage/Json/Animation.json @@ -0,0 +1,3 @@ +[ +{"id":1,"name":"SwordWave","rbxId":"133335766636767","priority":"Action"} +] \ No newline at end of file diff --git a/src/ReplicatedStorage/Json/Equipment.json b/src/ReplicatedStorage/Json/Equipment.json index a7d7f4d..42cb5ba 100644 --- a/src/ReplicatedStorage/Json/Equipment.json +++ b/src/ReplicatedStorage/Json/Equipment.json @@ -1,18 +1,18 @@ [ -{"id":40000,"type":1,"name":40000,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40001,"type":1,"name":40001,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40002,"type":1,"name":40002,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40003,"type":1,"name":40003,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40004,"type":1,"name":40004,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40005,"type":1,"name":40005,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40006,"type":1,"name":40006,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40007,"type":1,"name":40007,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40008,"type":1,"name":40008,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40009,"type":1,"name":40009,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40010,"type":1,"name":40010,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40011,"type":1,"name":40011,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40012,"type":1,"name":40012,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40013,"type":1,"name":40013,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40014,"type":1,"name":40014,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10}, -{"id":40015,"type":1,"name":40015,"attributes":[14,200,10,15,200,10,16,100,0],"recycle":10} +{"id":40000,"type":1,"name":40000,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40001,"type":1,"name":40001,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40002,"type":1,"name":40002,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40003,"type":1,"name":40003,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40004,"type":1,"name":40004,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40005,"type":1,"name":40005,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40006,"type":1,"name":40006,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40007,"type":1,"name":40007,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40008,"type":1,"name":40008,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40009,"type":1,"name":40009,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40010,"type":1,"name":40010,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40011,"type":1,"name":40011,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40012,"type":1,"name":40012,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40013,"type":1,"name":40013,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40014,"type":1,"name":40014,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10}, +{"id":40015,"type":1,"name":40015,"attributes":[14,200,10,15,200,10,16,100,0],"modelName":"Zeus","recycle":10} ] \ No newline at end of file diff --git a/src/ReplicatedStorage/Json/Param.json b/src/ReplicatedStorage/Json/Param.json index ecbd2fc..aca4859 100644 --- a/src/ReplicatedStorage/Json/Param.json +++ b/src/ReplicatedStorage/Json/Param.json @@ -1,5 +1,6 @@ [ {"id":1,"key":"quality_bonus","intValue":null,"stringValue":null,"intArray":[100,125,150,200,275,375]}, {"id":2,"key":"level_get_bonus","intValue":null,"stringValue":null,"intArray":[5,2]}, -{"id":3,"key":"mob_died_get","intValue":null,"stringValue":null,"intArray":[2,10]} +{"id":3,"key":"mob_died_get","intValue":null,"stringValue":null,"intArray":[2,10]}, +{"id":4,"key":"default_weapon","intValue":null,"stringValue":"Sword","intArray":[]} ] \ No newline at end of file diff --git a/src/ReplicatedStorage/Modules/BehavioursClient/SwordWave.luau b/src/ReplicatedStorage/Modules/BehavioursClient/SwordWave.luau index d10be85..62b2192 100644 --- a/src/ReplicatedStorage/Modules/BehavioursClient/SwordWave.luau +++ b/src/ReplicatedStorage/Modules/BehavioursClient/SwordWave.luau @@ -20,12 +20,16 @@ function SwordWave:Init(CasterPlayer: Player, CastInfo: table, DelayTime: number local self = BehaviourClient:Init(CasterPlayer, CastInfo, DelayTime, CastState) setmetatable(self, SwordWave) + -- 加载动画 + self:LoadAnimationByName("SwordWave") return self end function SwordWave:Show(CasterPlayer: Player, CastInfo: table, DelayTime: number, CastState: boolean) self.ShowTask, self.Projectile, self.Tween = self.EffectDispatcher:ShowProjectile(self.Player, DelayTime, 0, CastInfo.StartPos, CastInfo.EndPos, CastInfo.Duration, Prefab_SwordWave, Enum.EasingStyle.Linear) + + self.EffectDispatcher:ShowAnimation(self.Player, DelayTime, self:GetAnimationByName("SwordWave")) end function SwordWave:Destroy() diff --git a/src/ReplicatedStorage/Modules/EffectDispatcher.luau b/src/ReplicatedStorage/Modules/EffectDispatcher.luau index 8f9fcfd..a497d04 100644 --- a/src/ReplicatedStorage/Modules/EffectDispatcher.luau +++ b/src/ReplicatedStorage/Modules/EffectDispatcher.luau @@ -26,7 +26,6 @@ function EffectDispatcher:ShowProjectile(Caster: Player, DelayTime: number, PreT Projectile.CanCollide = false Projectile.Anchored = true - -- Tween动画 local tweenInfo = TweenInfo.new(Duration, EasingStyle or Enum.EasingStyle.Linear) local direction = (EndPos - StartPos).Unit @@ -43,4 +42,8 @@ function EffectDispatcher:ShowProjectile(Caster: Player, DelayTime: number, PreT return projectileTask, Projectile, tween end +function EffectDispatcher:ShowAnimation(Caster: Player, DelayTime: number, AnimationTrack: AnimationTrack) + AnimationTrack:Play() +end + return EffectDispatcher \ No newline at end of file diff --git a/src/ReplicatedStorage/Tools/Utils.luau b/src/ReplicatedStorage/Tools/Utils.luau index d1051f5..4966c66 100644 --- a/src/ReplicatedStorage/Tools/Utils.luau +++ b/src/ReplicatedStorage/Tools/Utils.luau @@ -11,6 +11,13 @@ local PlayerDataFolder = ReplicatedStorage:WaitForChild("PlayerData") -------------------------------------------------------------------------------- +function Utils:WaitPlayerDataFolder(Player: Player) + local pData = PlayerDataFolder:WaitForChild(Player.UserId) + if pData then return pData end + warn("玩家数据不存在: " .. Player.Name) + return nil +end + function Utils:GetPlayerDataFolder(Player: Player) local pData = PlayerDataFolder:FindFirstChild(Player.UserId) if pData then return pData end diff --git a/src/ServerStorage/Proxy/EquipmentProxy.luau b/src/ServerStorage/Proxy/EquipmentProxy.luau index 9d8796a..a0b63c4 100644 --- a/src/ServerStorage/Proxy/EquipmentProxy.luau +++ b/src/ServerStorage/Proxy/EquipmentProxy.luau @@ -281,6 +281,11 @@ function EquipmentProxy:WearEquipment(Player: Player, EquipmentId: number, Slot: -- 更新玩家数据 PlayerFightProxy:UpdatePlayerFightData(Player) + + -- 给前端的提示(模型穿戴) + if Slot == 1 then + RE_WearEquipment:FireClient(Player, true, EquipmentId, Slot) + end end -- 卸下装备 @@ -288,15 +293,20 @@ function EquipmentProxy:UnwearEquipment(Player: Player, EquipmentId: number) local pData = Utils:GetPlayerDataFolder(Player) if not pData then return end - -- TODO :卸下装备时再关闭模型 - -- 卸下装备 local EquipmentData = ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentId] if not EquipmentData then return end + + -- 给前端的提示(模型卸下) + if EquipmentData.wearing == 1 then + RE_WearEquipment:FireClient(Player, false, EquipmentId, EquipmentData.wearing) + end + ChangeValue(Player, EquipmentId, "wearing", 0) -- 更新玩家数据 PlayerFightProxy:UpdatePlayerFightData(Player) + end -- 获取穿戴中的装备UniqueId diff --git a/src/ServerStorage/Proxy/PlayerFightProxy/init.luau b/src/ServerStorage/Proxy/PlayerFightProxy/init.luau index bd0ecd0..c9b8af4 100644 --- a/src/ServerStorage/Proxy/PlayerFightProxy/init.luau +++ b/src/ServerStorage/Proxy/PlayerFightProxy/init.luau @@ -178,7 +178,7 @@ function PlayerFightProxy:UpdatePlayerFightData(Player: Player) for _, behaviourName in behaviourNameList do playerAI:AddBehaviour(behaviourName) end - playerAI:AddBehaviour("Move") + -- playerAI:AddBehaviour("Move") playerAI:AddBehaviour("SwordWave") diff --git a/src/ServerStorage/Proxy/PlayerInfoProxy.luau b/src/ServerStorage/Proxy/PlayerInfoProxy.luau index f86d984..3d2a261 100644 --- a/src/ServerStorage/Proxy/PlayerInfoProxy.luau +++ b/src/ServerStorage/Proxy/PlayerInfoProxy.luau @@ -335,7 +335,6 @@ end) RE_UpgradeAttributes.OnServerEvent:Connect(function(Player: Player, AttributeId: number) PlayerInfoProxy:UpgradeAttribute(Player, AttributeId) - print(ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade) end) return PlayerInfoProxy \ No newline at end of file diff --git a/src/StarterPlayerScripts/ClientMain/DefaultUIClose.luau b/src/StarterPlayerScripts/ClientMain/DefaultUIClose.luau new file mode 100644 index 0000000..aa43f22 --- /dev/null +++ b/src/StarterPlayerScripts/ClientMain/DefaultUIClose.luau @@ -0,0 +1,6 @@ +local StarterGui = game:GetService("StarterGui") + +-- Disable default health bar and backpack +StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) + +return {} \ No newline at end of file diff --git a/src/StarterPlayerScripts/ClientMain/MeleeMobAlign.luau b/src/StarterPlayerScripts/ClientMain/MeleeMobAlign.luau index c914c75..eb043d6 100644 --- a/src/StarterPlayerScripts/ClientMain/MeleeMobAlign.luau +++ b/src/StarterPlayerScripts/ClientMain/MeleeMobAlign.luau @@ -9,85 +9,88 @@ fighting any enemy with a melee weapon, especially on platforms like mobile, where shift lock may not be a feature. ]] ---> Services -local CollectionService = game:GetService("CollectionService") -local UserInputService = game:GetService("UserInputService") -local RunService = game:GetService("RunService") -local Players = game:GetService("Players") +-- 临时关闭(原参考demo代码) +return {} ---> Player -local Player = Players.LocalPlayer +-- --> Services +-- local CollectionService = game:GetService("CollectionService") +-- local UserInputService = game:GetService("UserInputService") +-- local RunService = game:GetService("RunService") +-- local Players = game:GetService("Players") ---> Variables -local Focus: Model? +-- --> Player +-- local Player = Players.LocalPlayer ---> Configuration -local Enabled = true +-- --> Variables +-- local Focus: Model? --------------------------------------------------------------------------------- +-- --> Configuration +-- local Enabled = true -if not Enabled then - return {} -end +-- -------------------------------------------------------------------------------- -local function GetNearestMob() - local Character = Player.Character - if not Character then return end +-- if not Enabled then +-- return {} +-- end + +-- local function GetNearestMob() +-- local Character = Player.Character +-- if not Character then return end - local Closest = {MobInstance = nil, Distance = math.huge} +-- local Closest = {MobInstance = nil, Distance = math.huge} - for _, MobInstance in CollectionService:GetTagged("Mob") do - local MobConfig = MobInstance:FindFirstChild("MobConfig") and require(MobInstance.MobConfig) - local Enemy = MobInstance:FindFirstChild("Enemy") - if not MobConfig or not Enemy or Enemy.Health == 0 then continue end +-- for _, MobInstance in CollectionService:GetTagged("Mob") do +-- local MobConfig = MobInstance:FindFirstChild("MobConfig") and require(MobInstance.MobConfig) +-- local Enemy = MobInstance:FindFirstChild("Enemy") +-- if not MobConfig or not Enemy or Enemy.Health == 0 then continue end - local Distance = (Character:GetPivot().Position - MobInstance:GetPivot().Position).Magnitude - local MaxDistance = MobConfig.FollowDistance +-- local Distance = (Character:GetPivot().Position - MobInstance:GetPivot().Position).Magnitude +-- local MaxDistance = MobConfig.FollowDistance - if (Distance < MaxDistance) and (Distance < Closest.Distance) then - Closest.MobInstance = MobInstance - Closest.Distance = Distance - end - end +-- if (Distance < MaxDistance) and (Distance < Closest.Distance) then +-- Closest.MobInstance = MobInstance +-- Closest.Distance = Distance +-- end +-- end - return Closest.MobInstance -end +-- return Closest.MobInstance +-- end -task.defer(function() - while true do - task.wait(1/5) - Focus = GetNearestMob() - end -end) +-- task.defer(function() +-- while true do +-- task.wait(1/5) +-- Focus = GetNearestMob() +-- end +-- end) -RunService:BindToRenderStep("MeleeLock", Enum.RenderPriority.Character.Value + 1, function(DeltaTime: number) - local Character = Player.Character - local Humanoid = Character and Character:FindFirstChild("Humanoid") :: Humanoid? - local HumanoidRootPart = Character and Character:FindFirstChild("HumanoidRootPart") :: BasePart? - if not Humanoid or not HumanoidRootPart then return end +-- RunService:BindToRenderStep("MeleeLock", Enum.RenderPriority.Character.Value + 1, function(DeltaTime: number) +-- local Character = Player.Character +-- local Humanoid = Character and Character:FindFirstChild("Humanoid") :: Humanoid? +-- local HumanoidRootPart = Character and Character:FindFirstChild("HumanoidRootPart") :: BasePart? +-- if not Humanoid or not HumanoidRootPart then return end - local Success = false +-- local Success = false - if Focus and UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then - local Tool = Character:FindFirstChildOfClass("Tool") - local ItemConfig = Tool and require(Tool:FindFirstChild("ItemConfig")) +-- if Focus and UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then +-- local Tool = Character:FindFirstChildOfClass("Tool") +-- local ItemConfig = Tool and require(Tool:FindFirstChild("ItemConfig")) - if ItemConfig and ItemConfig.WeaponType == "Melee" then - local CurrentRotation = HumanoidRootPart.CFrame.Rotation - local GoalRotation = CFrame.lookAt(HumanoidRootPart.Position, Focus:GetPivot().Position).Rotation - local _, Y, _ = CurrentRotation:Lerp(GoalRotation, DeltaTime * 30):ToOrientation() - local X, _, Z = CurrentRotation:ToOrientation() +-- if ItemConfig and ItemConfig.WeaponType == "Melee" then +-- local CurrentRotation = HumanoidRootPart.CFrame.Rotation +-- local GoalRotation = CFrame.lookAt(HumanoidRootPart.Position, Focus:GetPivot().Position).Rotation +-- local _, Y, _ = CurrentRotation:Lerp(GoalRotation, DeltaTime * 30):ToOrientation() +-- local X, _, Z = CurrentRotation:ToOrientation() - Humanoid.AutoRotate = false - HumanoidRootPart.CFrame = CFrame.Angles(X, Y, Z) + HumanoidRootPart.Position +-- Humanoid.AutoRotate = false +-- HumanoidRootPart.CFrame = CFrame.Angles(X, Y, Z) + HumanoidRootPart.Position - Success = true - end - end +-- Success = true +-- end +-- end - if not Success then - Humanoid.AutoRotate = true - end -end) +-- if not Success then +-- Humanoid.AutoRotate = true +-- end +-- end) -return {} \ No newline at end of file +-- return {} \ No newline at end of file diff --git a/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau b/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau index 43b423b..a526288 100644 --- a/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau +++ b/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau @@ -115,5 +115,6 @@ end) -- 打开默认界面 UIManager:OpenWindow("MainWindow") +UIManager:OpenWindow("TipsWindow") return PerformanceClient \ No newline at end of file diff --git a/src/StarterPlayerScripts/ClientMain/WeaponModel.luau b/src/StarterPlayerScripts/ClientMain/WeaponModel.luau new file mode 100644 index 0000000..5ce0310 --- /dev/null +++ b/src/StarterPlayerScripts/ClientMain/WeaponModel.luau @@ -0,0 +1,85 @@ +local WeaponModel = {} + +--> Services +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local Utils = require(ReplicatedStorage.Tools.Utils) + +--> Json +local JsonEquipment = require(ReplicatedStorage.Json.Equipment) +local JsonParam = require(ReplicatedStorage.Json.Param) + +--> Events +local RE_WearEquipment = ReplicatedStorage.Events.RE_WearEquipment + +--> Variables +local LocalPlayer = game.Players.LocalPlayer +local Character = LocalPlayer.Character +local LastWeaponName + +-- 如果角色不存在,等待角色加载 +if not Character then + Character = LocalPlayer.CharacterAdded:Wait() +end + +local FolderEquipment = Utils:WaitPlayerDataFolder(LocalPlayer):WaitForChild("Equipment") +local FolderPrefabEquipments = ReplicatedStorage.Prefabs.Equipments +local FolderBackpack = LocalPlayer.Backpack + +function WeaponModel:SetWeaponModel(WeaponInstance: Instance) + local WeaponData = Utils:GetIdDataFromJson(JsonEquipment, tonumber(WeaponInstance:GetAttribute("orgId"))) + if not WeaponData then warn("WeaponData not found") return end + + local WeaponModel = FolderPrefabEquipments:FindFirstChild(WeaponData.modelName) + if not WeaponModel then warn("WeaponModel not found") return end + + local newWeapon = WeaponModel:Clone() + newWeapon.Parent = LocalPlayer.Backpack + Character:FindFirstChild("Humanoid"):EquipTool(newWeapon) + return newWeapon.Name +end + +function WeaponModel:SetDefaultWeaponModel() + local modelName = Utils:GetIdDataFromJson(JsonParam, 4).stringValue + local WeaponModel = FolderPrefabEquipments:FindFirstChild(modelName) + if not WeaponModel then warn("DefaultWeaponModel not found") return end + + local newWeapon = WeaponModel:Clone() + newWeapon.Parent = LocalPlayer.Backpack + + Character:FindFirstChild("Humanoid"):EquipTool(newWeapon) + return newWeapon.Name +end + +-- 初始化 +local instance +for _, WeaponInstance in FolderEquipment:GetChildren() do + if WeaponInstance:GetAttribute("wearing") == 1 then + instance = WeaponInstance + break + end +end +-- 设置初始化武器 +if instance then + LastWeaponName = WeaponModel:SetWeaponModel(instance) +else + LastWeaponName = WeaponModel:SetDefaultWeaponModel() +end + +-- 穿戴装备 +RE_WearEquipment.OnClientEvent:Connect(function(IsWear: boolean, EquipmentId: number, Slot: number) + local oldWeaponName = LastWeaponName + if IsWear then + local newInstance = FolderEquipment:FindFirstChild(EquipmentId) + if not newInstance then warn("newInstance not found") return end + LastWeaponName = WeaponModel:SetWeaponModel(newInstance) + else + LastWeaponName = WeaponModel:SetDefaultWeaponModel() + end + for _, child in FolderBackpack:GetChildren() do + if child.Name == oldWeaponName then + child:Destroy() + end + end +end) + +return WeaponModel \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/InstanceScripts/Money.client.luau b/src/StarterPlayerScripts/UI/InstanceScripts/Money.client.luau new file mode 100644 index 0000000..77fc543 --- /dev/null +++ b/src/StarterPlayerScripts/UI/InstanceScripts/Money.client.luau @@ -0,0 +1,57 @@ +-- 检查父级是否为Frame类型,如果不是则退出脚本 +if typeof(script.Parent) ~= "Instance" or not script.Parent:IsA("Frame") then return end + +-- 必须读取内容 +local CheckMoneyId = script.Parent:GetAttribute("CheckMoneyId") +local tmpValue = script.Parent:FindFirstChild("_tmpValue") +local imgIcon = script.Parent:FindFirstChild("_imgIcon") +if not CheckMoneyId or not tmpValue or not imgIcon then warn("Money实例内容初始化失败") return end + +--> Server +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Modules +local Utils = require(ReplicatedStorage.Tools.Utils) +local Localization = require(ReplicatedStorage.Tools.Localization) + +--> Json +local JsonItemProp = require(ReplicatedStorage.Json.ItemProp) + +-- 临时变量 +local LocalPlayer = game.Players.LocalPlayer +local connection, connectionFolder + +local PlayerDataFolder = Utils:GetPlayerDataFolder(LocalPlayer) +if not PlayerDataFolder then warn("无法获取玩家数据文件夹") return end + +local PlayerInfo = PlayerDataFolder:FindFirstChild("PlayerInfo") +if not PlayerInfo then warn("无法获取玩家信息文件夹") return end + +local MoneyFolder = PlayerInfo:FindFirstChild("Items") +if not MoneyFolder then warn("无法获取物品文件夹") return end + +local InstanceMoney = MoneyFolder:FindFirstChild(CheckMoneyId) + +local ItemData = Utils:GetIdDataFromJson(JsonItemProp, tonumber(CheckMoneyId)) +imgIcon.Image = Localization:GetImageData(ItemData.iconId) + +if not InstanceMoney then + tmpValue.Text = "0" + connectionFolder = MoneyFolder.ChildAdded:Connect(function(child) + if child.Name == tostring(CheckMoneyId) then + tmpValue.Text = child.Value + InstanceMoney = child + connectionFolder:Disconnect() + end + end) +else + tmpValue.Text = InstanceMoney.Value + connection = InstanceMoney.Changed:Connect(function(newValue) + tmpValue.Text = newValue + end) +end + +script.Destroying:Once(function() + if connectionFolder then connectionFolder:Disconnect() end + if connection then connection:Disconnect() end +end) \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/AttributeLvupWindow/AttributeLvupShow.luau b/src/StarterPlayerScripts/UI/Windows/AttributeLvupWindow/AttributeLvupShow.luau index 6070115..cde052e 100644 --- a/src/StarterPlayerScripts/UI/Windows/AttributeLvupWindow/AttributeLvupShow.luau +++ b/src/StarterPlayerScripts/UI/Windows/AttributeLvupWindow/AttributeLvupShow.luau @@ -45,16 +45,15 @@ function AttributeLvupShow:Refresh() end if self.instance and not self.instanceCon then - local instanceCon = self.instance.ValueChanged:Connect(function() + local instanceCon = self.instance.Changed:Connect(function() self:Refresh() end) self.instanceCon = instanceCon end - local attributeData = Utils:GetSpecialKeyDataFromJson(JsonAttributes, "effectAttribute", self.Data.attribute) + local attributeData = Utils:GetIdDataFromJson(JsonAttributes, self.Data.id) self.Variables._imgIcon.Image = Localization:GetImageData(attributeData.iconId) self.Variables._tmpAttributeName.Text = self.Data.id - self.UIRoot.LayoutOrder = 1000 - attributeData.id local nowLv = self:GetNowLv() self.Variables._tmpLv.Text = "Lv." .. nowLv @@ -91,13 +90,18 @@ function AttributeLvupShow:OnInitFinish() -- 没有实例时,监听文件夹,有实例时,监听实例 if not self.instance then local attributeFolder = Utils:GetPlayerDataFolder(LocalPlayer):FindFirstChild("PlayerInfo"):FindFirstChild("AttributesUpgrade") - local folderCon = attributeFolder.ChildAdded:Connect(function(child) - if child.Name == tostring(self.Data.id) then - self.instance = child - self:Refresh() - end - end) - self.folderCon = folderCon + local attributeInst = attributeFolder:FindFirstChild(tostring(self.Data.id)) + if attributeInst then + self.instance = attributeInst + else + local folderCon = attributeFolder.ChildAdded:Connect(function(child) + if child.Name == tostring(self.Data.id) then + self.instance = child + self:Refresh() + end + end) + self.folderCon = folderCon + end end end diff --git a/src/StarterPlayerScripts/UI/Windows/AttributeLvupWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/AttributeLvupWindow/init.luau index d6198c0..ecf4b69 100644 --- a/src/StarterPlayerScripts/UI/Windows/AttributeLvupWindow/init.luau +++ b/src/StarterPlayerScripts/UI/Windows/AttributeLvupWindow/init.luau @@ -28,6 +28,11 @@ function AttributeLvupWindow:Init(UIManager: table, Data: table?) ["__listBaseAttributes"] = 0, ["_tmpSpecialTitle"] = 0, ["_tmpBaseTitle"] = 0, + + ["__moneyCoin"] = 0, + + ["_btnClose"] = 0, + ["_btnBgClose"] = 0, } self.UIRootName = "ui_w_attribute_lvup" self.UIParentName = UIEnums.UIParent.UIRoot @@ -59,6 +64,15 @@ function AttributeLvupWindow:OnOpenWindow() self.Variables["__listBaseAttributes"]:SetData(self.Data.Base) self.Variables["__listSpecialAttributes"]:SetLayoutOrder("id") self.Variables["__listBaseAttributes"]:SetLayoutOrder("id") + + local bgCloseCon = self.Variables["_btnBgClose"].Activated:Connect(function() + self.UIManager:CloseWindow(script.Name) + end) + local closeCon = self.Variables["_btnClose"].Activated:Connect(function() + self.UIManager:CloseWindow(script.Name) + end) + table.insert(self.Connections, bgCloseCon) + table.insert(self.Connections, closeCon) end diff --git a/src/StarterPlayerScripts/UI/Windows/ChaWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/ChaWindow/init.luau index b11bb7b..d1d19c0 100644 --- a/src/StarterPlayerScripts/UI/Windows/ChaWindow/init.luau +++ b/src/StarterPlayerScripts/UI/Windows/ChaWindow/init.luau @@ -81,15 +81,18 @@ function ChaWindow:AddInstanceData(configInstance: Instance, Data: table?) local attributes = configInstance:GetAttributes() -- 归类是否是穿戴的装备 - local parentName = "Package" - if attributes.wearing ~= 0 then parentName = "Wearing" end - data[parentName][configInstance.Name] = {} + local parentName, secondName = "Package", configInstance.Name + if attributes.wearing ~= 0 then + parentName = "Wearing" + secondName = "slot"..attributes.wearing + end + data[parentName][secondName] = {} for attributeKey, attributeValue in attributes do - data[parentName][configInstance.Name][attributeKey] = attributeValue + data[parentName][secondName][attributeKey] = attributeValue end - data[parentName][configInstance.Name].instance = configInstance - return data[parentName][configInstance.Name], parentName + data[parentName][secondName].instance = configInstance + return data[parentName][secondName], parentName end function ChaWindow:OnOpenWindow() @@ -125,9 +128,9 @@ function ChaWindow:OnOpenWindow() local addCon = DataFolder.ChildAdded:Connect(function(child) local data, parentName = self:AddInstanceData(child, data) if parentName == "Wearing" then - self.Variables["__listWeaing"]:AddData(data) + self.Variables["__listWeaing"]:AddData("slot"..data.wearing, data) else - self.Variables["__listWeaponPackage"]:AddData(data) + self.Variables["__listWeaponPackage"]:AddData(child.Name, data) end end) diff --git a/src/StarterPlayerScripts/UI/Windows/TipsWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/TipsWindow/init.luau new file mode 100644 index 0000000..379d172 --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/TipsWindow/init.luau @@ -0,0 +1,63 @@ +--> Services +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Dependencies +local UIWindow = require(ReplicatedStorage.Base.UIWindow) +local UIEnums = require(ReplicatedStorage.Base.UIEnums) +local Tween = require(ReplicatedStorage.Modules.Tween) + +--> Components + +--> Events +local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip + +-------------------------------------------------------------------------------- + +local TipsWindow = {} +TipsWindow.__index = TipsWindow +setmetatable(TipsWindow, {__index = UIWindow}) + +function TipsWindow:Init(UIManager: table, Data: table?) + local self = UIWindow:Init(UIManager, Data) + setmetatable(self, TipsWindow) + self.Variables = { + ["__goPanel1"] = 0, + } + self.UIRootName = "ui_w_tips" + self.UIParentName = UIEnums.UIParent.UIRoot + + return self +end + +function TipsWindow:ShowPanel1(text: string) + local newPanel = self.Variables["__goPanel1"]:Clone() + newPanel.Parent = self.UIRoot + newPanel.Visible = true + newPanel:FindFirstChild("_tmpContent").Text = text or "" + + -- 设置初始位置(向下偏移) + + -- 创建向上移动的tween动画 + local tween = Tween:Play(newPanel, {2, "Circular", "Out"}, { + Position = newPanel.Position + UDim2.new(0, 0, 0, -80) + }) + + -- 动画完成后自动销毁面板 + tween.Completed:Once(function() + task.delay(0.5, function() + newPanel:Destroy() + end) + end) +end + +function TipsWindow:OnOpenWindow() + UIWindow.OnOpenWindow(self) + + self.Variables["__goPanel1"].Visible = false + local con = RE_PlayerTip.OnClientEvent:Connect(function(data) + self:ShowPanel1(data) + end) + table.insert(self.Connections, con) +end + +return TipsWindow \ No newline at end of file