From 6b6d563780d1ab389a179dfe640aea00452ff49a Mon Sep 17 00:00:00 2001 From: Ggafrik <906823881@qq.com> Date: Tue, 22 Jul 2025 01:56:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0-=E5=89=8D=E7=AB=AF=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=95=8C=E9=9D=A2=E5=81=9A=E4=BA=86=E4=B8=80=E5=8D=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- excel/attribute.xlsx | Bin 12383 -> 12561 bytes excel/equipment.xlsx | Bin 9622 -> 9619 bytes src/ReplicatedStorage/Base/UIList.luau | 26 +- src/ReplicatedStorage/Base/UIWindow.luau | 20 ++ src/ReplicatedStorage/Json/Attributes.json | 62 ++--- src/ReplicatedStorage/Tools/Utils.luau | 7 + src/ServerStorage/Proxy/EquipmentProxy.luau | 27 +- src/ServerStorage/Proxy/HelpProxy.luau | 7 +- src/ServerStorage/Proxy/PlayerInfoProxy.luau | 2 +- .../BilGui/Gui.client.luau | 60 ++--- .../ClientMain/Helper.luau | 2 + .../ClientMain/PerformanceClient/init.luau | 10 +- src/StarterPlayerScripts/UI/UIManager.luau | 14 ++ .../UI/Windows/ChaWindow/PackageShow.luau | 50 ++++ .../UI/Windows/ChaWindow/WearingShow.luau | 61 +++++ .../UI/Windows/ChaWindow/init.luau | 142 +++++++++++ .../UI/Windows/CreateWindow/init.luau | 2 - .../EquipmentDetailWindow/AttributeShow.luau | 50 ++++ .../EquipmentDetailWindow/ReplaceShow.luau | 57 +++++ .../Windows/EquipmentDetailWindow/init.luau | 234 ++++++++++++++++++ .../UI/Windows/MainWindow/init.luau | 6 + 21 files changed, 757 insertions(+), 82 deletions(-) create mode 100644 src/StarterPlayerScripts/UI/Windows/ChaWindow/PackageShow.luau create mode 100644 src/StarterPlayerScripts/UI/Windows/ChaWindow/WearingShow.luau create mode 100644 src/StarterPlayerScripts/UI/Windows/ChaWindow/init.luau create mode 100644 src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/AttributeShow.luau create mode 100644 src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/ReplaceShow.luau create mode 100644 src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/init.luau diff --git a/excel/attribute.xlsx b/excel/attribute.xlsx index 47a54e8278953849f237d0d723e22c0d198bc2f4..371cd9136b516416d35afc0b9232e60b938c439a 100644 GIT binary patch delta 4455 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 LaS=+3{(=4n3r=NK delta 4295 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 Y(!ZVEBFulA8oA_=>Px# diff --git a/excel/equipment.xlsx b/excel/equipment.xlsx index 613987b46d17f6a1b24287cf81506eb21fb7c35f..1a1e49ee4c974a747b4ba9e39908f4a09297f65a 100644 GIT binary patch delta 1810 zcmV+t2krQlOOs2m$_5082EI*`&ITQSVQ-^25dD7A{RhN%3MN1ZDqV#Dx=8IR%I4Zz zsZ!;DQ+x%?8Pia$_P_5KLeey=Rkl5p*w`LFznOU+EEuVT$rm0I93#W^d9ufC94{dD!`AD3IkpVo{$DF9H`zM2V9dAeRF87XjoeZeYH z!pes60t*=ON4>5%!D*clB8pr$4a3n3OiQ&#@c20xY_p*W30cwXsF98Q9zlcNfn za8|R8xBzIqCw<~SGIWHFLeQRn#^5|8OXuX7${g-lap#?^oIRFv07J%y(GWsqRtk{Xj`~Ms)nU&v1|n9Ljf5> z((v3@XWspSvwuk<>U+L!=V?yv2(DOpPuhg!_pdaFPX+%QD#VElf)0-N&{2 z8rr?6~3dJ2=A~FJZWU5!o)S653ZS$l=M-4Q_`OWOxlt4>Z0RyGN7#n`T)1E*+Ky z?3R*keGq^gD(xLDQ?~V04N2L)91pkM;vG#z1`4uW6HNNKzX*NIfH4|P3@LYRN@l)# z#3<|;#qemdIbx*0qSTd2pw{(D*~vQs%~Z1XL0OiSw2Lz++LOnB@Og^5JPtb(oF@ye z$gVS-Aj6zU3(|_~T68@qjRHet8Pl;bu{0wZ*_s9SLUXN=sm-j=jO=j~Mu9C;B&)sm zf7HBA@ZRtlkt{RJ#fszP2|hkcvI%evn(7?_zOTs!wi_5DplHP?)+{tJv>Hg+kofXH`yWIqf2Ck~SrQO(*ZM>V^Pj32&U8;_*pSKKU+;_WwW%vcW z&&ip_@$H$0v(GoHn=@^%qt(M*e6I2ICJ3kJ+fSFv>DN{C&v1nP(}3z-!e!gZR3Bt= z^#hZU0~E7Y3Nr!@@aKUwc57tT37Bq=sN}v^{ zlI^yj-@k2UA1HC2w-r~Wg@T^I(Z}`scdLW3JJ$esf`rx;wDG>n8FQim&0S`3Ps~+K0t+0NWhk8iGLcd)chFwgRFd0&^d0B=$$wE=Qxo}vQh9b39z38 zX&hzQBF<8r`i~H^3r^Ti!exYt5}e=2A?SapSqS$p0JDh>I1dF<#U-0Yv&J1J0e@dl zgD@1u-%b1ur0-D5{x}<8iJCpR#6*n7x2C;gL|U4*%J%Ioupwr~$9vD|@1A?pbbXL@ z@CC+Jjmi*-VibVlji^+ap_gJ4u25hdQ-alvf(#wOqIG_Km2ypaW8ld&8jP#J2A-rW ztp!*1ix(` zpZitAN_Ds5fbvvu$_+5rn7rh>6i@2zb~UqZ>(9KaK-?V%%VpbB`p^RkL_pwU&>{3$ zd7a%q6dRN$FaX`*tf3)Kv;QR~o_G@`q#!qRKBtR#LOcWV z6kmLW{2P;z0~E78AWZ`Vhz7n*la3>S3GnBEL?HzL0NRrnBv%2`lW-(J0f>{aBsu}x zlk6lX8&bt3n??Zu09OJ401*HH000000000000025lP)Db0W6bkB_js?A^-pY0JY{^ AU;qFB delta 1811 zcmV+u2kiKhOO{Kp$_51QGh4lr&ITQSZEvGE5dMDB{RhN%3MP;jRJsZQbdlOsl+Crb zQl-i|2uahdR@wGYVq<&!_?eliYCBsk**_4OB8>7TCt{Nr-V#nYPeCk+6K%GXmVOV2bblF}T1R~Njb z1*~ki$gzZ>cr>e0P@GgLr83V<+p>mcj#;612%b0xgKsvB(2$clr-kf51kJDn`c=xx zsz=MoIdC}^PjzV!o|gczW*L(&EvT;L#G5}BT;O#EZa2u)8Ueo{{E-EX-Jb+YCr9Os z2ww4xyZ~skBYomOvP^`ILeQLl#^5|8#}xFLsT}TEiQzk04fj~X0~oSCjD|p3tyVk; z-aFCUJvUpwy4&qqyY7J#7fh?q6vTp9=mrREUWRf(edy&`z z>y@^ULWB2tcn#71f}bJwkl|!^HRljqGs8-&JaV9g9CwviFQgb_vd zWN0JXj*v{s{A@0X5r%tG1P?*~{eW z2LO|i0~E7Y3Nr!;h-;?zB?SNg-jkCIFMml;gCMIatEhWdwcYmGm?2oPF||z&s`~C7 z4oNDds-i_;gYEzOXY3(+I%!1?V4XBgPNN{C1R7yV+3a%q`fWS=K#B9bDY-HY%}(JdkhsiZ#-P)f8&Uv`bL zyil0;DOzwrP8RPNpZUdR7{7DUQdr|mg4+Y#$#6v~1!W||7e^F0^FcgK~P5cj}?@-E|VgoEu zvnQ9Bh|&1gw0De1OVd`_{=Ee@#LW13?>YVMxi`&Ld)WkEU~Jv09FZtS0Vv*zT2(oE zDc50&0_&I(tZ5bG=l~Y2ipz_PYsy;#Po~viTn#qxBxNbrIodg=DaMxXKr$P7hw|dK zHIg}Bf0_zw#y?mEIEmwHEWt6s9K$^@)DsaMk%CW1{b`y3AUK8wBq(Pwi3tAjIxy1y z`Cw3HPFcHy_B$Qp&e?*G;^f}jdNOuh7j=svhR;v%+vf3kST(Fwe=82C$ONa{0CTM= zD!$F|tnP2uFzYt{%-b5o-C?wxw>@PDJ)%GaKRyN>L!Xq_#r;FMMnw{nWf)(F@vkzr@57Z$grmB&JD1<8($m0g4QteTCv1laT`yvpOJ60|f6g zTfLKuBY_EsYo_-l1polvlNBUa0@o3f?-3P~v?CCcmKYEV0000000000004}Wt|U4E z-;?PiCmY;P#6v{^00374000pH000000000000000vy&?&J^?S2Y9%8E03!eZ003;Q BSg!y8 diff --git a/src/ReplicatedStorage/Base/UIList.luau b/src/ReplicatedStorage/Base/UIList.luau index fb70853..6d7b6ac 100644 --- a/src/ReplicatedStorage/Base/UIList.luau +++ b/src/ReplicatedStorage/Base/UIList.luau @@ -63,6 +63,16 @@ function UIList:AddData(data: table) self:SetSingleInstance(#self.Data, data) end +function UIList:RemoveData(data: table) + for i, v in pairs(self.Data) do + if Utils:CompareTableJson(v, data) then + self.Instances[i]:Destroy() + table.remove(self.Data, i) + return i + end + end +end + function UIList:SetLayoutOrder(keyName: string) self.LayoutOrderKey = keyName for _, ui in pairs(self.Instances) do @@ -126,15 +136,19 @@ function UIList:Clean() -- 清除下面组件的内容 for _, ui in pairs(self.Instances) do - for _, connection in pairs(ui.SignalConnections) do - connection:DisconnectAll() + if ui.SignalConnections then + for _, connection in pairs(ui.SignalConnections) do + connection:DisconnectAll() + end + self.SignalConnections = nil end - self.SignalConnections = nil - for _, connection in pairs(ui.Connections) do - connection:Disconnect() + if ui.Connections then + for _, connection in pairs(ui.Connections) do + connection:Disconnect() + end + self.Connections = nil end - self.Connections = nil if ui.UIRoot then ui.UIRoot:Destroy() end ui:Destroy() diff --git a/src/ReplicatedStorage/Base/UIWindow.luau b/src/ReplicatedStorage/Base/UIWindow.luau index 156fd5c..0475f7b 100644 --- a/src/ReplicatedStorage/Base/UIWindow.luau +++ b/src/ReplicatedStorage/Base/UIWindow.luau @@ -133,6 +133,26 @@ function UIWindow:Destroy() end self.Connections = nil + -- 销毁数据 + if self.Data then + if type(self.Data) == "table" then + for k, v in pairs(self.Data) do + self.Data[k] = nil + end + end + self.Data = nil + end + + -- 销毁实例内容 + if self.Variables then + for k, v in pairs(self.Variables) do + if v.Destroy then + v:Destroy() + end + v = nil + end + end + for k, v in pairs(self) do self[k] = nil end diff --git a/src/ReplicatedStorage/Json/Attributes.json b/src/ReplicatedStorage/Json/Attributes.json index ae4d652..419a1fa 100644 --- a/src/ReplicatedStorage/Json/Attributes.json +++ b/src/ReplicatedStorage/Json/Attributes.json @@ -1,33 +1,33 @@ [ -{"id":1,"type":1,"effectAttribute":"attack","battleValue":[1,10]}, -{"id":2,"type":1,"effectAttribute":"hp","battleValue":[1,10]}, -{"id":3,"type":1,"effectAttribute":"swordAtk","battleValue":[1,10]}, -{"id":4,"type":2,"effectAttribute":"swordWearBase","battleValue":[1,10]}, -{"id":5,"type":2,"effectAttribute":"swordWearSpe","battleValue":[1,10]}, -{"id":6,"type":2,"effectAttribute":"fireAtk","battleValue":[1,10]}, -{"id":7,"type":2,"effectAttribute":"iceAtk","battleValue":[1,10]}, -{"id":8,"type":2,"effectAttribute":"lightAtk","battleValue":[1,10]}, -{"id":9,"type":2,"effectAttribute":"shadowAtk","battleValue":[1,10]}, -{"id":10,"type":1,"effectAttribute":"fireDef","battleValue":[1,10]}, -{"id":11,"type":1,"effectAttribute":"iceDef","battleValue":[1,10]}, -{"id":12,"type":1,"effectAttribute":"lightDef","battleValue":[1,10]}, -{"id":13,"type":1,"effectAttribute":"shadowDef","battleValue":[1,10]}, -{"id":14,"type":2,"effectAttribute":"attackRate","battleValue":[1,10]}, -{"id":15,"type":2,"effectAttribute":"hpRate","battleValue":[1,10]}, -{"id":16,"type":2,"effectAttribute":"atkSpeed","battleValue":[1,10]}, -{"id":20,"type":2,"effectAttribute":"critRate","battleValue":[1,10]}, -{"id":21,"type":2,"effectAttribute":"critDamageRate","battleValue":[1,10]}, -{"id":22,"type":2,"effectAttribute":"atkSpeedRate","battleValue":[1,10]}, -{"id":23,"type":2,"effectAttribute":"cdRate","battleValue":[1,10]}, -{"id":24,"type":1,"effectAttribute":"mpBonus","battleValue":[1,10]}, -{"id":25,"type":2,"effectAttribute":"mpReduceRate","battleValue":[1,10]}, -{"id":26,"type":1,"effectAttribute":"mpRecoverBonus","battleValue":[1,10]}, -{"id":27,"type":2,"effectAttribute":"vampireRate","battleValue":[1,10]}, -{"id":28,"type":2,"effectAttribute":"coinBonus","battleValue":[1,10]}, -{"id":50,"type":1,"effectAttribute":"wearNumber","battleValue":[1,10]}, -{"id":51,"type":1,"effectAttribute":"skillNumber","battleValue":[1,10]}, -{"id":52,"type":1,"effectAttribute":"extraAttributeNumber","battleValue":[1,10]}, -{"id":53,"type":1,"effectAttribute":"elementNumber","battleValue":[1,10]}, -{"id":54,"type":1,"effectAttribute":"elementDefNumber","battleValue":[1,10]}, -{"id":55,"type":1,"effectAttribute":"gemNumber","battleValue":[1,10]} +{"id":1,"type":1,"effectAttribute":"attack","battleValue":[1,10],"iconId":1}, +{"id":2,"type":1,"effectAttribute":"hp","battleValue":[1,10],"iconId":2}, +{"id":3,"type":1,"effectAttribute":"swordAtk","battleValue":[1,10],"iconId":3}, +{"id":4,"type":2,"effectAttribute":"swordWearBase","battleValue":[1,10],"iconId":4}, +{"id":5,"type":2,"effectAttribute":"swordWearSpe","battleValue":[1,10],"iconId":5}, +{"id":6,"type":2,"effectAttribute":"fireAtk","battleValue":[1,10],"iconId":6}, +{"id":7,"type":2,"effectAttribute":"iceAtk","battleValue":[1,10],"iconId":7}, +{"id":8,"type":2,"effectAttribute":"lightAtk","battleValue":[1,10],"iconId":8}, +{"id":9,"type":2,"effectAttribute":"shadowAtk","battleValue":[1,10],"iconId":9}, +{"id":10,"type":1,"effectAttribute":"fireDef","battleValue":[1,10],"iconId":10}, +{"id":11,"type":1,"effectAttribute":"iceDef","battleValue":[1,10],"iconId":11}, +{"id":12,"type":1,"effectAttribute":"lightDef","battleValue":[1,10],"iconId":12}, +{"id":13,"type":1,"effectAttribute":"shadowDef","battleValue":[1,10],"iconId":13}, +{"id":14,"type":2,"effectAttribute":"attackRate","battleValue":[1,10],"iconId":14}, +{"id":15,"type":2,"effectAttribute":"hpRate","battleValue":[1,10],"iconId":15}, +{"id":16,"type":2,"effectAttribute":"atkSpeed","battleValue":[1,10],"iconId":16}, +{"id":20,"type":2,"effectAttribute":"critRate","battleValue":[1,10],"iconId":17}, +{"id":21,"type":2,"effectAttribute":"critDamageRate","battleValue":[1,10],"iconId":18}, +{"id":22,"type":2,"effectAttribute":"atkSpeedRate","battleValue":[1,10],"iconId":19}, +{"id":23,"type":2,"effectAttribute":"cdRate","battleValue":[1,10],"iconId":20}, +{"id":24,"type":1,"effectAttribute":"mpBonus","battleValue":[1,10],"iconId":21}, +{"id":25,"type":2,"effectAttribute":"mpReduceRate","battleValue":[1,10],"iconId":22}, +{"id":26,"type":1,"effectAttribute":"mpRecoverBonus","battleValue":[1,10],"iconId":23}, +{"id":27,"type":2,"effectAttribute":"vampireRate","battleValue":[1,10],"iconId":24}, +{"id":28,"type":2,"effectAttribute":"coinBonus","battleValue":[1,10],"iconId":25}, +{"id":50,"type":1,"effectAttribute":"wearNumber","battleValue":[1,10],"iconId":26}, +{"id":51,"type":1,"effectAttribute":"skillNumber","battleValue":[1,10],"iconId":27}, +{"id":52,"type":1,"effectAttribute":"extraAttributeNumber","battleValue":[1,10],"iconId":28}, +{"id":53,"type":1,"effectAttribute":"elementNumber","battleValue":[1,10],"iconId":29}, +{"id":54,"type":1,"effectAttribute":"elementDefNumber","battleValue":[1,10],"iconId":30}, +{"id":55,"type":1,"effectAttribute":"gemNumber","battleValue":[1,10],"iconId":31} ] \ No newline at end of file diff --git a/src/ReplicatedStorage/Tools/Utils.luau b/src/ReplicatedStorage/Tools/Utils.luau index 34454c0..86f5a62 100644 --- a/src/ReplicatedStorage/Tools/Utils.luau +++ b/src/ReplicatedStorage/Tools/Utils.luau @@ -2,6 +2,7 @@ local Utils = {} --> Services local ReplicatedStorage = game:GetService("ReplicatedStorage") +local HttpService = game:GetService("HttpService") --> Variables local PlayerDataFolder = ReplicatedStorage:WaitForChild("PlayerData") @@ -184,6 +185,12 @@ function Utils:CreateDataInstance(Player: Player, UniqueId: number, EquipmentDat return Config end +function Utils:CompareTableJson(t1: table, t2: table) + local json1 = HttpService:JSONEncode(t1) + local json2 = HttpService:JSONEncode(t2) + return json1 == json2 +end + -- 复制表 function Utils:CopyTable(t: table) local newTable = {} diff --git a/src/ServerStorage/Proxy/EquipmentProxy.luau b/src/ServerStorage/Proxy/EquipmentProxy.luau index f489d70..44b13c2 100644 --- a/src/ServerStorage/Proxy/EquipmentProxy.luau +++ b/src/ServerStorage/Proxy/EquipmentProxy.luau @@ -19,6 +19,8 @@ local JsonParam = require(ReplicatedStorage.Json.Param) --> Events local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip +local RE_WearEquipment = ReplicatedStorage.Events.RE_WearEquipment + --> Constants local STORE_NAME = "Equipment" @@ -64,7 +66,7 @@ function EquipmentProxy:InitPlayer(Player: Player) -- 初始化装备 for uniqueId, EquipmentData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do - Utils:CreateDataInstance(Player, uniqueId, EquipmentData, GetPlayerEquipmentFolder(Player)) + local config = Utils:CreateDataInstance(Player, uniqueId, EquipmentData, GetPlayerEquipmentFolder(Player)) end end @@ -78,7 +80,7 @@ function EquipmentProxy:AddEquipment(Player: Player, EquipmentId: number) local EquipmentData = Utils:GetIdDataFromJson(JsonEquipment, EquipmentId) if not EquipmentData then return end - local UniqueId = Utils:GenUniqueId(ArchiveProxy.pData[Player.UserId]) + local UniqueId = Utils:GenUniqueId(ArchiveProxy.pData[Player.UserId][STORE_NAME]) -- 配置表内容 local ResultData = {} for key, value in pairs(EquipmentData) do @@ -107,16 +109,16 @@ function EquipmentProxy:AddEquipment(Player: Player, EquipmentId: number) [6] = 5, } local quality = Utils:GetRandomWeightIndex(qualityWeightTable) - local qualityParam = Utils:GetIdDataFromJson(JsonParam, 1) + local qualityParam = Utils:GetIdDataFromJson(JsonParam, 1).intArray ResultData.quality = quality -- 生成装备基础词条(固定的) ResultData.attributes = {} - for i = 1, EquipmentData.attributesNumber, 3 do + for i = 1, #EquipmentData.attributes, 3 do local AttributeData = Utils:GetIdDataFromJson(JsonAttributes, EquipmentData.attributes[i]) local baseLvValue = EquipmentData.attributes[i + 1] + EquipmentData.attributes[i + 2] * (PlayerLevel - 1) local qualityEffectValue = math.floor(baseLvValue * (qualityParam[quality] / 100)) - ResultData.attributes[AttributeData.name] = qualityEffectValue + ResultData.attributes[AttributeData.effectAttribute] = qualityEffectValue end -- TODO: 其他随机词条内容添加在下面 @@ -216,7 +218,8 @@ function EquipmentProxy:AddEquipment(Player: Player, EquipmentId: number) ------------------------------------------------------------ - ArchiveProxy.pData[Player.UserId][UniqueId] = ResultData + ArchiveProxy.pData[Player.UserId][STORE_NAME][UniqueId] = ResultData + print(ArchiveProxy.pData[Player.UserId][STORE_NAME]) Utils:CreateDataInstance(Player, UniqueId, ResultData, GetPlayerEquipmentFolder(Player)) -- 添加图鉴记录 @@ -257,7 +260,8 @@ function EquipmentProxy:WearEquipment(Player: Player, EquipmentId: number, Slot: -- TODO :穿戴装备时再生成模型 -- 查看槽位数量是否超出 local PlayerInfoData = PlayerInfoProxy:GetPlayerInfo(Player) - if Slot > PlayerInfoData.wearingNumber then + -- 没升级是没有键值对的,所以做了个括号简单判断 + if Slot > (PlayerInfoData.AttributesUpgrade.wearingNumber or 1) then RE_PlayerTip:FireClient(Player, '穿戴装备槽位超出') return end @@ -355,5 +359,14 @@ end ReplicatedStorage.Remotes.PlayerRemoving.Event:Connect(function(PlayerUserId: string) EquipmentProxy:OnPlayerRemoving(PlayerUserId) end) +RE_WearEquipment.OnServerEvent:Connect(function(Player: Player, EquipmentUniqueId: number, SlotId: number, Unwear: boolean?) + if Unwear then + EquipmentProxy:UnwearEquipment(Player, EquipmentUniqueId) + else + print(Player, EquipmentUniqueId, SlotId) + EquipmentProxy:WearEquipment(Player, EquipmentUniqueId, SlotId) + end +end) + return EquipmentProxy \ No newline at end of file diff --git a/src/ServerStorage/Proxy/HelpProxy.luau b/src/ServerStorage/Proxy/HelpProxy.luau index 3d657c9..7334435 100644 --- a/src/ServerStorage/Proxy/HelpProxy.luau +++ b/src/ServerStorage/Proxy/HelpProxy.luau @@ -23,13 +23,16 @@ RE_PlayerHelper.OnServerEvent:Connect(function(Player: Player, EventName: string elseif EventName == "AddItem" then local PlayerInfoProxy = require(script.Parent.PlayerInfoProxy) local itemData = Utils:GetIdDataFromJson(JsonItemProp, EventData[1]) - if itemData.type == 3 then + if itemData.type == 2 then + local EquipmentProxy = require(script.Parent.EquipmentProxy) + EquipmentProxy:AddEquipment(Player, EventData[1], EventData[2]) + elseif itemData.type == 3 then local BookProxy = require(script.Parent.BookProxy) BookProxy:UnlockBook(Player, EventData[1] - 10000) else PlayerInfoProxy:ChangeItemCount(Player, EventData[1], EventData[2]) end - print("添加物品成功", PlayerInfoProxy:GetItemCount(Player, EventData[1])) + print("添加物品成功", EventData) end end) diff --git a/src/ServerStorage/Proxy/PlayerInfoProxy.luau b/src/ServerStorage/Proxy/PlayerInfoProxy.luau index 16e31eb..f86d984 100644 --- a/src/ServerStorage/Proxy/PlayerInfoProxy.luau +++ b/src/ServerStorage/Proxy/PlayerInfoProxy.luau @@ -127,7 +127,7 @@ end function PlayerInfoProxy:GetPlayerLevel(Player: Player) if not Player then warn('获取玩家等级失败: ', Player.Name) return end local playerInfoData = ArchiveProxy.pData[Player.UserId][STORE_NAME] - return playerInfoData.Stats.level + return playerInfoData.Stats.level.value end function PlayerInfoProxy:GetPlayerAttributesUpgrade(Player: Player, AttributeName: string) diff --git a/src/StarterPlayerScripts/BilGui/Gui.client.luau b/src/StarterPlayerScripts/BilGui/Gui.client.luau index 78d777e..ebd91d1 100644 --- a/src/StarterPlayerScripts/BilGui/Gui.client.luau +++ b/src/StarterPlayerScripts/BilGui/Gui.client.luau @@ -1,32 +1,32 @@ -local function load_bil_gui() - local player = game.Players.LocalPlayer - local gui = player:WaitForChild("PlayerGui") - local bil_gui = game.StarterPlayer.StarterPlayerScripts.BilGui -- BilGui 是一个文件夹 +-- local function load_bil_gui() +-- local player = game.Players.LocalPlayer +-- local gui = player:WaitForChild("PlayerGui") +-- local bil_gui = game.StarterPlayer.StarterPlayerScripts.BilGui -- BilGui 是一个文件夹 - print("加载bilgui开始") - -- 将 BilGui 加载到指定的 UI 预制体中 - for _, folder in ipairs(bil_gui:GetChildren()) do - if folder:IsA("Folder") then - local target_ui = gui:WaitForChild(folder.Name) - if target_ui then - for _, script in ipairs(folder:GetChildren()) do - if script:IsA("LocalScript") then - local target_frame = target_ui:WaitForChild(script.Name) -- 找对应脚本名字的frame - if target_frame then - local script_clone = script:Clone() - script_clone.Parent = target_frame - print("加载成功: " .. script.Name) - else - warn("目标 Frame 未找到: " .. script.Name) - end - end - end - else - warn("目标 UI 预制体未找到: " .. script.Name) - end - end - end - print("加载bilgui结束") -end +-- print("加载bilgui开始") +-- -- 将 BilGui 加载到指定的 UI 预制体中 +-- for _, folder in ipairs(bil_gui:GetChildren()) do +-- if folder:IsA("Folder") then +-- local target_ui = gui:WaitForChild(folder.Name) +-- if target_ui then +-- for _, script in ipairs(folder:GetChildren()) do +-- if script:IsA("LocalScript") then +-- local target_frame = target_ui:WaitForChild(script.Name) -- 找对应脚本名字的frame +-- if target_frame then +-- local script_clone = script:Clone() +-- script_clone.Parent = target_frame +-- print("加载成功: " .. script.Name) +-- else +-- warn("目标 Frame 未找到: " .. script.Name) +-- end +-- end +-- end +-- else +-- warn("目标 UI 预制体未找到: " .. script.Name) +-- end +-- end +-- end +-- print("加载bilgui结束") +-- end -load_bil_gui() \ No newline at end of file +-- load_bil_gui() \ No newline at end of file diff --git a/src/StarterPlayerScripts/ClientMain/Helper.luau b/src/StarterPlayerScripts/ClientMain/Helper.luau index 5d9f989..1168257 100644 --- a/src/StarterPlayerScripts/ClientMain/Helper.luau +++ b/src/StarterPlayerScripts/ClientMain/Helper.luau @@ -26,6 +26,8 @@ UserInputService.InputBegan:Connect(function(input, gameProcessed) RE_UpgradeAttributes:FireServer(4) elseif input.KeyCode == Enum.KeyCode.KeypadOne then RE_PlayerHelper:FireServer("AddItem", {math.random(50000, 50015), 1}) + elseif input.KeyCode == Enum.KeyCode.KeypadTwo then + RE_PlayerHelper:FireServer("AddItem", {math.random(40000, 40015), 1}) end end end) diff --git a/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau b/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau index db38889..43b423b 100644 --- a/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau +++ b/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau @@ -55,13 +55,13 @@ RE_PerformanceEvent.OnClientEvent:Connect(function(ServerTime: number, CastTag: local delayTime = ServerTime - tick() if CastTag == "Init" then - print("Init", BehaviourName) + -- print("Init", BehaviourName) -- 暂时就新增一个表,不调用初始化,因为服务端不是多个new做的,而是多次调用 if not PerformanceClient.pData[UserId][BehaviourName] then PerformanceClient.pData[UserId][BehaviourName] = {} end elseif CastTag == "Show" then - print("Show", BehaviourName, Behaviours, Infos) + -- print("Show", BehaviourName, Behaviours, Infos) -- 直接调用init和对应的show(因为服务端只new一次,客户端多次调用) if not PerformanceClient.pData[UserId][BehaviourName] then return end for _, CastInfo in pairs(Infos) do @@ -94,7 +94,11 @@ end) -- 这里主要是初始化 RE_AbilityPerformance.OnClientEvent:Connect(function(ServerTime: number, CastTag: string, CastPlayer: Player, AbilityDetail: table) print("AbilityPerformance", ServerTime, CastTag, CastPlayer, AbilityDetail) - UIManager:OpenWindow("AbilityStateWindow", AbilityDetail) + if not UIManager:IsOpened("AbilityStateWindow") then + UIManager:OpenWindow("AbilityStateWindow", AbilityDetail) + else + UIManager:SetData("AbilityStateWindow", AbilityDetail) + end end) -- 清理玩家所有表现数据 diff --git a/src/StarterPlayerScripts/UI/UIManager.luau b/src/StarterPlayerScripts/UI/UIManager.luau index eb11217..4f513d5 100644 --- a/src/StarterPlayerScripts/UI/UIManager.luau +++ b/src/StarterPlayerScripts/UI/UIManager.luau @@ -18,6 +18,14 @@ function UIManager:OpenWindow(WindowName: string, Data: table?) UIManager.Instances[WindowName]:OnOpenWindow() end +function UIManager:SetData(WindowName: string, Data: table) + if not UIManager.Instances[WindowName] then + warn("UIManager:SetData() 窗口不存在:" .. WindowName) + return + end + UIManager.Instances[WindowName]:SetData(Data) +end + function UIManager:CloseWindow(WindowName: string) if not UIManager.Instances[WindowName] then warn("UIManager:CloseWindow() 窗口不存在:" .. WindowName) @@ -25,6 +33,12 @@ function UIManager:CloseWindow(WindowName: string) end UIManager.Instances[WindowName]:OnCloseWindow() + UIManager.Instances[WindowName]:Destroy() + UIManager.Instances[WindowName] = nil +end + +function UIManager:IsOpened(WindowName: string) + return UIManager.Instances[WindowName] ~= nil end diff --git a/src/StarterPlayerScripts/UI/Windows/ChaWindow/PackageShow.luau b/src/StarterPlayerScripts/UI/Windows/ChaWindow/PackageShow.luau new file mode 100644 index 0000000..2b2e914 --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/ChaWindow/PackageShow.luau @@ -0,0 +1,50 @@ +local PackageShow = {} +PackageShow.__index = PackageShow + +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local Utils = require(ReplicatedStorage.Tools.Utils) +local Localization = require(ReplicatedStorage.Tools.Localization) +local JsonEquipment = require(ReplicatedStorage.Json.Equipment) +local JsonItemProp = require(ReplicatedStorage.Json.ItemProp) + +function PackageShow:Init(data: table) + local self = {} + self.Data = data + self.Variables = { + ["_btnClick"] = 0, + ["_imgIcon"] = 0, + ["_tmpQuality"] = 0, + } + self.Connections = {} + + setmetatable(self, PackageShow) + return self +end + +function PackageShow:Refresh() + local itemData = Utils:GetIdDataFromJson(JsonItemProp, self.Data.orgId) + self.Variables._imgIcon.Image = Localization:GetImageData(itemData.iconId) + self.Variables._imgIcon.Visible = false + self.Variables._tmpQuality.Text = self.Data.quality +end + +function PackageShow:OnInitFinish() + local con = self.Variables._btnClick.MouseButton1Click:Connect(function() + if self.Data == {} then + -- TODO: 之后做提示弹窗 + else + self.TopUI:ShowDetailData(self.Data.id) + end + end) + table.insert(self.Connections, con) +end + +function PackageShow:Destroy() + for k, v in pairs(self) do + self[k] = nil + end + self = nil +end + +return PackageShow \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/ChaWindow/WearingShow.luau b/src/StarterPlayerScripts/UI/Windows/ChaWindow/WearingShow.luau new file mode 100644 index 0000000..ed9b7ed --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/ChaWindow/WearingShow.luau @@ -0,0 +1,61 @@ +local WearingShow = {} +WearingShow.__index = WearingShow + +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local Utils = require(ReplicatedStorage.Tools.Utils) +local Localization = require(ReplicatedStorage.Tools.Localization) +local JsonEquipment = require(ReplicatedStorage.Json.Equipment) +local JsonItemProp = require(ReplicatedStorage.Json.ItemProp) + +function WearingShow:Init(data: table) + local self = {} + self.Data = data + self.Variables = { + ["_btnClick"] = 0, + ["_imgIcon"] = 0, + ["_imgbg"] = 0, + ["_tmpQuality"] = 0, + } + self.Connections = {} + + setmetatable(self, WearingShow) + + return self +end + +function WearingShow:Refresh() + -- 槽位为空 + if self.Data.id == nil then + self.Variables._imgIcon.Image = "" + self.Variables._imgbg.Visible = true + self.Variables._tmpQuality.Text = "" + else + -- 槽位有装备 + local itemData = Utils:GetIdDataFromJson(JsonItemProp, self.Data.orgId) + self.Variables._imgIcon.Image = Localization:GetImageData(itemData.iconId) + self.Variables._imgbg.Visible = false + self.Variables._tmpQuality.Text = self.Data.quality + end +end + + +function WearingShow:OnInitFinish() + local con = self.Variables._btnClick.MouseButton1Click:Connect(function() + if self.Data == {} then + -- TODO: 之后做提示弹窗 + else + self.TopUI:ShowDetailData(self.Data.id) + end + end) + table.insert(self.Connections, con) +end + +function WearingShow:Destroy() + for k, v in pairs(self) do + self[k] = nil + end + self = nil +end + +return WearingShow \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/ChaWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/ChaWindow/init.luau new file mode 100644 index 0000000..f50976a --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/ChaWindow/init.luau @@ -0,0 +1,142 @@ +--> Services +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Dependencies +local UIWindow = require(ReplicatedStorage.Base.UIWindow) +local UIEnums = require(ReplicatedStorage.Base.UIEnums) + +--> Components +local WearingShow = require(script.WearingShow) +local PackageShow = require(script.PackageShow) + +--> Dependencies +local Utils = require(ReplicatedStorage.Tools.Utils) + +--> Json +local JsonAttributesUpgrade = require(ReplicatedStorage.Json.AttributesUpgrade) + +--> Variables +local LocalPlayer = game.Players.LocalPlayer + +-------------------------------------------------------------------------------- + +local ChaWindow = {} +ChaWindow.__index = ChaWindow +setmetatable(ChaWindow, {__index = UIWindow}) + +function ChaWindow:Init(UIManager: table, Data: table?) + local self = UIWindow:Init(UIManager, Data) + setmetatable(self, ChaWindow) + self.Variables = { + ["__listWeaponPackage"] = 0, + ["__listWeaing"] = 0, + ["_tmpCombatValue"] = 0, + ["_imgIcon"] = 0, + ["_btnClose"] = 0, + ["_btnBgClose"] = 0, + } + self.UIRootName = "ui_w_cha" + self.UIParentName = UIEnums.UIParent.UIRoot + + return self +end + +function ChaWindow:ShowDetailData(uniqueId: number) + local data = { + EquipmentUniqueId = uniqueId, + } + self.UIManager:OpenWindow("EquipmentDetailWindow", data) +end + +function ChaWindow:AddInstanceData(configInstance: Instance, Data: table?) + local data = self.Data + if Data then data = Data end + local attributes = configInstance:GetAttributes() + + -- 归类是否是穿戴的装备 + local parentName = "Package" + if attributes.wearing ~= 0 then parentName = "Wearing" end + data[parentName][configInstance.Name] = {} + + for attributeKey, attributeValue in attributes do + data[parentName][configInstance.Name][attributeKey] = attributeValue + end + return data[parentName][configInstance.Name], parentName +end + +function ChaWindow:OnOpenWindow() + UIWindow.OnOpenWindow(self) + + -- 自己进行数据处理 + local DataFolder = Utils:GetPlayerDataFolder(LocalPlayer):FindFirstChild("Equipment") + local data = { + Wearing = {}, + Package = {}, + } + for _, child in DataFolder:GetChildren() do + self:AddInstanceData(child, data) + end + self:SetData(data) + + local maxSlotNumber = Utils:GetIdDataFromJson(JsonAttributesUpgrade, 10).maxLv + for i = 1, maxSlotNumber do + local isExist = false + for k, data in pairs(self.Data.Wearing) do + if data.wearing == i then + isExist = true + break + end + end + if not isExist then + self.Data.Wearing["slot" .. i] = { + wearing = i, + } + end + end + + local addCon = DataFolder.ChildAdded:Connect(function(child) + local data, parentName = self:AddInstanceData(child, data) + if parentName == "Wearing" then + self.Variables["__listWeaing"]:AddData(data) + else + self.Variables["__listWeaponPackage"]:AddData(data) + end + end) + + local removeCon = DataFolder.ChildRemoved:Connect(function(child) + local parentName = self:RemoveInstanceData(child, data) + if parentName == "Wearing" then + local removeIndex = self.Variables["__listWeaing"]:RemoveData(data) + self.Data.Wearing[removeIndex] = {} + else + local removeIndex = self.Variables["__listWeaponPackage"]:RemoveData(data) + self.Data.Package[removeIndex] = {} + end + end) + + 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, addCon) + table.insert(self.Connections, removeCon) + table.insert(self.Connections, bgCloseCon) + table.insert(self.Connections, closeCon) + + self.Variables["__listWeaponPackage"]:AddComponent(PackageShow) + self.Variables["__listWeaing"]:AddComponent(WearingShow) + self.Variables["__listWeaponPackage"]:SetData(self.Data.Package) + self.Variables["__listWeaing"]:SetData(self.Data.Wearing) + self.Variables["__listWeaing"]:SetLayoutOrder("wearing") +end + +function ChaWindow:OnCloseWindow() + UIWindow.OnCloseWindow(self) +end + + + +return ChaWindow \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/CreateWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/CreateWindow/init.luau index 349f43b..d3036b6 100644 --- a/src/StarterPlayerScripts/UI/Windows/CreateWindow/init.luau +++ b/src/StarterPlayerScripts/UI/Windows/CreateWindow/init.luau @@ -151,8 +151,6 @@ end function CreateWindow:OnCloseWindow() UIWindow.OnCloseWindow(self) - - self.Variables["__listWeaponPackage"]:Clean() end diff --git a/src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/AttributeShow.luau b/src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/AttributeShow.luau new file mode 100644 index 0000000..f8fad43 --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/AttributeShow.luau @@ -0,0 +1,50 @@ +local AttributeShow = {} +AttributeShow.__index = AttributeShow + +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local Utils = require(ReplicatedStorage.Tools.Utils) +local Localization = require(ReplicatedStorage.Tools.Localization) +local JsonEquipment = require(ReplicatedStorage.Json.Equipment) +local JsonItemProp = require(ReplicatedStorage.Json.ItemProp) +local JsonAttributes = require(ReplicatedStorage.Json.Attributes) + +function AttributeShow:Init(data: table) + local self = {} + self.Data = data + self.Variables = { + ["_imgIcon"] = 0, + ["_tmpAttributeName"] = 0, + ["_tmpValue"] = 0, + } + + setmetatable(self, AttributeShow) + return self +end + +function AttributeShow:Refresh() + local attributeData = Utils:GetSpecialKeyDataFromJson(JsonAttributes, "effectAttribute", self.Data.attribute) + if attributeData.id == 14 or attributeData.id == 15 or attributeData.id == 16 then + self.Variables._imgIcon.Image = Localization:GetImageData(attributeData.iconId) + else + self.Variables._imgIcon:Destroy() + self.Variables._imgIcon = nil + end + self.Variables._tmpAttributeName.Text = self.Data.attribute + self.UIRoot.LayoutOrder = 1000 - attributeData.id + + if attributeData.type == 2 then + self.Variables._tmpValue.Text = string.format("%.2f%%", self.Data.value / 100) + else + self.Variables._tmpValue.Text = self.Data.value + end +end + +function AttributeShow:Destroy() + for k, v in pairs(self) do + self[k] = nil + end + self = nil +end + +return AttributeShow \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/ReplaceShow.luau b/src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/ReplaceShow.luau new file mode 100644 index 0000000..7655835 --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/ReplaceShow.luau @@ -0,0 +1,57 @@ +local ReplaceShow = {} +ReplaceShow.__index = ReplaceShow + +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local Utils = require(ReplicatedStorage.Tools.Utils) +local Localization = require(ReplicatedStorage.Tools.Localization) +local JsonEquipment = require(ReplicatedStorage.Json.Equipment) +local JsonItemProp = require(ReplicatedStorage.Json.ItemProp) + +--> Events +local RE_WearEquipment = ReplicatedStorage.Events.RE_WearEquipment + +function ReplaceShow:Init(data: table) + local self = {} + self.Data = data + self.Variables = { + ["_btnClick"] = 0, + ["_imgIcon"] = 0, + ["_imgbg"] = 0, + ["_tmpQuality"] = 0, + } + self.Connections = {} + + setmetatable(self, ReplaceShow) + + local con = self.Variables._btnClick.MouseButton1Click:Connect(function() + RE_WearEquipment:FireServer(self.Data.uniqueId, self.Data.wearing, false) + self.TopUI:CloseReplaceWindow() + end) + table.insert(self.Connections, con) + return self +end + +function ReplaceShow:Refresh() + -- 槽位为空 + if self.Data.id == nil then + self.Variables._imgIcon.Image = "" + self.Variables._imgbg.Image.Visible = true + self.Variables._tmpQuality.Text = "" + else + -- 槽位有装备 + local itemData = Utils:GetIdDataFromJson(JsonItemProp, self.Data.orgId) + self.Variables._imgIcon.Image = Localization:GetItemIcon(itemData.iconId) + self.Variables._imgbg.Image.Visible = false + self.Variables._tmpQuality.Text = self.Data.quality + end +end + +function ReplaceShow:Destroy() + for k, v in pairs(self) do + self[k] = nil + end + self = nil +end + +return ReplaceShow \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/init.luau new file mode 100644 index 0000000..093bac8 --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/EquipmentDetailWindow/init.luau @@ -0,0 +1,234 @@ +--> Services +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Dependencies +local UIWindow = require(ReplicatedStorage.Base.UIWindow) +local UIEnums = require(ReplicatedStorage.Base.UIEnums) + +--> Components +local AttributeShow = require(script.AttributeShow) +local ReplaceShow = require(script.ReplaceShow) + +--> Dependencies +local Utils = require(ReplicatedStorage.Tools.Utils) +local Localization = require(ReplicatedStorage.Tools.Localization) + +--> Json +local JsonItemProp = require(ReplicatedStorage.Json.ItemProp) +local JsonEquipment = require(ReplicatedStorage.Json.Equipment) +local JsonAttributesUpgrade = require(ReplicatedStorage.Json.AttributesUpgrade) + +--> Events +local RE_WearEquipment = ReplicatedStorage.Events.RE_WearEquipment + +--> Variables +local LocalPlayer = game.Players.LocalPlayer + +-------------------------------------------------------------------------------- + +local EquipmentDetailWindow = {} +EquipmentDetailWindow.__index = EquipmentDetailWindow +setmetatable(EquipmentDetailWindow, {__index = UIWindow}) + +function EquipmentDetailWindow:Init(UIManager: table, Data: table?) + local self = UIWindow:Init(UIManager, Data) + setmetatable(self, EquipmentDetailWindow) + self.Variables = { + ["__listBaseAttributes"] = 0, + ["_goExAttributesPanel"] = 0, + ["__listExAttributes"] = 0, + ["_goElementPanel"] = 0, + ["__listElement"] = 0, + ["_goElementDefPanel"] = 0, + ["__listElementDef"] = 0, + + ["_imgIcon"] = 0, + ["_tmpName"] = 0, + ["_tmpQuality"] = 0, + ["_tmpCombatValue"] = 0, + + ["_goBottomPanel"] = 0, + ["_btnUnwear"] = 0, + ["_btnWear"] = 0, + + ["_goReplaceDetail"] = 0, + ["__listReplace"] = 0, + + ["_btnClose"] = 0, + ["_btnBgClose"] = 0, + ["_btnReplaceClose"] = 0, + } + self.UIRootName = "ui_w_equipment_detail" + self.UIParentName = UIEnums.UIParent.UIRoot + + return self +end + +function EquipmentDetailWindow:TransformKeyTable(data: table) + local newData = {} + local index = 1 + for k, v in pairs(data) do + newData[index] = {} + newData[index]["attribute"] = k + newData[index]["value"] = v + index = index + 1 + end + return newData +end + +function EquipmentDetailWindow:AddInstanceData(configInstance: Instance, Data: table?) + local data = self.Data + if Data then data = Data end + local attributes = configInstance:GetAttributes() + + -- 归类是否是穿戴的装备 + local parentName = "Package" + data[parentName][configInstance.Name] = {} + if attributes.wearing then parentName = "Wearing" end + + for attributeKey, attributeValue in attributes do + data[parentName][configInstance.Name][attributeKey] = attributeValue + end + return data[parentName][configInstance.Name], parentName +end + +function EquipmentDetailWindow:ShowReplaceWindow(data: table) + self.Variables["_goReplaceDetail"].Visible = true + self.Variables["__listReplace"]:AddComponent(ReplaceShow) + self.Variables["__listReplace"]:SetData(data) + self.Variables["__listReplace"]:SetLayoutOrder("wearing") +end + +function EquipmentDetailWindow:CloseReplaceWindow() + self.Variables["_goReplaceDetail"].Visible = false +end + +function EquipmentDetailWindow:OnOpenWindow() + UIWindow.OnOpenWindow(self) + + -- 关闭替换页面 + self.Variables["_goReplaceDetail"].Visible = false + + -- 处理数据 + local selfData = Utils:GetPlayerDataFolder(LocalPlayer):FindFirstChild("Equipment") + local equipmentInstance = selfData:FindFirstChild(self.Data.EquipmentUniqueId) + local data = { + EquipmentUniqueId = self.Data.EquipmentUniqueId, + base = equipmentInstance:GetAttributes(), + attributes = equipmentInstance:FindFirstChild("attributes"):GetAttributes(), + exAttributes = equipmentInstance:FindFirstChild("exAttributes"):GetAttributes(), + elements = equipmentInstance:FindFirstChild("elements"):GetAttributes(), + elementDef = equipmentInstance:FindFirstChild("elementDef"):GetAttributes(), + } + self:SetData(data) + + 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) + + local btnUnwearCon = self.Variables["_btnUnwear"].Activated:Connect(function() + if self.Data.base.wearing ~= 0 then + RE_WearEquipment:FireServer(self.Data.EquipmentUniqueId, 0, true) + else + -- TODO: 提示弹窗,暂时没有穿戴 + end + end) + local btnWearCon = self.Variables["_btnWear"].Activated:Connect(function() + -- TODO: 只有一个槽位时,直接穿戴,如果有多个槽位,让他选择穿戴槽位 + local wearNumberInstance = Utils:GetPlayerDataFolder(LocalPlayer):FindFirstChild("PlayerInfo"):FindFirstChild("AttributesUpgrade"):FindFirstChild("wearNumber") + local EquipmentFolder = Utils:GetPlayerDataFolder(LocalPlayer):FindFirstChild("Equipment") + + if wearNumberInstance then + local data = {} + -- 穿戴装备数据设置 + for _, equipmentInstance in EquipmentFolder:GetChildren() do + local attributes = equipmentInstance:GetAttributes() + if attributes.wearing ~= 0 then + data[attributes.wearing] = {} + for attributeKey, attributeValue in attributes do + data[attributes.wearing][attributeKey] = attributeValue + end + end + end + -- 空槽位补充 + local maxSlotNumber = Utils:GetIdDataFromJson(JsonAttributesUpgrade, 11).maxLv + for i = 1, maxSlotNumber do + if not data[i] then + data[i] = { + wearing = i, + } + end + end + self:ShowReplaceWindow(data) + else + -- 检查是否已经穿戴 + local isExist = false + for _, equipmentInstance in EquipmentFolder:GetChildren() do + if equipmentInstance:GetAttribute("wearing") == 1 then + isExist = true + break + end + end + if isExist then + -- TODO: 提示弹窗,已经穿戴 + else + RE_WearEquipment:FireServer(self.Data.EquipmentUniqueId, 1) + end + end + end) + + table.insert(self.Connections, bgCloseCon) + table.insert(self.Connections, closeCon) + table.insert(self.Connections, btnUnwearCon) + table.insert(self.Connections, btnWearCon) + + -- 装备信息 + local equipmentInstance = Utils:GetPlayerDataFolder(LocalPlayer):FindFirstChild("Equipment"):FindFirstChild(self.Data.EquipmentUniqueId) + local equipmentData = Utils:GetIdDataFromJson(JsonItemProp, equipmentInstance:GetAttribute("id")) + self.Variables["_imgIcon"].Image = Localization:GetImageData(equipmentData.iconId) + self.Variables["_tmpName"].Text = Localization:GetLanguageData(equipmentData.textId) + self.Variables["_tmpQuality"].Text = equipmentInstance:GetAttribute("quality") + self.Variables["_tmpCombatValue"].Text = 0 + + -- 穿戴状态按钮显示 + self.Variables["_btnUnwear"].Visible = self.Data.base.wearing ~= 0 + self.Variables["_btnWear"].Visible = self.Data.base.wearing == 0 + + -- 基础属性 + self.Variables["__listBaseAttributes"]:AddComponent(AttributeShow) + self.Variables["__listBaseAttributes"]:SetData(self:TransformKeyTable(self.Data.attributes)) + + -- 额外属性 + if self.Data.exAttributes then + self.Variables["_goExAttributesPanel"].Visible = true + self.Variables["__listExAttributes"]:AddComponent(AttributeShow) + self.Variables["__listExAttributes"]:SetData(self:TransformKeyTable(self.Data.exAttributes)) + else + self.Variables["_goExAttributesPanel"].Visible = false + end + + -- 元素属性 + if self.Data.elements then + self.Variables["_goElementPanel"].Visible = true + self.Variables["__listElement"]:AddComponent(AttributeShow) + self.Variables["__listElement"]:SetData(self:TransformKeyTable(self.Data.elements)) + else + self.Variables["_goElementPanel"].Visible = false + end + + -- 元素定义属性 + if self.Data.elementDef then + self.Variables["_goElementDefPanel"].Visible = true + self.Variables["__listElementDef"]:AddComponent(AttributeShow) + self.Variables["__listElementDef"]:SetData(self:TransformKeyTable(self.Data.elementDef)) + else + self.Variables["_goElementDefPanel"].Visible = false + end +end + + + +return EquipmentDetailWindow \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/MainWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/MainWindow/init.luau index b998de6..06392dd 100644 --- a/src/StarterPlayerScripts/UI/Windows/MainWindow/init.luau +++ b/src/StarterPlayerScripts/UI/Windows/MainWindow/init.luau @@ -16,6 +16,7 @@ function MainWindow:Init(UIManager: table, Data: table?) setmetatable(self, MainWindow) self.Variables = { ["_btnMainCreate"] = 0, + ["_btnMainCha"] = 0, } self.UIRootName = "ui_w_main" self.UIParentName = UIEnums.UIParent.UIRoot @@ -29,7 +30,12 @@ function MainWindow:OnOpenWindow() local createCon = self.Variables["_btnMainCreate"].Activated:Connect(function() self.UIManager:OpenWindow("CreateWindow") end) + local chaCon = self.Variables["_btnMainCha"].Activated:Connect(function() + self.UIManager:OpenWindow("ChaWindow") + end) + table.insert(self.Connections, createCon) + table.insert(self.Connections, chaCon) end