This commit is contained in:
gechangfu 2025-08-21 19:29:10 +08:00
parent ed086039a1
commit 532dab80a0
21 changed files with 335 additions and 249 deletions

Binary file not shown.

View File

@ -0,0 +1,10 @@
local ServerSignalEnum = {}
ServerSignalEnum = {
BEFORE_ATTACK = "BEFORE_ATTACK",
-- AFTER_ATTACK = "AFTER_ATTACK",
-- BEFORE_KILL_MONSTER = "BEFORE_KILL_MONSTER",
BEFORE_KILL_MONSTER = "BEFORE_KILL_MONSTER",
}
return ServerSignalEnum

View File

@ -1,7 +0,0 @@
local ServerSignalEnum = {}
ServerSignalEnum = {
SHOW_ABILITY = "SHOW_ABILITY",
}
return ServerSignalEnum

View File

@ -1,230 +0,0 @@
--[[
EventFilter使用例子
演示如何使用事件过滤系统
]]
local EventFilter = require(script.Parent.EventFilter)
-- ===== 基础使用示例 =====
-- 1. 创建符文对象(作为所有者)
local function createRunes()
local fireRune = {
name = "火焰符文",
level = 5,
element = "fire"
}
local iceRune = {
name = "冰霜符文",
level = 3,
element = "ice"
}
local criticalRune = {
name = "暴击符文",
level = 4,
criticalChance = 0.3
}
-- 添加Destroy方法用于自动回收
function fireRune:Destroy()
print("销毁火焰符文")
for k, v in pairs(self) do self[k] = nil end
self = nil
end
function iceRune:Destroy()
print("销毁冰霜符文")
for k, v in pairs(self) do self[k] = nil end
self = nil
end
function criticalRune:Destroy()
print("销毁暴击符文")
for k, v in pairs(self) do self[k] = nil end
self = nil
end
return fireRune, iceRune, criticalRune
end
-- 2. 设置符文效果
local function setupRuneEffects(fireRune, iceRune, criticalRune)
-- 火焰符文增加50%伤害
EventFilter.SubscribeGlobalFilter("OnAttack", function(eventData)
print("🔥 火焰符文生效:伤害 +50%")
eventData.damage = eventData.damage * 1.5
eventData.element = "fire"
return eventData
end, 10, fireRune) -- 优先级10所有者是fireRune
-- 冰霜符文增加30%伤害,有概率冰冻
EventFilter.SubscribeGlobalFilter("OnAttack", function(eventData)
print("❄️ 冰霜符文生效:伤害 +30%")
eventData.damage = eventData.damage * 1.3
eventData.element = "ice"
-- 20%概率冰冻
if math.random() < 0.2 then
eventData.freeze = true
print(" 💎 触发冰冻效果!")
end
return eventData
end, 8, iceRune) -- 优先级8所有者是iceRune
-- 暴击符文30%概率暴击
EventFilter.SubscribeGlobalFilter("OnAttack", function(eventData)
if math.random() < 0.3 then
print("⚡ 暴击符文生效:暴击!")
eventData.damage = eventData.damage * 2
eventData.isCritical = true
end
return eventData
end, 5, criticalRune) -- 优先级5所有者是criticalRune
end
-- 3. 监听最终结果
local function setupResultListener()
EventFilter.SubscribeGlobal("OnAttack", function(finalData)
print("=== 最终攻击结果 ===")
print("伤害:", finalData.damage)
print("元素:", finalData.element or "无")
print("暴击:", finalData.isCritical and "是" or "否")
print("冰冻:", finalData.freeze and "是" or "否")
print("==================")
end)
end
-- 4. 发送攻击事件
local function sendAttackEvent()
local attackData = {
damage = 100,
attacker = "玩家",
target = "敌人"
}
print("🗡️ 发送攻击事件,基础伤害:", attackData.damage)
EventFilter.FireGlobalWithFilter("OnAttack", attackData, function(processedData)
print("✅ 攻击事件处理完成!")
-- 这里可以执行实际的攻击逻辑
-- 比如DealDamage(processedData.damage, processedData.target)
end)
end
-- ===== 演示自动回收 =====
local function demonstrateAutoCleanup()
print("\n=== 演示自动回收 ===")
-- 第一次攻击:所有符文生效
print("\n第一次攻击所有符文生效")
sendAttackEvent()
-- 销毁火焰符文
print("\n销毁火焰符文...")
fireRune:Destroy()
-- 第二次攻击:只有冰霜和暴击符文生效
print("\n第二次攻击冰霜+暴击符文生效):")
sendAttackEvent()
-- 销毁冰霜符文
print("\n销毁冰霜符文...")
iceRune:Destroy()
-- 第三次攻击:只有暴击符文生效
print("\n第三次攻击只有暴击符文生效")
sendAttackEvent()
-- 销毁暴击符文
print("\n销毁暴击符文...")
criticalRune:Destroy()
-- 第四次攻击:没有符文生效
print("\n第四次攻击没有符文生效")
sendAttackEvent()
end
-- ===== 实际游戏场景示例 =====
local function gameSceneExample()
print("\n=== 实际游戏场景示例 ===")
-- 模拟玩家攻击
local function playerAttack()
local attackData = {
damage = 80,
attackType = "melee",
attacker = game.Players.LocalPlayer,
target = nil, -- 目标敌人
weaponType = "sword"
}
print("玩家发起攻击...")
-- 发送攻击事件,让符文系统处理
EventFilter.FireGlobalWithFilter("OnAttack", attackData, function(finalData)
print("执行攻击:", finalData.damage, "点伤害")
-- 应用元素效果
if finalData.element == "fire" then
print("🔥 造成燃烧效果")
elseif finalData.element == "ice" then
print("❄️ 造成冰冻效果")
end
-- 应用暴击效果
if finalData.isCritical then
print("⚡ 暴击!")
end
-- 应用冰冻效果
if finalData.freeze then
print("💎 目标被冰冻!")
end
end)
end
-- 执行攻击
playerAttack()
end
-- ===== 主函数:完整演示 =====
local function runCompleteExample()
print("=== EventFilter使用示例 ===")
-- 1. 创建符文
local fireRune, iceRune, criticalRune = createRunes()
print("创建了三个符文")
-- 2. 设置符文效果
setupRuneEffects(fireRune, iceRune, criticalRune)
print("设置了符文效果")
-- 3. 设置结果监听
setupResultListener()
print("设置了结果监听")
-- 4. 演示自动回收
demonstrateAutoCleanup()
-- 5. 实际游戏场景
gameSceneExample()
print("\n=== 示例完成 ===")
end
-- ===== 导出函数 =====
return {
runCompleteExample = runCompleteExample,
createRunes = createRunes,
setupRuneEffects = setupRuneEffects,
sendAttackEvent = sendAttackEvent,
demonstrateAutoCleanup = demonstrateAutoCleanup,
gameSceneExample = gameSceneExample
}

View File

@ -151,6 +151,9 @@ end
-- 销毁
function Rune:OnDestroy()
self.executionRecords = nil
for _, data in self do
data = nil
end
self = nil
end

View File

@ -12,6 +12,10 @@ local DamageProxy = require(ServerStorage.Proxy.DamageProxy)
local Utils = require(ReplicatedStorage.Tools.Utils)
local Rng = require(ReplicatedStorage.Tools.Rng)
--> EventFilter
local EventFilter = require(ReplicatedStorage.Modules.EventFilter)
local EventFilterEnum = require(ReplicatedStorage.Data.EventFilterEnum)
--------------------------------------------------------------------------------
local Attack = {}
@ -123,6 +127,15 @@ function Attack:Execute()
})
end
end
-- 发送事件
EventFilter.FireGlobalWithFilter(EventFilterEnum.BEFORE_ATTACK, {
attacker = self.Character,
target = self.CheckData["ClosestCharacter"],
damageData = damageData,
}, function(processedData)
damageData = processedData.damageData
end)
DamageProxy:TakeDamage(self.Character, self.CheckData["ClosestCharacter"], damageData)
-- task.wait(atkSpeed / 2)

View File

@ -20,10 +20,6 @@ function RuneBookQualityPurple:Init(PlayerAI, Character: TypeList.Character)
end
function RuneBookQualityPurple:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneBookQualityPurple:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
@ -34,8 +30,14 @@ function RuneBookQualityPurple:OnExecute(index: number, AttributesData: table, B
local bookList = bookFolder:GetChildren()
if #bookList == 0 then return nil end
self.Data = bookList
return true
end
function RuneBookQualityPurple:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local qualityNumber = 0
for _, book in bookList do
for _, book in self.Data do
local bookQuality = book:GetAttribute("quality")
if bookQuality >= 3 then
qualityNumber = qualityNumber + 1

View File

@ -0,0 +1,51 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
--> Json
local JsonLevel = require(ReplicatedStorage.Json.Level)
local RuneBossAtk = {}
RuneBossAtk.__index = RuneBossAtk
setmetatable(RuneBossAtk, {__index = Rune})
function RuneBossAtk:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneBossAtk)
return self
end
function RuneBossAtk:Check(index: number, AttributesData: table, BehaviorNameList: table)
local LevelFolder = game.Workspace:FindFirstChild("Level")
if not LevelFolder then return nil end
local pLevelFolder = LevelFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pLevelFolder then return nil end
local pChallengeFolder = pLevelFolder:FindFirstChild("Challenge")
if not pChallengeFolder then return nil end
local pLevelId = pChallengeFolder:FindFirstChild("LevelId")
if not pLevelId then return nil end
local LevelData = Utils:GetIdDataFromJson(JsonLevel, pLevelId.Value)
if tostring(LevelData.type) ~= "2" then return nil end
return true
end
function RuneBossAtk:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local baseAttribute = AttributesData.attackRate or 100
local addAttribute = math.floor(baseAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", addAttribute)
return nil
end
return RuneBossAtk

View File

@ -0,0 +1,51 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
--> Json
local JsonLevel = require(ReplicatedStorage.Json.Level)
local RuneBossHp = {}
RuneBossHp.__index = RuneBossHp
setmetatable(RuneBossHp, {__index = Rune})
function RuneBossHp:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneBossHp)
return self
end
function RuneBossHp:Check(index: number, AttributesData: table, BehaviorNameList: table)
local LevelFolder = game.Workspace:FindFirstChild("Level")
if not LevelFolder then return nil end
local pLevelFolder = LevelFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pLevelFolder then return nil end
local pChallengeFolder = pLevelFolder:FindFirstChild("Challenge")
if not pChallengeFolder then return nil end
local pLevelId = pChallengeFolder:FindFirstChild("LevelId")
if not pLevelId then return nil end
local LevelData = Utils:GetIdDataFromJson(JsonLevel, pLevelId.Value)
if tostring(LevelData.type) ~= "2" then return nil end
return true
end
function RuneBossHp:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local baseAttribute = AttributesData.hpRate or 100
local addAttribute = math.floor(baseAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "hpRate", addAttribute)
return nil
end
return RuneBossHp

View File

@ -0,0 +1,47 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
--> EventFilter
local EventFilter = require(ReplicatedStorage.Modules.EventFilter)
local EventFilterEnum = require(ReplicatedStorage.Data.EventFilterEnum)
local RuneFirstAttack = {}
RuneFirstAttack.__index = RuneFirstAttack
setmetatable(RuneFirstAttack, {__index = Rune})
function RuneFirstAttack:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneFirstAttack)
self.FirstAttack = true
EventFilter.SubscribeGlobalFilter(EventFilterEnum.BEFORE_ATTACK, function(eventData)
if self.FirstAttack then
self.FirstAttack = false
for _, damageData in eventData.damageData do
damageData.Damage = damageData.Damage * 3
end
end
return eventData
end, 10, self)
return self
end
function RuneFirstAttack:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneFirstAttack:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
return nil
end
return RuneFirstAttack

View File

@ -0,0 +1,37 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
--> Json
local JsonLevel = require(ReplicatedStorage.Json.Level)
local RuneHpToAtk = {}
RuneHpToAtk.__index = RuneHpToAtk
setmetatable(RuneHpToAtk, {__index = Rune})
function RuneHpToAtk:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneHpToAtk)
return self
end
function RuneHpToAtk:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneHpToAtk:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local baseAttribute = AttributesData.atkRate or 100
local addAttribute = math.floor(baseAttribute * AttributesData.hp * 0.035)
Utils:TableSafeAddValue(AttributesData, "atkRate", addAttribute)
return nil
end
return RuneHpToAtk

View File

@ -0,0 +1,47 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
--> DamageProxy
local DamageProxy = require(ServerStorage.Proxy.DamageProxy)
--> EventFilter
local EventFilter = require(ReplicatedStorage.Modules.EventFilter)
local EventFilterEnum = require(ReplicatedStorage.Data.EventFilterEnum)
local RuneKillEnemyHeal = {}
RuneKillEnemyHeal.__index = RuneKillEnemyHeal
setmetatable(RuneKillEnemyHeal, {__index = Rune})
function RuneKillEnemyHeal:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneKillEnemyHeal)
self.FirstAttack = true
EventFilter.SubscribeGlobalFilter(EventFilterEnum.BEFORE_KILL_MONSTER, function(eventData)
if self.FirstAttack then
self.FirstAttack = false
DamageProxy:Heal(PlayerAI, PlayerAI, math.floor(self.Character.Config.maxhp * 0.01))
end
end, 10, self)
return self
end
function RuneKillEnemyHeal:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneKillEnemyHeal:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
return nil
end
return RuneKillEnemyHeal

View File

@ -42,7 +42,7 @@ function RuneWearElementAttack:OnExecute(index: number, AttributesData: table, B
end
end
local attackRate = math.floor(elementNumber * 25 / 100)
local attackRate = math.floor((AttributesData.attackRate or 100) * elementNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil

View File

@ -60,7 +60,7 @@ function RuneWearEmptySlot:OnExecute(index: number, AttributesData: table, Behav
end
end
local attackRate = math.floor((maxRuneNumber - hasSlotNumber) * 25 / 100)
local attackRate = math.floor((AttributesData.attackRate or 100) * (maxRuneNumber - hasSlotNumber) * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil

View File

@ -0,0 +1,52 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneWearExAttributeAttack = {}
RuneWearExAttributeAttack.__index = RuneWearExAttributeAttack
setmetatable(RuneWearExAttributeAttack, {__index = Rune})
function RuneWearExAttributeAttack:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneWearExAttributeAttack)
return self
end
function RuneWearExAttributeAttack:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneWearExAttributeAttack:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pData then return nil end
local equipmentFolder = pData:FindFirstChild("Equipment")
if not equipmentFolder then return nil end
local equipmentList = equipmentFolder:GetChildren()
if #equipmentList == 0 then return nil end
local elementNumber = 0
for _, equipment in equipmentList do
local equipmentWearing = equipment:GetAttribute("wearing")
if equipmentWearing > 0 then
elementNumber = elementNumber + #equipment:FindFirstChild("exAttributes"):GetAttributes()
end
end
local attackRate = math.floor((AttributesData.attackRate or 100) * elementNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil
end
return RuneWearExAttributeAttack

View File

@ -60,7 +60,7 @@ function RuneWearFillSlot:OnExecute(index: number, AttributesData: table, Behavi
end
end
local attackRate = math.floor(hasSlotNumber * 25 / 100)
local attackRate = math.floor((AttributesData.attackRate or 100) * hasSlotNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil

View File

@ -50,7 +50,7 @@ function RuneWearHeavySword:OnExecute(index: number, AttributesData: table, Beha
subTypeNumber = subTypeNumber + self.PlayerAI:GetSharedData(CheckShareName)
end
local attackRate = math.floor(subTypeNumber * 25 / 100)
local attackRate = math.floor((AttributesData.attackRate or 100) * subTypeNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil

View File

@ -50,7 +50,7 @@ function RuneWearKnife:OnExecute(index: number, AttributesData: table, BehaviorN
subTypeNumber = subTypeNumber + self.PlayerAI:GetSharedData(CheckShareName)
end
local attackRate = math.floor(subTypeNumber * 25 / 100)
local attackRate = math.floor((AttributesData.attackRate or 100) * subTypeNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil

View File

@ -50,7 +50,7 @@ function RuneWearStick:OnExecute(index: number, AttributesData: table, BehaviorN
subTypeNumber = subTypeNumber + self.PlayerAI:GetSharedData(CheckShareName)
end
local attackRate = math.floor(subTypeNumber * 25 / 100)
local attackRate = math.floor((AttributesData.attackRate or 100) * subTypeNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil

View File

@ -50,7 +50,7 @@ function RuneWearSword:OnExecute(index: number, AttributesData: table, BehaviorN
subTypeNumber = subTypeNumber + self.PlayerAI:GetSharedData(CheckShareName)
end
local attackRate = math.floor(subTypeNumber * 25 / 100)
local attackRate = math.floor((AttributesData.attackRate or 100) * subTypeNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil

View File

@ -15,6 +15,10 @@ local TypeList = require(ServerStorage.Base.TypeList)
--> Json
local JsonMob = require(ReplicatedStorage.Json.Enemy)
--> EventFilter
local EventFilter = require(ReplicatedStorage.Modules.EventFilter)
local EventFilterEnum = require(ReplicatedStorage.Data.EventFilterEnum)
--> Constants
--------------------------------------------------------------------------------
@ -87,6 +91,12 @@ function Mob:Died(isChallengeFailed: boolean?)
MobsProxy:RemoveMob(self.Player, self.Instance)
if not isChallengeFailed then
if self.OnDied then self.OnDied(self.Player, self) end
else
-- 发送怪物死亡事件
EventFilter.FireGlobalWithFilter(EventFilterEnum.BEFORE_KILL_MONSTER, {
attacker = self.Player,
target = self,
})
end
Character.Died(self)
end