rbxIdleWeapon/src/ServerStorage/Proxy/EquipmentProxy.luau
2025-08-15 19:24:17 +08:00

521 lines
22 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 装备代理
local EquipmentProxy = {}
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Variables
local Utils = require(ReplicatedStorage.Tools.Utils)
local Rng = require(ReplicatedStorage.Tools.Rng)
local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy)
local PlayerInfoProxy = require(ServerStorage.Proxy.PlayerInfoProxy)
local PlayerFightProxy = require(ServerStorage.Proxy.PlayerFightProxy)
local AbilityProxy = require(ServerStorage.Proxy.AbilityProxy)
--> Json
local JsonEquipment = require(ReplicatedStorage.Json.Equipment)
local JsonAttributes = require(ReplicatedStorage.Json.Attributes)
local JsonExAttributes = require(ReplicatedStorage.Json.ExAttributes)
local JsonParam = require(ReplicatedStorage.Json.Param)
local JsonBlessing = require(ReplicatedStorage.Json.Blessing)
local JsonForge = require(ReplicatedStorage.Json.Forge)
local JsonQualityEffect = require(ReplicatedStorage.Json.QualityEffect)
--> Events
local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip
local RE_WearEquipment = ReplicatedStorage.Events.RE_WearEquipment
local RE_RecycleEquipment = ReplicatedStorage.Events.RE_RecycleEquipment
--> Constants
local STORE_NAME = "Equipment"
--------------------------------------------------------------------------------
-- 获取装备文件夹
local function GetPlayerEquipmentFolder(Player: Player)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
local EquipmentFolder = pData:FindFirstChild("Equipment")
return EquipmentFolder
end
-- 计算词条等级加成上限
local function GetEntryLvBonus(PlayerLv: number, BonusData: table)
local bonus = math.floor(PlayerLv / BonusData[1]) * BonusData[2]
return math.min(bonus, BonusData[3])
end
-- 改变装备数据
local function ChangeValue(Player: Player, EquipmentUniqueId: number, KeyName: string, Value: any)
if not Player or not EquipmentUniqueId or not KeyName then warn("EquipmentProxy ChangeValue", Player.UserId, EquipmentUniqueId, KeyName, Value) return end
local ValueInstance = GetPlayerEquipmentFolder(Player):FindFirstChild(EquipmentUniqueId)
if not ValueInstance then warn("ValueInstance not found", KeyName) return end
ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentUniqueId][KeyName] = Value
ValueInstance:SetAttribute(KeyName, Value)
end
--------------------------------------------------------------------------------
-- 初始化玩家
function EquipmentProxy:InitPlayer(Player: Player)
local pData = Utils:WaitPlayerDataFolder(Player)
if not pData then return end
Utils:CreateFolder("Equipment", pData)
-- 新玩家数据初始化
if not ArchiveProxy.pData[Player.UserId][STORE_NAME] then
ArchiveProxy.pData[Player.UserId][STORE_NAME] = {}
end
-- 初始化装备
for uniqueId, EquipmentData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do
local config = Utils:CreateDataInstance(Player, tostring(uniqueId), EquipmentData, GetPlayerEquipmentFolder(Player))
end
end
-- 一些特殊记录或者不用记录的Key
local EXCEPT_KEYS = { "id", "orgId", "name", "attributes"}
-- 添加装备到背包
function EquipmentProxy:AddEquipment(Player: Player, EquipmentId: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
local EquipmentData = Utils:GetIdDataFromJson(JsonEquipment, EquipmentId)
if not EquipmentData then return end
local UniqueId = Utils:GenUniqueIdString(ArchiveProxy.pData[Player.UserId][STORE_NAME])
-- 配置表内容
local ResultData = {}
for key, value in pairs(EquipmentData) do
if not table.find(EXCEPT_KEYS, key) then
ResultData[key] = value
end
end
ResultData.id = UniqueId
ResultData.orgId = EquipmentId
-- 到时候记录穿戴槽位
ResultData.wearing = 0
-- 随机生成总变量
local rng = Random.new()
local PlayerLevel = PlayerInfoProxy:GetPlayerLevel(Player)
-- TODO: 之后这里可能根据等级限制权重
-- 获取锻造等级
local forgeTime = PlayerInfoProxy:GetForgeTime(Player)
local maxForgeTime = Utils:GetMaxIdFromJson(JsonForge)
-- 当前锻造次数限制
if forgeTime <= 0 then forgeTime = 1 end
if forgeTime > maxForgeTime then forgeTime = maxForgeTime end
-- 根据锻造等级获取品质权重
local qualityWeightTable = Utils:GetIdDataFromJson(JsonForge, forgeTime).qualityRate
local quality = Rng:GetRandomWeightedIndex(qualityWeightTable)
local qualityEffectData = Utils:GetIdDataFromJson(JsonQualityEffect, quality)
-- 旧的固定值已经废弃
-- local qualityParam = Utils:GetIdDataFromJson(JsonParam, 1).intArray
ResultData.quality = quality
-- 生成装备基础词条(固定的)
ResultData.attributes = {}
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
-- 攻击速度词条特殊处理
if AttributeData.effectAttribute == "atkSpeed" then
qualityEffectValue = baseLvValue
else
qualityEffectValue = math.floor(baseLvValue * (Rng:GetRandomInt(qualityEffectData.minValue, qualityEffectData.maxValue) / 100))
end
ResultData.attributes[AttributeData.effectAttribute] = qualityEffectValue
end
-- TODO: 其他随机词条内容添加在下面
-- 随机生成额外属性数量
local maxExAttributeNumber = PlayerInfoProxy:GetPlayerInfo(Player).exAttributeNumber or 0
local exAttributeNumber = rng:NextInteger(0, maxExAttributeNumber)
ResultData.maxExAttributeNumber = exAttributeNumber
ResultData.exAttributes = {}
if exAttributeNumber > 0 then
local spawnExAttributesId = {}
for i = 1, exAttributeNumber do
local newExAttributeId = Utils:GetRandomIdFromJsonWithSpecialKey(JsonExAttributes, "specialType", 1, spawnExAttributesId)
table.insert(spawnExAttributesId, newExAttributeId)
local ExAttributeData = Utils:GetIdDataFromJson(JsonExAttributes, newExAttributeId)
local minValue = ExAttributeData.randomValue[1]
local maxValue = ExAttributeData.randomValue[2] + GetEntryLvBonus(PlayerLevel, ExAttributeData.bonus)
local randomExAttributeValue = rng:NextInteger(minValue, maxValue)
local AttributeData = Utils:GetIdDataFromJson(JsonAttributes, newExAttributeId)
ResultData.exAttributes[AttributeData.name] = randomExAttributeValue
end
end
-- 随机生成元素属性数量(暂时跟额外属性相同,之后可以改逻辑)
local maxElementNumber = PlayerInfoProxy:GetPlayerInfo(Player).elementNumber or 0
local elementNumber = rng:NextInteger(0, maxElementNumber)
ResultData.maxElementNumber = elementNumber
ResultData.elements = {}
if elementNumber > 0 then
local spawnElementsId = {}
for i = 1, elementNumber do
local newElementAttributeId = Utils:GetRandomIdFromJsonWithSpecialKey(JsonExAttributes, "specialType", 2, spawnElementsId)
table.insert(spawnElementsId, newElementAttributeId)
local ElementAttributeData = Utils:GetIdDataFromJson(JsonExAttributes, newElementAttributeId)
local minValue = ElementAttributeData.randomValue[1]
local maxValue = ElementAttributeData.randomValue[2] + GetEntryLvBonus(PlayerLevel, ElementAttributeData.bonus)
local randomElementAttributeValue = rng:NextInteger(minValue, maxValue)
local AttributeData = Utils:GetIdDataFromJson(JsonAttributes, newElementAttributeId)
ResultData.elements[AttributeData.name] = randomElementAttributeValue
end
end
-- 随机生成元素抗性数量
local maxElementDefNumber = PlayerInfoProxy:GetPlayerInfo(Player).elementDefNumber or 0
local elementDefNumber = rng:NextInteger(0, maxElementDefNumber)
ResultData.maxElementDefNumber = elementDefNumber
ResultData.elementDef = {}
if elementDefNumber > 0 then
local spawnElementDefId = {}
for i = 1, elementDefNumber do
local newElementDefId = Utils:GetRandomIdFromJsonWithSpecialKey(JsonExAttributes, "specialType", 3, spawnElementDefId)
table.insert(spawnElementDefId, newElementDefId)
local ElementDefAttributeData = Utils:GetIdDataFromJson(JsonExAttributes, newElementDefId)
local minValue = ElementDefAttributeData.randomValue[1]
local maxValue = ElementDefAttributeData.randomValue[2] + GetEntryLvBonus(PlayerLevel, ElementDefAttributeData.bonus)
local randomElementDefAttributeValue = rng:NextInteger(minValue, maxValue)
local AttributeData = Utils:GetIdDataFromJson(JsonAttributes, newElementDefId)
ResultData.elementDef[AttributeData.name] = randomElementDefAttributeValue
end
end
-- 属性祝福处理
local BookProxy = require(ServerStorage.Proxy.BookProxy)
local blessingId, blessingRate = BookProxy:GetBlessingInfo(Player, EquipmentId)
local blessingType, blessingEffect
local blessingTableName
local isNotTrigger = true
if blessingId then
local blessingData = Utils:GetIdDataFromJson(JsonBlessing, blessingId)
blessingType = blessingData.type
blessingEffect = blessingData.effect
end
if blessingType == 1 then
-- 找到对应祝福所属的表名
local attributeData = Utils:GetIdDataFromJson(JsonAttributes, blessingEffect)
if attributeData.specialType then
if attributeData.specialType == 1 then
blessingTableName = "exAttributes"
elseif attributeData.specialType == 2 then
blessingTableName = "elements"
elseif attributeData.specialType == 3 then
blessingTableName = "elementDef"
end
end
-- 如果表名存在,进行下一步处理
if blessingTableName then
-- 不存在该属性时,且有其他属性时
if not ResultData[blessingTableName][attributeData.effectAttribute] and #ResultData[blessingTableName] > 0 then
-- 随机替换功能是否触发
local isTrigger = Rng:GetRandomInt(1, 100) <= blessingRate
if isTrigger and isNotTrigger then
-- 将第一个属性替换为祝福属性,保留对应的随机值,只替换属性名
local oldAttributeValue
for key, value in ResultData[blessingTableName] do
oldAttributeValue = value
ResultData[blessingTableName][key] = nil
break
end
ResultData[blessingTableName][attributeData.effectAttribute] = oldAttributeValue
isNotTrigger = false
end
end
end
end
------------------------------------------------------------
-- 随机生成技能槽位数量
local AbilityProxy = require(ServerStorage.Proxy.AbilityProxy)
local maxAbilityNumber = PlayerInfoProxy:GetPlayerInfo(Player)["AttributesUpgrade"]["11"] or 0
local abilityNumber = rng:NextInteger(0, maxAbilityNumber)
ResultData.maxAbilityNumber = abilityNumber
-- 随机生成宝石数量
local GemProxy = require(ServerStorage.Proxy.GemProxy)
local maxGemNumber = PlayerInfoProxy:GetPlayerInfo(Player).gemNumber or 0
local gemNumber = rng:NextInteger(0, maxGemNumber)
ResultData.maxGemNumber = gemNumber
-- 随机生成符文数量
local RuneProxy = require(ServerStorage.Proxy.RuneProxy)
local maxRuneNumber = PlayerInfoProxy:GetPlayerInfo(Player)["AttributesUpgrade"]["15"] or 0
local runeNumber = rng:NextInteger(0, maxRuneNumber)
ResultData.maxRuneNumber = runeNumber
------------------------------------------------------------
ArchiveProxy.pData[Player.UserId][STORE_NAME][UniqueId] = ResultData
local equipmentInstance = Utils:CreateDataInstance(Player, UniqueId, ResultData, GetPlayerEquipmentFolder(Player))
print("生成装备符文孔数", equipmentInstance.Name, runeNumber, maxRuneNumber)
------------------------------------------------------------
-- 下面逻辑会找Instance实例所以放在之后执行逻辑
if abilityNumber > 0 then
local spawnAbilitiesId = {}
for i = 1, abilityNumber do
-- 技能祝福处理
local specialAbilityId
if blessingType == 2 and isNotTrigger then
-- 没触发过中了概率就指定技能id
local isTrigger = Rng:GetRandomInt(1, 100) <= blessingRate
if isTrigger then
specialAbilityId = blessingEffect
isNotTrigger = false
end
end
local newAbilityId = specialAbilityId or AbilityProxy:GetRandomAbilityId(spawnAbilitiesId)
table.insert(spawnAbilitiesId, newAbilityId)
local newAbilityData, newAbilityInstance = AbilityProxy:AddAbility(Player, newAbilityId)
AbilityProxy:WearAbility(Player, newAbilityData.id, UniqueId)
end
end
if gemNumber > 0 then
local spawnGemsId = {}
for i = 1, gemNumber do
local newGemId = GemProxy:GetRandomGemId(spawnGemsId)
table.insert(spawnGemsId, newGemId)
local newGemData, newGemInstance = GemProxy:AddGem(Player, newGemId)
GemProxy:WearGem(Player, newGemData.id, UniqueId)
end
end
if runeNumber > 0 then
local spawnRunesId = {}
for i = 1, runeNumber do
-- 是否生成符文
local isTrigger = Rng:GetRandomInt(1, 100) <= 5
if isTrigger then
local newRuneId = RuneProxy:GetRandomRuneId(spawnRunesId)
table.insert(spawnRunesId, newRuneId)
local newRuneData, newRuneInstance = RuneProxy:AddRune(Player, newRuneId)
RuneProxy:WearRune(Player, newRuneData.id, UniqueId)
end
end
end
------------------------------------------------------------
-- 添加图鉴记录
local BookProxy = require(ServerStorage.Proxy.BookProxy)
BookProxy:AddBook(Player, EquipmentId, UniqueId)
return equipmentInstance
end
-- 回收单件装备
function EquipmentProxy:RecycleEquipment(Player: Player, EquipmentId: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
local EquipmentData = ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentId]
if not EquipmentData then return end
-- 根据对应功能模块进行对应回收
local AbilityProxy = require(ServerStorage.Proxy.AbilityProxy)
-- AbilityProxy:RecycleAbility(Player, EquipmentData.id)
local GemProxy = require(ServerStorage.Proxy.GemProxy)
-- GemProxy:RecycleGem(Player, EquipmentData.id)
-- 回收装备返回金币
-- TODO:处理关卡金币产出加成和词条加成
local rewardData = {["1"] = EquipmentData.recycle}
PlayerInfoProxy:ChangeItemCount(Player, 1, EquipmentData.recycle)
ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentId] = nil
local EquipmentInstance = GetPlayerEquipmentFolder(Player):FindFirstChild(EquipmentId)
if EquipmentInstance then
EquipmentInstance:Destroy()
end
return rewardData
end
-- 批量回收装备
function EquipmentProxy:RecycleEquipmentList(Player: Player, EquipmentUniqueIds: table)
local rewardData = {}
for _, EquipmentUniqueId in EquipmentUniqueIds do
local newRewardData = EquipmentProxy:RecycleEquipment(Player, EquipmentUniqueId)
if newRewardData then
Utils:TableSafeAddTableValue(rewardData, newRewardData)
end
end
return rewardData
end
-- 穿戴装备
function EquipmentProxy:WearEquipment(Player: Player, EquipmentId: number, Slot: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
-- TODO :穿戴装备时再生成模型
-- 查看槽位数量是否超出
local PlayerInfoData = PlayerInfoProxy:GetPlayerInfo(Player)
-- 没升级是没有键值对的,所以做了个括号简单判断
if Slot > (PlayerInfoData.AttributesUpgrade.wearingNumber or 1) then
RE_PlayerTip:FireClient(Player, '穿戴装备槽位超出')
return
end
-- 查看该槽位是否穿戴装备,穿戴就返回
for _, EquipmentData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do
if EquipmentData.wearing == Slot then
RE_PlayerTip:FireClient(Player, '该槽位已穿戴装备')
return
end
end
-- 穿戴装备
local EquipmentData = ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentId]
if not EquipmentData then return end
ChangeValue(Player, EquipmentId, "wearing", Slot)
-- 更新玩家数据
PlayerFightProxy:UpdatePlayerFightData(Player)
-- 给前端的提示(模型穿戴)
if Slot == 1 then
RE_WearEquipment:FireClient(Player, true, EquipmentId, Slot)
end
end
-- 卸下装备
function EquipmentProxy:UnwearEquipment(Player: Player, EquipmentId: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
-- 卸下装备
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
function EquipmentProxy:GetPlayerWearingEquipmentUniqueId(Player: Player)
local wearingEquipmentUniqueId = {}
-- 穿戴中的填入
for _, EquipmentData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do
if EquipmentData.wearing > 0 then
wearingEquipmentUniqueId[EquipmentData.wearing] = EquipmentData.id
end
end
-- 补全空缺没填进去的槽位
local wearingNumber = PlayerInfoProxy:GetPlayerAttributesUpgrade(Player, "wearingNumber")
if wearingNumber <= 0 then return wearingEquipmentUniqueId end
for i = 1, wearingNumber do
if not wearingEquipmentUniqueId[i] then wearingEquipmentUniqueId[i] = 0 end
end
return wearingEquipmentUniqueId
end
-- 获取装备属性(汇总,不进行最终属性计算)
function EquipmentProxy:GetPlayerAttributes(Player: Player)
local AttributesData = {}
for _, EquipmentData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do
if EquipmentData.wearing > 0 then
-- 增加装备基础属性
for AttributeName, AttributeValue in EquipmentData.attributes do
if AttributeName == "atkSpeed" then
if EquipmentData.wearing == 1 then
Utils:TableSafeAddValue(AttributesData, AttributeName, AttributeValue)
end
else
Utils:TableSafeAddValue(AttributesData, AttributeName, AttributeValue)
end
end
-- 增加装备额外属性
Utils:TableSafeAddTableValue(AttributesData, EquipmentData.exAttributes)
-- 增加装备元素属性
Utils:TableSafeAddTableValue(AttributesData, EquipmentData.elements)
-- 增加装备元素抗性
Utils:TableSafeAddTableValue(AttributesData, EquipmentData.elementDef)
-- print("属性表", AttributesData)
-- 计算特殊词条加成是否激活
if EquipmentData.specialType then
local isActive = false
-- 属性类型加成
if EquipmentData.specialType == 1 then
local attributeData = Utils:GetIdDataFromJson(JsonAttributes, EquipmentData.specialRequire)
-- 根据配置的id转换一下
if AttributesData[attributeData.effectAttribute] then isActive = true end
-- 技能类型加成
elseif EquipmentData.specialType == 2 then
local wearingAbilityUniqueId, wearingOrgId = AbilityProxy:GetPlayerAbilityByEquipmentUniqueId(Player, EquipmentData.id)
if table.find(wearingOrgId, EquipmentData.specialRequire) then isActive = true end
-- 晶石类型加成
elseif EquipmentData.specialType == 3 then
end
if isActive then
local newAddAttribute = Utils:GetIdDataFromJson(JsonAttributes, EquipmentData.specialActive[1])
Utils:TableSafeAddValue(AttributesData, newAddAttribute.effectAttribute, EquipmentData.specialActive[2])
end
end
end
end
-- print("结果属性表", AttributesData)
return AttributesData
end
-- 获取装备数据
function EquipmentProxy:GetEquipmentData(Player: Player, EquipmentUniqueId: number)
local EquipmentData = ArchiveProxy.pData[Player.UserId][STORE_NAME][tostring(EquipmentUniqueId)]
return EquipmentData
end
function EquipmentProxy:OnPlayerRemoving(Player: Player)
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
EquipmentProxy:WearEquipment(Player, EquipmentUniqueId, SlotId)
end
end)
RE_RecycleEquipment.OnServerEvent:Connect(function(Player: Player, EquipmentUniqueIds: table)
EquipmentProxy:RecycleEquipmentList(Player, EquipmentUniqueIds)
end)
return EquipmentProxy