init
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<Bindings>
|
||||
|
||||
<Binding name="PERFBOOSTENABLE" header="PERFBOOST">
|
||||
SlashCmdList.PBENABLE()
|
||||
</Binding>
|
||||
|
||||
<Binding name="PBHIDEALLPLAYERS" header="PERFBOOST">
|
||||
SlashCmdList.PBHIDEALLPLAYERS()
|
||||
</Binding>
|
||||
|
||||
|
||||
<Binding name="PBTOGGLEPLAYERRENDERIST" header="PERFBOOST">
|
||||
SlashCmdList.PBTOGGLEPLAYERRENDERIST()
|
||||
</Binding>
|
||||
|
||||
<Binding name="PBSHOWALLPLAYERS" header="PERFBOOST">
|
||||
SlashCmdList.PBSHOWALLPLAYERS()
|
||||
</Binding>
|
||||
|
||||
<Binding name="PBCYCLEPLAYERVISIBILITY" header="PERFBOOST">
|
||||
SlashCmdList.PBCYCLEPLAYERVISIBILITY()
|
||||
</Binding>
|
||||
|
||||
|
||||
</Bindings>
|
||||
@@ -0,0 +1,60 @@
|
||||
# Installation
|
||||
- Add the dll from the lastest https://gitea.com/avitasia/perf_boost/releases next to WoW.exe
|
||||
- Enable perf_boost.dll in the launcher if you use it or add perf_boost.dll to dlls.txt
|
||||
|
||||
|
||||
- Install https://gitea.com/avitasia/PerfBoostSettings like any other addon
|
||||
|
||||
# General
|
||||
- Any distance set to -1 just means it is disabled and that category won't ever be hidden.
|
||||
- Setting a distance to 0 will always hide that category
|
||||
|
||||
- If you want different settings on different characters enable `Per character settings` otherwise settings will be shared with all your characters
|
||||
- Play around with the settings to best fit your role (tanks and healers likely don't want to hide as much stuff as ranged dps)
|
||||
|
||||
- If you don't want to hide players just turning off their spell effects will still be a large performance boost
|
||||
|
||||
# 1. Setup keybinds or a macro to turn off perf boost quickly when needed
|
||||
<img width="923" height="121" alt="image" src="https://github.com/user-attachments/assets/c073185c-37f9-4992-bdcf-f1c73b1b82d8" />
|
||||
|
||||
Or can macro these commands if you prefer
|
||||
```
|
||||
/pbenable or /perfboostenable - Toggle performance boost on/off. Can be keybound also.
|
||||
/pbhideallplayers or /pbhap - Toggle hide all players on/off. Can be keybound also.
|
||||
```
|
||||
|
||||
# 2. Suggested rendering settings
|
||||
## Initial Recommended
|
||||
- Default player render distance -1 (you'll see everyone out of combat)
|
||||
- In combat player render distance - 10yd
|
||||
- In combat trash distance 60yd
|
||||
- Pet distance 0 yd
|
||||
- Totem/Guardian distance 0 yd
|
||||
- Corpse distance 0 yd
|
||||
- In cities distance 5yd
|
||||
|
||||
## Max Performance
|
||||
- Set either Default or In combat (when most people suffer fps drops) player render distance to 0 yd
|
||||
- Whitelist tanks you want to see (if any) by adding their names to Always Render Players
|
||||
- In combat trash distance 60yd
|
||||
- Pet distance 0 yd
|
||||
- Totem/Guardian distance 0 yd
|
||||
- Corpse distance 0 yd
|
||||
- In cities distance 5yd
|
||||
|
||||
# 3. Suggested spell visual settings
|
||||
## Initial Recommended
|
||||
- Defaults are fine (will just hide spells cast by hidden players)
|
||||
|
||||
## Max Performance
|
||||
- Spell visuals off
|
||||
- Ground effects off
|
||||
- Unit auras off
|
||||
- Player auras off
|
||||
|
||||
- Whitelist specific spells by adding them to Always Shown Spell Ids
|
||||
|
||||
# 4. Filter GUID Events
|
||||
`Filters out generally unnecessary superwow GUID-based events to reduce event spam and improve performance. Blocks events like UNIT_AURA, UNIT_HEALTH, UNIT_MANA when triggered with a guid instead of a string like 'player' or 'raid1', while preserving commonly used guid events like UNIT_COMBAT and UNIT_MODEL_CHANGED.`
|
||||
|
||||
If you use superwow you most likely can turn this on to reduce event spam. I think very few addons will be affected by turning this on whereas many addons are affected by the repeat event spam. If you notice something no longer happening in one of your addons just disable this setting.
|
||||
@@ -0,0 +1,23 @@
|
||||
## Interface: 11200
|
||||
## Title: Perf_boost Settings v1.7.0
|
||||
## Notes: the companion compatibility addon to the mod of the same name.
|
||||
## SavedVariablesPerCharacter: PerfBoostSettingsDB
|
||||
## X-Embeds: Ace2, FuBarPlugin-2.0, CompostLib, DewDropLib, TabletLib
|
||||
|
||||
libs\AceLibrary\AceLibrary.lua
|
||||
|
||||
libs\AceOO-2.0\AceOO-2.0.lua
|
||||
libs\AceAddon-2.0\AceAddon-2.0.lua
|
||||
libs\AceConsole-2.0\AceConsole-2.0.lua
|
||||
libs\AceHook-2.1\AceHook-2.1.lua
|
||||
libs\AceDB-2.0\AceDB-2.0.lua
|
||||
libs\AceDebug-2.0\AceDebug-2.0.lua
|
||||
libs\AceEvent-2.0\AceEvent-2.0.lua
|
||||
libs\AceLocale-2.2\AceLocale-2.2.lua
|
||||
libs\AceModuleCore-2.0\AceModuleCore-2.0.lua
|
||||
|
||||
libs\Dewdrop\Dewdrop-2.0.lua
|
||||
libs\Tablet\Tablet-2.0.lua
|
||||
libs\FuBarPlugin\FuBarPlugin-2.0.lua
|
||||
|
||||
settings.lua
|
||||
@@ -0,0 +1,85 @@
|
||||
### PerfBoost Settings
|
||||
|
||||
A configuration addon for the perf_boost.dll mod https://gitea.com/avitasia/perf_boost that provides an easy-to-use interface for adjusting performance optimization settings.
|
||||
|
||||
### [Guide for new users](GUIDE.md)
|
||||
|
||||
## Settings
|
||||
|
||||
### Master Control
|
||||
- **Enable Performance Boost** - Enable/disable all performance boost features
|
||||
|
||||
<b>You can keybind this in your keybinds — I highly recommend doing this in case you need to see hidden units in an emergency!<b>
|
||||
|
||||
### Rendering Settings
|
||||
- **Always Render Raid Marks** - Whether to always render raid marks regardless of distance/combat/etc
|
||||
- **Always Render PVP Players** - Whether to always render players flagged for PVP
|
||||
- **Always Render Players With Aggro** - Whether to always render players who have aggro from enemies
|
||||
- **Always Render Players** - Comma-separated list of player names to always render regardless of other settings
|
||||
- **Never Render Players** - Comma-separated list of player names to never render regardless of other settings
|
||||
- **Show All Players** - Show all players regardless of distance and other render settings
|
||||
- **Hide All Players** - Hide all players regardless of other render settings
|
||||
|
||||
**Priority:** Settings are applied from top to bottom - earlier settings override later ones.
|
||||
|
||||
**Note:** The addon will scan for players in your always/never render lists once per minute to cache their GUIDs. For better performance, it's recommended to clear out old names from these lists when players are no longer relevant.
|
||||
|
||||
### Player Render Distance
|
||||
- **Default Player Render Distance** - Max distance to render players when not in combat or cities (-1 to disable, 0-100 yards)
|
||||
- **In Combat Player Render Distance** - Max distance to render players when in combat (-1 to disable, 0-100 yards)
|
||||
- **In Cities Player Render Distance** - Max distance to render players when in cities (-1 to disable, 0-100 yards)
|
||||
|
||||
### Unit Render Distance
|
||||
- **Default Trash Unit Render Distance** - Max distance to render trash units (level < 63) when not in combat (-1 to disable, 0-100 yards)
|
||||
- **In Combat Trash Unit Render Distance** - Max distance to render trash units (level < 63) when in combat (-1 to disable, 0-100 yards)
|
||||
|
||||
### Pet Render Distance
|
||||
- **Default Pet Render Distance** - Max distance to render pets when not in combat (-1 to disable, 0-100 yards)
|
||||
- **In Combat Pet Render Distance** - Max distance to render pets when in combat (-1 to disable, 0-100 yards)
|
||||
|
||||
### Totem/Guardian Render Distance
|
||||
- **Default Totem/Guardian Render Distance** - Max distance to render unnamed summons when not in combat (-1 to disable, 0-100 yards)
|
||||
- **In Combat Totem/Guardian Render Distance** - Max distance to render unnamed summons when in combat (-1 to disable, 0-100 yards)
|
||||
|
||||
### Other Rendering
|
||||
- **Corpse Render Distance** - Max distance to render corpses (-1 to disable, 0-100 yards)
|
||||
|
||||
### Spell Visual Settings
|
||||
- **Show Other Player Spell Visuals** - Whether to show spell visual effects from other players (spell casts, ranged weapon projectiles, wanding, etc.)
|
||||
- **Show Other Player Ground Effects** - Whether to show ground effects from players
|
||||
- **Show Other Player Aura Visuals** - Whether to show aura visual effects on players
|
||||
- **Show Unit Aura Visuals** - Whether to show aura visual effects on units (NPCs, mobs)
|
||||
- **Hide Spells for Hidden Players** - Hide spell visuals from players that are hidden due to render distance or other settings
|
||||
- **Always Hidden Spell IDs** - Comma-separated list of spell IDs to hide visuals for (e.g., 1234,5678)
|
||||
- **Always Shown Spell IDs** - Comma-separated list of spell IDs to always show visuals for, overriding other settings
|
||||
- **Apply Hidden Spell IDs to Me** - Whether to apply the hidden spell IDs list to your own character's spells
|
||||
|
||||
### Event Filtering
|
||||
- **Filter GUID Events** - Filters out generally unnecessary superwow GUID-based events to reduce event spam and improve performance. Blocks events like UNIT_AURA, UNIT_HEALTH, UNIT_MANA when triggered with a guid instead of a string like 'player' or 'raid1', while preserving commonly used guid events like UNIT_COMBAT and UNIT_MODEL_CHANGED.
|
||||
|
||||
## Distance Priority
|
||||
|
||||
The addon will prioritize render distances in the following order:
|
||||
1. **Combat Distance** - Used when in combat (highest priority)
|
||||
2. **City Distance** - Used when in cities (for players only)
|
||||
3. **Default Distance** - Used in all other situations (lowest priority)
|
||||
|
||||
## Slash Commands
|
||||
|
||||
### General Commands
|
||||
- `/pbenable` or `/perfboostenable` - Toggle performance boost on/off. Can be keybound also.
|
||||
- `/pbshowallplayers` or `/pbsap` - Toggle show all players on/off. Can be keybound also.
|
||||
- `/pbhideallplayers` or `/pbhap` - Toggle hide all players on/off. Can be keybound also.
|
||||
- `/pbcycleplayervisibility` or `/pbcycle` - Cycle through player visibility modes: normal → show all → hide all → repeat. Can be keybound also.
|
||||
|
||||
### Player Render List Commands
|
||||
- `/pbalwaysrender` or `/pbar` - Add current target to always render list
|
||||
- `/pbalwaysrenderremove` or `/pbarr` - Remove current target from always render list
|
||||
- `/pbalwaysrenderclear` or `/pbarc` - Clear entire always render list
|
||||
- `/pbneverrender` or `/pbnr` - Add current target to never render list
|
||||
- `/pbneverrenderremove` or `/pbnrr` - Remove current target from never render list
|
||||
- `/pbneverrenderclear` or `/pbnrc` - Clear entire never render list
|
||||
|
||||
## Per-Character Settings
|
||||
|
||||
Enable "Per Character Settings" to save different configurations for each character. When enabled, settings are saved to your character's saved variables file and will override whatever is in the global Config.wtf file.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,245 @@
|
||||
--[[
|
||||
Name: AceDebug-2.0
|
||||
Revision: $Rev: 17638 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceDebug-2.0
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceDebug-2.0
|
||||
Description: Mixin to allow for simple debugging capabilities.
|
||||
Dependencies: AceLibrary, AceOO-2.0
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceDebug-2.0"
|
||||
local MINOR_VERSION = "$Revision: 17639 $"
|
||||
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
|
||||
|
||||
local DEBUGGING, TOGGLE_DEBUGGING
|
||||
|
||||
if GetLocale() == "frFR" then
|
||||
DEBUGGING = "D\195\169boguage"
|
||||
TOGGLE_DEBUGGING = "Activer/d\195\169sactiver le d\195\169boguage"
|
||||
elseif GetLocale() == "esES" then
|
||||
DEBUGGING = "Depurar"
|
||||
TOGGLE_DEBUGGING = "Activar/desactivar depurar"
|
||||
elseif GetLocale() == "deDE" then
|
||||
DEBUGGING = "Debuggen"
|
||||
TOGGLE_DEBUGGING = "Aktiviert/Deaktiviert Debugging"
|
||||
elseif GetLocale() == "koKR" then
|
||||
DEBUGGING = "디버깅"
|
||||
TOGGLE_DEBUGGING = "디버깅 기능 사용함/사용안함"
|
||||
elseif GetLocale() == "zhTW" then
|
||||
DEBUGGING = "除錯"
|
||||
TOGGLE_DEBUGGING = "啟用/停用除錯功能"
|
||||
elseif GetLocale() == "zhCN" then
|
||||
DEBUGGING = "\232\176\131\232\175\149"
|
||||
TOGGLE_DEBUGGING = "\229\144\175\231\148\168/\231\166\129\231\148\168 \232\176\131\232\175\149"
|
||||
elseif GetLocale() == "ruRU" then
|
||||
DEBUGGING = "Отладка"
|
||||
TOGGLE_DEBUGGING = "Вкл/Выкл отладку для этого аддона."
|
||||
else -- enUS
|
||||
DEBUGGING = "Debugging"
|
||||
TOGGLE_DEBUGGING = "Enable/disable debugging"
|
||||
end
|
||||
|
||||
local table_setn
|
||||
do
|
||||
local version = GetBuildInfo()
|
||||
if string.find(version, "^2%.") then
|
||||
-- 2.0.0
|
||||
table_setn = function() end
|
||||
else
|
||||
table_setn = table.setn
|
||||
end
|
||||
end
|
||||
|
||||
local math_mod = math.mod or math.fmod
|
||||
|
||||
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
|
||||
local AceDebug = AceOO.Mixin {"Debug", "CustomDebug", "IsDebugging", "SetDebugging", "SetDebugLevel", "LevelDebug", "CustomLevelDebug", "GetDebugLevel"}
|
||||
|
||||
local function print(text, r, g, b, frame, delay)
|
||||
(frame or DEFAULT_CHAT_FRAME):AddMessage(text, r, g, b, 1, delay or 5)
|
||||
end
|
||||
|
||||
local tmp
|
||||
|
||||
function AceDebug:CustomDebug(r, g, b, frame, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if not self.debugging then return end
|
||||
|
||||
local output = string.format("|cff7fff7f(DEBUG) %s:[%s%3d]|r", tostring(self), date("%H:%M:%S"), math_mod(GetTime(), 1) * 1000)
|
||||
|
||||
if string.find(tostring(a1), "%%") then
|
||||
output = output .. " " .. string.format(tostring(a1), tostring(a2), tostring(a3), tostring(a4), tostring(a5), tostring(a6), tostring(a7), tostring(a8), tostring(a9), tostring(a10), tostring(a11), tostring(a12), tostring(a13), tostring(a14), tostring(a15), tostring(a16), tostring(a17), tostring(a18), tostring(a19), tostring(a20))
|
||||
else
|
||||
if not tmp then
|
||||
tmp = {}
|
||||
end
|
||||
|
||||
-- This block dynamically rebuilds the tmp array stopping on the first nil.
|
||||
table.insert(tmp, output)
|
||||
|
||||
table.insert(tmp, tostring(a1))
|
||||
table.insert(tmp, a2)
|
||||
table.insert(tmp, a3)
|
||||
table.insert(tmp, a4)
|
||||
table.insert(tmp, a5)
|
||||
table.insert(tmp, a6)
|
||||
table.insert(tmp, a7)
|
||||
table.insert(tmp, a8)
|
||||
table.insert(tmp, a9)
|
||||
table.insert(tmp, a10)
|
||||
table.insert(tmp, a11)
|
||||
table.insert(tmp, a12)
|
||||
table.insert(tmp, a13)
|
||||
table.insert(tmp, a14)
|
||||
table.insert(tmp, a15)
|
||||
table.insert(tmp, a16)
|
||||
table.insert(tmp, a17)
|
||||
table.insert(tmp, a18)
|
||||
table.insert(tmp, a19)
|
||||
table.insert(tmp, a20)
|
||||
while tmp[table.getn(tmp)] == nil do
|
||||
table.remove(tmp)
|
||||
end
|
||||
for k = 1, table.getn(tmp) do
|
||||
tmp[k] = tostring(tmp[k])
|
||||
end
|
||||
|
||||
output = table.concat(tmp, " ")
|
||||
|
||||
for k,v in pairs(tmp) do
|
||||
tmp[k] = nil
|
||||
end
|
||||
table_setn(tmp, 0)
|
||||
end
|
||||
|
||||
print(output, r, g, b, frame or self.debugFrame, delay)
|
||||
end
|
||||
|
||||
function AceDebug:Debug(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
AceDebug.CustomDebug(self, nil, nil, nil, nil, nil, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
|
||||
function AceDebug:IsDebugging()
|
||||
return self.debugging
|
||||
end
|
||||
|
||||
function AceDebug:SetDebugging(debugging)
|
||||
self.debugging = debugging
|
||||
end
|
||||
|
||||
-- Takes a number 1-3
|
||||
-- Level 1: Critical messages that every user should receive
|
||||
-- Level 2: Should be used for local debugging (function calls, etc)
|
||||
-- Level 3: Very verbose debugging, will dump everything and anything
|
||||
-- If set to nil, you will receive no debug information
|
||||
function AceDebug:SetDebugLevel(level)
|
||||
AceDebug:argCheck(level, 1, "number", "nil")
|
||||
if not level then
|
||||
self.debuglevel = nil
|
||||
return
|
||||
end
|
||||
if level < 1 or level > 3 then
|
||||
AceDebug:error("Bad argument #1 to `SetDebugLevel`, must be a number 1-3")
|
||||
end
|
||||
self.debuglevel = level
|
||||
end
|
||||
|
||||
function AceDebug:GetDebugLevel()
|
||||
return self.debuglevel
|
||||
end
|
||||
|
||||
function AceDebug:CustomLevelDebug(level, r, g, b, frame, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if not self.debugging or not self.debuglevel then return end
|
||||
AceDebug:argCheck(level, 1, "number")
|
||||
if level < 1 or level > 3 then
|
||||
AceDebug:error("Bad argument #1 to `LevelDebug`, must be a number 1-3")
|
||||
end
|
||||
if level > self.debuglevel then return end
|
||||
|
||||
local output = string.format("|cff7fff7f(DEBUG) %s:[%s.%3d]|r", tostring(self), date("%H:%M:%S"), math_mod(GetTime(), 1) * 1000)
|
||||
|
||||
if string.find(tostring(a1), "%%") then
|
||||
output = output .. " " .. string.format(tostring(a1), tostring(a2), tostring(a3), tostring(a4), tostring(a5), tostring(a6), tostring(a7), tostring(a8), tostring(a9), tostring(a10), tostring(a11), tostring(a12), tostring(a13), tostring(a14), tostring(a15), tostring(a16), tostring(a17), tostring(a18), tostring(a19), tostring(a20))
|
||||
else
|
||||
if not tmp then
|
||||
tmp = {}
|
||||
end
|
||||
|
||||
-- This block dynamically rebuilds the tmp array stopping on the first nil.
|
||||
table.insert(tmp, output)
|
||||
|
||||
table.insert(tmp, tostring(a1))
|
||||
table.insert(tmp, a2)
|
||||
table.insert(tmp, a3)
|
||||
table.insert(tmp, a4)
|
||||
table.insert(tmp, a5)
|
||||
table.insert(tmp, a6)
|
||||
table.insert(tmp, a7)
|
||||
table.insert(tmp, a8)
|
||||
table.insert(tmp, a9)
|
||||
table.insert(tmp, a10)
|
||||
table.insert(tmp, a11)
|
||||
table.insert(tmp, a12)
|
||||
table.insert(tmp, a13)
|
||||
table.insert(tmp, a14)
|
||||
table.insert(tmp, a15)
|
||||
table.insert(tmp, a16)
|
||||
table.insert(tmp, a17)
|
||||
table.insert(tmp, a18)
|
||||
table.insert(tmp, a19)
|
||||
table.insert(tmp, a20)
|
||||
while tmp[table.getn(tmp)] == nil do
|
||||
table.remove(tmp)
|
||||
end
|
||||
for k = 1, table.getn(tmp) do
|
||||
tmp[k] = tostring(tmp[k])
|
||||
end
|
||||
|
||||
output = table.concat(tmp, " ")
|
||||
|
||||
for k,v in pairs(tmp) do
|
||||
tmp[k] = nil
|
||||
end
|
||||
table_setn(tmp, 0)
|
||||
end
|
||||
|
||||
print(output, r, g, b, frame or self.debugFrame, delay)
|
||||
end
|
||||
|
||||
function AceDebug:LevelDebug(level, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if not self.debugging or not self.debuglevel then return end
|
||||
AceDebug:argCheck(level, 1, "number")
|
||||
if level < 1 or level > 3 then
|
||||
AceDebug:error("Bad argument #1 to `LevelDebug`, must be a number 1-3")
|
||||
end
|
||||
if level > self.debuglevel then return end
|
||||
|
||||
AceDebug.CustomLevelDebug(self, level, nil, nil, nil, nil, nil, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
|
||||
|
||||
local options
|
||||
function AceDebug:GetAceOptionsDataTable(target)
|
||||
if not options then
|
||||
options = {
|
||||
debug = {
|
||||
name = DEBUGGING,
|
||||
desc = TOGGLE_DEBUGGING,
|
||||
type = "toggle",
|
||||
get = "IsDebugging",
|
||||
set = "SetDebugging",
|
||||
order = -2,
|
||||
}
|
||||
}
|
||||
end
|
||||
return options
|
||||
end
|
||||
AceLibrary:Register(AceDebug, MAJOR_VERSION, MINOR_VERSION, AceDebug.activate)
|
||||
AceDebug = AceLibrary(MAJOR_VERSION)
|
||||
@@ -0,0 +1,973 @@
|
||||
--[[
|
||||
Name: AceEvent-2.0
|
||||
Revision: $Rev: 17803 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceEvent-2.0
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
|
||||
Description: Mixin to allow for event handling, scheduling, and inter-addon
|
||||
communication.
|
||||
Dependencies: AceLibrary, AceOO-2.0
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceEvent-2.0"
|
||||
local MINOR_VERSION = "$Revision: 17803 $"
|
||||
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
|
||||
|
||||
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
|
||||
local Mixin = AceOO.Mixin
|
||||
local AceEvent = Mixin {
|
||||
"RegisterEvent",
|
||||
"RegisterAllEvents",
|
||||
"UnregisterEvent",
|
||||
"UnregisterAllEvents",
|
||||
"TriggerEvent",
|
||||
"ScheduleEvent",
|
||||
"ScheduleRepeatingEvent",
|
||||
"CancelScheduledEvent",
|
||||
"CancelAllScheduledEvents",
|
||||
"IsEventRegistered",
|
||||
"IsEventScheduled",
|
||||
"RegisterBucketEvent",
|
||||
"UnregisterBucketEvent",
|
||||
"UnregisterAllBucketEvents",
|
||||
"IsBucketEventRegistered",
|
||||
}
|
||||
|
||||
local table_setn
|
||||
do
|
||||
local version = GetBuildInfo()
|
||||
if string.find(version, "^2%.") then
|
||||
-- 2.0.0
|
||||
table_setn = function() end
|
||||
else
|
||||
table_setn = table.setn
|
||||
end
|
||||
end
|
||||
|
||||
local weakKey = {__mode="k"}
|
||||
local new, del
|
||||
do
|
||||
local list = setmetatable({}, weakKey)
|
||||
function new()
|
||||
local t = next(list)
|
||||
if t then
|
||||
list[t] = nil
|
||||
return t
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
function del(t)
|
||||
setmetatable(t, nil)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
list[t] = true
|
||||
end
|
||||
end
|
||||
|
||||
local FAKE_NIL
|
||||
local RATE
|
||||
|
||||
local eventsWhichHappenOnce = {
|
||||
PLAYER_LOGIN = true,
|
||||
AceEvent_FullyInitialized = true,
|
||||
VARIABLES_LOADED = true,
|
||||
PLAYER_LOGOUT = true,
|
||||
}
|
||||
|
||||
local registeringFromAceEvent
|
||||
function AceEvent:RegisterEvent(event, method, once)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
if self == AceEvent and not registeringFromAceEvent then
|
||||
AceEvent:argCheck(method, 3, "function")
|
||||
self = method
|
||||
else
|
||||
AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
|
||||
if type(method) == "boolean" or type(method) == "number" then
|
||||
AceEvent:argCheck(once, 4, "nil")
|
||||
once, method = method, event
|
||||
end
|
||||
end
|
||||
AceEvent:argCheck(once, 4, "number", "boolean", "nil")
|
||||
if eventsWhichHappenOnce[event] then
|
||||
once = true
|
||||
end
|
||||
local throttleRate
|
||||
if type(once) == "number" then
|
||||
throttleRate, once = once
|
||||
end
|
||||
if not method then
|
||||
method = event
|
||||
end
|
||||
if type(method) == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
|
||||
else
|
||||
assert(type(method) == "function" or type(method) == "string")
|
||||
end
|
||||
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if not AceEvent_registry[event] then
|
||||
AceEvent_registry[event] = new()
|
||||
AceEvent.frame:RegisterEvent(event)
|
||||
end
|
||||
|
||||
local remember = true
|
||||
if AceEvent_registry[event][self] then
|
||||
remember = false
|
||||
end
|
||||
AceEvent_registry[event][self] = method
|
||||
|
||||
local AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
if once then
|
||||
if not AceEvent_onceRegistry then
|
||||
AceEvent.onceRegistry = new()
|
||||
AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
end
|
||||
if not AceEvent_onceRegistry[event] then
|
||||
AceEvent_onceRegistry[event] = new()
|
||||
end
|
||||
AceEvent_onceRegistry[event][self] = true
|
||||
else
|
||||
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
|
||||
AceEvent_onceRegistry[event][self] = nil
|
||||
if not next(AceEvent_onceRegistry[event]) then
|
||||
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
if throttleRate then
|
||||
if not AceEvent_throttleRegistry then
|
||||
AceEvent.throttleRegistry = new()
|
||||
AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
end
|
||||
if not AceEvent_throttleRegistry[event] then
|
||||
AceEvent_throttleRegistry[event] = new()
|
||||
end
|
||||
if AceEvent_throttleRegistry[event][self] then
|
||||
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
|
||||
end
|
||||
AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
|
||||
local t = AceEvent_throttleRegistry[event][self]
|
||||
t[RATE] = throttleRate
|
||||
else
|
||||
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
|
||||
if AceEvent_throttleRegistry[event][self] then
|
||||
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
|
||||
end
|
||||
if not next(AceEvent_throttleRegistry[event]) then
|
||||
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if remember then
|
||||
AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
|
||||
end
|
||||
end
|
||||
|
||||
local ALL_EVENTS
|
||||
|
||||
function AceEvent:RegisterAllEvents(method)
|
||||
if self == AceEvent then
|
||||
AceEvent:argCheck(method, 1, "function")
|
||||
self = method
|
||||
else
|
||||
AceEvent:argCheck(method, 1, "string", "function")
|
||||
if type(method) == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot register all events to method %q, it does not exist", method)
|
||||
end
|
||||
end
|
||||
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if not AceEvent_registry[ALL_EVENTS] then
|
||||
AceEvent_registry[ALL_EVENTS] = new()
|
||||
AceEvent.frame:RegisterAllEvents()
|
||||
end
|
||||
|
||||
AceEvent_registry[ALL_EVENTS][self] = method
|
||||
end
|
||||
|
||||
local _G = getfenv(0)
|
||||
local memstack, timestack = {}, {}
|
||||
local memdiff, timediff
|
||||
function AceEvent:TriggerEvent(event, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
|
||||
return
|
||||
end
|
||||
local _G_event = _G.event
|
||||
_G.event = event
|
||||
local lastEvent = AceEvent.currentEvent
|
||||
AceEvent.currentEvent = event
|
||||
|
||||
local AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
local AceEvent_debugTable = AceEvent.debugTable
|
||||
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
|
||||
local tmp = new()
|
||||
for obj, method in pairs(AceEvent_onceRegistry[event]) do
|
||||
tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
|
||||
end
|
||||
local obj = next(tmp)
|
||||
while obj do
|
||||
local mem, time
|
||||
if AceEvent_debugTable then
|
||||
if not AceEvent_debugTable[event] then
|
||||
AceEvent_debugTable[event] = new()
|
||||
end
|
||||
if not AceEvent_debugTable[event][obj] then
|
||||
AceEvent_debugTable[event][obj] = new()
|
||||
AceEvent_debugTable[event][obj].mem = 0
|
||||
AceEvent_debugTable[event][obj].time = 0
|
||||
AceEvent_debugTable[event][obj].count = 0
|
||||
end
|
||||
if memdiff then
|
||||
table.insert(memstack, memdiff)
|
||||
table.insert(timestack, timediff)
|
||||
end
|
||||
memdiff, timediff = 0, 0
|
||||
mem, time = gcinfo(), GetTime()
|
||||
end
|
||||
local method = tmp[obj]
|
||||
AceEvent.UnregisterEvent(obj, event)
|
||||
if type(method) == "string" then
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
elseif method then -- function
|
||||
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
if AceEvent_debugTable then
|
||||
local dmem, dtime = memdiff, timediff
|
||||
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
|
||||
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
|
||||
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
|
||||
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
|
||||
|
||||
memdiff, timediff = table.remove(memstack), table.remove(timestack)
|
||||
if memdiff then
|
||||
memdiff = memdiff + mem + dmem
|
||||
timediff = timediff + time + dtime
|
||||
end
|
||||
end
|
||||
tmp[obj] = nil
|
||||
obj = next(tmp)
|
||||
end
|
||||
del(tmp)
|
||||
end
|
||||
|
||||
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
|
||||
if AceEvent_registry[event] then
|
||||
local tmp = new()
|
||||
for obj, method in pairs(AceEvent_registry[event]) do
|
||||
tmp[obj] = method
|
||||
end
|
||||
local obj = next(tmp)
|
||||
while obj do
|
||||
local method = tmp[obj]
|
||||
local continue = false
|
||||
if throttleTable and throttleTable[obj] then
|
||||
local a1 = a1
|
||||
if a1 == nil then
|
||||
a1 = FAKE_NIL
|
||||
end
|
||||
if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
|
||||
throttleTable[obj][a1] = GetTime()
|
||||
else
|
||||
continue = true
|
||||
end
|
||||
end
|
||||
if not continue then
|
||||
local mem, time
|
||||
if AceEvent_debugTable then
|
||||
if not AceEvent_debugTable[event] then
|
||||
AceEvent_debugTable[event] = new()
|
||||
end
|
||||
if not AceEvent_debugTable[event][obj] then
|
||||
AceEvent_debugTable[event][obj] = new()
|
||||
AceEvent_debugTable[event][obj].mem = 0
|
||||
AceEvent_debugTable[event][obj].time = 0
|
||||
AceEvent_debugTable[event][obj].count = 0
|
||||
end
|
||||
if memdiff then
|
||||
table.insert(memstack, memdiff)
|
||||
table.insert(timestack, timediff)
|
||||
end
|
||||
memdiff, timediff = 0, 0
|
||||
mem, time = gcinfo(), GetTime()
|
||||
end
|
||||
if type(method) == "string" then
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
elseif method then -- function
|
||||
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
if AceEvent_debugTable then
|
||||
local dmem, dtime = memdiff, timediff
|
||||
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
|
||||
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
|
||||
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
|
||||
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
|
||||
|
||||
memdiff, timediff = table.remove(memstack), table.remove(timestack)
|
||||
if memdiff then
|
||||
memdiff = memdiff + mem + dmem
|
||||
timediff = timediff + time + dtime
|
||||
end
|
||||
end
|
||||
end
|
||||
tmp[obj] = nil
|
||||
obj = next(tmp)
|
||||
end
|
||||
del(tmp)
|
||||
end
|
||||
if AceEvent_registry[ALL_EVENTS] then
|
||||
local tmp = new()
|
||||
for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
|
||||
tmp[obj] = method
|
||||
end
|
||||
local obj = next(tmp)
|
||||
while obj do
|
||||
local method = tmp[obj]
|
||||
local mem, time
|
||||
if AceEvent_debugTable then
|
||||
if not AceEvent_debugTable[event] then
|
||||
AceEvent_debugTable[event] = new()
|
||||
end
|
||||
if not AceEvent_debugTable[event][obj] then
|
||||
AceEvent_debugTable[event][obj] = new()
|
||||
AceEvent_debugTable[event][obj].mem = 0
|
||||
AceEvent_debugTable[event][obj].time = 0
|
||||
AceEvent_debugTable[event][obj].count = 0
|
||||
end
|
||||
if memdiff then
|
||||
table.insert(memstack, memdiff)
|
||||
table.insert(timestack, timediff)
|
||||
end
|
||||
memdiff, timediff = 0, 0
|
||||
mem, time = gcinfo(), GetTime()
|
||||
end
|
||||
if type(method) == "string" then
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
elseif method then -- function
|
||||
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
if AceEvent_debugTable then
|
||||
local dmem, dtime = memdiff, timediff
|
||||
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
|
||||
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
|
||||
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
|
||||
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
|
||||
|
||||
memdiff, timediff = table.remove(memstack), table.remove(timestack)
|
||||
if memdiff then
|
||||
memdiff = memdiff + mem + dmem
|
||||
timediff = timediff + time + dtime
|
||||
end
|
||||
end
|
||||
tmp[obj] = nil
|
||||
obj = next(tmp)
|
||||
end
|
||||
del(tmp)
|
||||
end
|
||||
_G.event = _G_event
|
||||
AceEvent.currentEvent = lastEvent
|
||||
end
|
||||
|
||||
-- local accessors
|
||||
local getn = table.getn
|
||||
local tinsert = table.insert
|
||||
local tremove = table.remove
|
||||
local floor = math.floor
|
||||
local GetTime = GetTime
|
||||
local next = next
|
||||
local pairs = pairs
|
||||
local unpack = unpack
|
||||
|
||||
local delayRegistry
|
||||
local tmp = {}
|
||||
local function OnUpdate()
|
||||
local t = GetTime()
|
||||
for k,v in pairs(delayRegistry) do
|
||||
tmp[k] = true
|
||||
end
|
||||
for k in pairs(tmp) do
|
||||
local v = delayRegistry[k]
|
||||
if v then
|
||||
local v_time = v.time
|
||||
if not v_time then
|
||||
delayRegistry[k] = del(v)
|
||||
elseif v_time <= t then
|
||||
local v_repeatDelay = v.repeatDelay
|
||||
if v_repeatDelay then
|
||||
-- use the event time, not the current time, else timing inaccuracies add up over time
|
||||
v.time = v_time + v_repeatDelay
|
||||
end
|
||||
local event = v.event
|
||||
local mem, time
|
||||
if AceEvent_debugTable then
|
||||
mem, time = gcinfo(), GetTime()
|
||||
end
|
||||
if type(event) == "function" then
|
||||
event(unpack(v))
|
||||
else
|
||||
AceEvent:TriggerEvent(event, unpack(v))
|
||||
end
|
||||
if AceEvent_debugTable then
|
||||
mem, time = gcinfo() - mem, GetTime() - time
|
||||
v.mem = v.mem + mem
|
||||
v.timeSpent = v.timeSpent + time
|
||||
v.count = v.count + 1
|
||||
end
|
||||
if not v_repeatDelay then
|
||||
local x = delayRegistry[k]
|
||||
if x and x.time == v_time then -- check if it was manually reset
|
||||
delayRegistry[k] = del(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for k in pairs(tmp) do
|
||||
tmp[k] = nil
|
||||
end
|
||||
if not next(delayRegistry) then
|
||||
AceEvent.frame:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function ScheduleEvent(self, repeating, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
local id
|
||||
if type(event) == "string" or type(event) == "table" then
|
||||
if type(event) == "table" then
|
||||
if not delayRegistry or not delayRegistry[event] then
|
||||
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
|
||||
end
|
||||
end
|
||||
if type(delay) ~= "number" then
|
||||
id, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
|
||||
AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
|
||||
AceEvent:argCheck(delay, 4, "number")
|
||||
self:CancelScheduledEvent(id)
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(event, 2, "string", "function")
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
end
|
||||
|
||||
if not delayRegistry then
|
||||
AceEvent.delayRegistry = new()
|
||||
delayRegistry = AceEvent.delayRegistry
|
||||
AceEvent.frame:SetScript("OnUpdate", OnUpdate)
|
||||
end
|
||||
local t
|
||||
if type(id) == "table" then
|
||||
for k in pairs(id) do
|
||||
id[k] = nil
|
||||
end
|
||||
t = id
|
||||
else
|
||||
t = new()
|
||||
end
|
||||
t[1] = a1
|
||||
t[2] = a2
|
||||
t[3] = a3
|
||||
t[4] = a4
|
||||
t[5] = a5
|
||||
t[6] = a6
|
||||
t[7] = a7
|
||||
t[8] = a8
|
||||
t[9] = a9
|
||||
t[10] = a10
|
||||
t[11] = a11
|
||||
t[12] = a12
|
||||
t[13] = a13
|
||||
t[14] = a14
|
||||
t[15] = a15
|
||||
t[16] = a16
|
||||
t[17] = a17
|
||||
t[18] = a18
|
||||
t[19] = a19
|
||||
t[20] = a20
|
||||
table_setn(t, 20)
|
||||
t.event = event
|
||||
t.time = GetTime() + delay
|
||||
t.self = self
|
||||
t.id = id or t
|
||||
t.repeatDelay = repeating and delay
|
||||
if AceEvent_debugTable then
|
||||
t.mem = 0
|
||||
t.count = 0
|
||||
t.timeSpent = 0
|
||||
end
|
||||
delayRegistry[t.id] = t
|
||||
AceEvent.frame:Show()
|
||||
return t.id
|
||||
end
|
||||
|
||||
function AceEvent:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if type(event) == "string" or type(event) == "table" then
|
||||
if type(event) == "table" then
|
||||
if not delayRegistry or not delayRegistry[event] then
|
||||
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
|
||||
end
|
||||
end
|
||||
if type(delay) ~= "number" then
|
||||
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
|
||||
AceEvent:argCheck(a1, 4, "number")
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(event, 2, "string", "function")
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
end
|
||||
|
||||
return ScheduleEvent(self, false, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
|
||||
function AceEvent:ScheduleRepeatingEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if type(event) == "string" or type(event) == "table" then
|
||||
if type(event) == "table" then
|
||||
if not delayRegistry or not delayRegistry[event] then
|
||||
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
|
||||
end
|
||||
end
|
||||
if type(delay) ~= "number" then
|
||||
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
|
||||
AceEvent:argCheck(a1, 4, "number")
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(event, 2, "string", "function")
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
end
|
||||
|
||||
return ScheduleEvent(self, true, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
|
||||
function AceEvent:CancelScheduledEvent(t)
|
||||
AceEvent:argCheck(t, 2, "string", "table")
|
||||
if delayRegistry then
|
||||
local v = delayRegistry[t]
|
||||
if v then
|
||||
delayRegistry[t] = del(v)
|
||||
if not next(delayRegistry) then
|
||||
AceEvent.frame:Hide()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function AceEvent:IsEventScheduled(t)
|
||||
AceEvent:argCheck(t, 2, "string", "table")
|
||||
if delayRegistry then
|
||||
local v = delayRegistry[t]
|
||||
if v then
|
||||
return true, v.time - GetTime()
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterEvent(event)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if AceEvent_registry[event] and AceEvent_registry[event][self] then
|
||||
AceEvent_registry[event][self] = nil
|
||||
local AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
|
||||
AceEvent_onceRegistry[event][self] = nil
|
||||
if not next(AceEvent_onceRegistry[event]) then
|
||||
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
|
||||
end
|
||||
end
|
||||
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
|
||||
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
|
||||
if not next(AceEvent_throttleRegistry[event]) then
|
||||
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
|
||||
end
|
||||
end
|
||||
if not next(AceEvent_registry[event]) then
|
||||
AceEvent_registry[event] = del(AceEvent_registry[event])
|
||||
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
|
||||
AceEvent.frame:UnregisterEvent(event)
|
||||
end
|
||||
end
|
||||
else
|
||||
if self == AceEvent then
|
||||
error(string.format("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0.", event), 2)
|
||||
else
|
||||
AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
|
||||
end
|
||||
end
|
||||
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterAllEvents()
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
|
||||
AceEvent_registry[ALL_EVENTS][self] = nil
|
||||
if not next(AceEvent_registry[ALL_EVENTS]) then
|
||||
del(AceEvent_registry[ALL_EVENTS])
|
||||
AceEvent.frame:UnregisterAllEvents()
|
||||
for k,v in pairs(AceEvent_registry) do
|
||||
if k ~= ALL_EVENTS then
|
||||
AceEvent.frame:RegisterEvent(k)
|
||||
end
|
||||
end
|
||||
AceEvent_registry[event] = nil
|
||||
end
|
||||
end
|
||||
local first = true
|
||||
for event, data in pairs(AceEvent_registry) do
|
||||
if first then
|
||||
if AceEvent_registry.AceEvent_EventUnregistered then
|
||||
event = "AceEvent_EventUnregistered"
|
||||
else
|
||||
first = false
|
||||
end
|
||||
end
|
||||
local x = data[self]
|
||||
data[self] = nil
|
||||
if x and event ~= ALL_EVENTS then
|
||||
if not next(data) then
|
||||
del(data)
|
||||
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
|
||||
AceEvent.frame:UnregisterEvent(event)
|
||||
end
|
||||
AceEvent_registry[event] = nil
|
||||
end
|
||||
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
|
||||
end
|
||||
if first then
|
||||
event = nil
|
||||
end
|
||||
end
|
||||
if AceEvent.onceRegistry then
|
||||
for event, data in pairs(AceEvent.onceRegistry) do
|
||||
data[self] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:CancelAllScheduledEvents()
|
||||
if delayRegistry then
|
||||
for k,v in pairs(delayRegistry) do
|
||||
if v.self == self then
|
||||
delayRegistry[k] = del(v)
|
||||
end
|
||||
end
|
||||
if not next(delayRegistry) then
|
||||
AceEvent.frame:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:IsEventRegistered(event)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if self == AceEvent then
|
||||
return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false
|
||||
end
|
||||
if AceEvent_registry[event] and AceEvent_registry[event][self] then
|
||||
return true, AceEvent_registry[event][self]
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
local bucketfunc
|
||||
function AceEvent:RegisterBucketEvent(event, delay, method)
|
||||
AceEvent:argCheck(event, 2, "string", "table")
|
||||
if type(event) == "table" then
|
||||
for k,v in pairs(event) do
|
||||
if type(k) ~= "number" then
|
||||
AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
|
||||
elseif type(v) ~= "string" then
|
||||
AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
|
||||
end
|
||||
end
|
||||
end
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
if AceEvent == self then
|
||||
AceEvent:argCheck(method, 4, "function")
|
||||
self = method
|
||||
else
|
||||
if type(event) == "string" then
|
||||
AceEvent:argCheck(method, 4, "string", "function", "nil")
|
||||
if not method then
|
||||
method = event
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(method, 4, "string", "function")
|
||||
end
|
||||
|
||||
if type(method) == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
|
||||
end
|
||||
end
|
||||
if not AceEvent.buckets then
|
||||
AceEvent.buckets = new()
|
||||
end
|
||||
if not AceEvent.buckets[event] then
|
||||
AceEvent.buckets[event] = new()
|
||||
end
|
||||
if not AceEvent.buckets[event][self] then
|
||||
AceEvent.buckets[event][self] = new()
|
||||
AceEvent.buckets[event][self].current = new()
|
||||
AceEvent.buckets[event][self].self = self
|
||||
else
|
||||
AceEvent.CancelScheduledEvent(self, AceEvent.buckets[event][self].id)
|
||||
end
|
||||
local bucket = AceEvent.buckets[event][self]
|
||||
bucket.method = method
|
||||
|
||||
local func = function(arg1)
|
||||
bucket.run = true
|
||||
if arg1 then
|
||||
bucket.current[arg1] = true
|
||||
end
|
||||
end
|
||||
AceEvent.buckets[event][self].func = func
|
||||
if type(event) == "string" then
|
||||
AceEvent.RegisterEvent(self, event, func)
|
||||
else
|
||||
for _,v in ipairs(event) do
|
||||
AceEvent.RegisterEvent(self, v, func)
|
||||
end
|
||||
end
|
||||
if not bucketfunc then
|
||||
bucketfunc = function(bucket)
|
||||
local current = bucket.current
|
||||
local method = bucket.method
|
||||
local self = bucket.self
|
||||
if bucket.run then
|
||||
if type(method) == "string" then
|
||||
self[method](self, current)
|
||||
elseif method then -- function
|
||||
method(current)
|
||||
end
|
||||
for k in pairs(current) do
|
||||
current[k] = nil
|
||||
k = nil
|
||||
end
|
||||
bucket.run = false
|
||||
end
|
||||
end
|
||||
end
|
||||
bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket)
|
||||
end
|
||||
|
||||
function AceEvent:IsBucketEventRegistered(event)
|
||||
AceEvent:argCheck(event, 2, "string", "table")
|
||||
return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterBucketEvent(event)
|
||||
AceEvent:argCheck(event, 2, "string", "table")
|
||||
if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
|
||||
AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
|
||||
end
|
||||
|
||||
local bucket = AceEvent.buckets[event][self]
|
||||
|
||||
if type(event) == "string" then
|
||||
AceEvent.UnregisterEvent(self, event)
|
||||
else
|
||||
for _,v in ipairs(event) do
|
||||
AceEvent.UnregisterEvent(self, v)
|
||||
end
|
||||
end
|
||||
AceEvent:CancelScheduledEvent(bucket.id)
|
||||
|
||||
del(bucket.current)
|
||||
AceEvent.buckets[event][self] = del(AceEvent.buckets[event][self])
|
||||
if not next(AceEvent.buckets[event]) then
|
||||
AceEvent.buckets[event] = del(AceEvent.buckets[event])
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterAllBucketEvents()
|
||||
if not AceEvent.buckets or not next(AceEvent.buckets) then
|
||||
return
|
||||
end
|
||||
for k,v in pairs(AceEvent.buckets) do
|
||||
if v == self then
|
||||
AceEvent.UnregisterBucketEvent(self, k)
|
||||
k = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:OnEmbedDisable(target)
|
||||
self.UnregisterAllEvents(target)
|
||||
|
||||
self.CancelAllScheduledEvents(target)
|
||||
|
||||
self.UnregisterAllBucketEvents(target)
|
||||
end
|
||||
|
||||
function AceEvent:EnableDebugging()
|
||||
if not self.debugTable then
|
||||
self.debugTable = new()
|
||||
|
||||
if delayRegistry then
|
||||
for k,v in pairs(self.delayRegistry) do
|
||||
if not v.mem then
|
||||
v.mem = 0
|
||||
v.count = 0
|
||||
v.timeSpent = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:IsFullyInitialized()
|
||||
return self.postInit or false
|
||||
end
|
||||
|
||||
function AceEvent:IsPostPlayerLogin()
|
||||
return self.playerLogin or false
|
||||
end
|
||||
|
||||
function AceEvent:activate(oldLib, oldDeactivate)
|
||||
AceEvent = self
|
||||
|
||||
if oldLib then
|
||||
self.onceRegistry = oldLib.onceRegistry
|
||||
self.throttleRegistry = oldLib.throttleRegistry
|
||||
self.delayRegistry = oldLib.delayRegistry
|
||||
self.buckets = oldLib.buckets
|
||||
self.registry = oldLib.registry
|
||||
self.frame = oldLib.frame
|
||||
self.debugTable = oldLib.debugTable
|
||||
self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
|
||||
self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
|
||||
self.ALL_EVENTS = oldLib.ALL_EVENTS
|
||||
self.FAKE_NIL = oldLib.FAKE_NIL
|
||||
self.RATE = oldLib.RATE
|
||||
end
|
||||
if not self.registry then
|
||||
self.registry = {}
|
||||
end
|
||||
if not self.frame then
|
||||
self.frame = CreateFrame("Frame", "AceEvent20Frame")
|
||||
end
|
||||
if not self.ALL_EVENTS then
|
||||
self.ALL_EVENTS = {}
|
||||
end
|
||||
if not self.FAKE_NIL then
|
||||
self.FAKE_NIL = {}
|
||||
end
|
||||
if not self.RATE then
|
||||
self.RATE = {}
|
||||
end
|
||||
ALL_EVENTS = self.ALL_EVENTS
|
||||
FAKE_NIL = self.FAKE_NIL
|
||||
RATE = self.RATE
|
||||
local inPlw = false
|
||||
local blacklist = {
|
||||
UNIT_INVENTORY_CHANGED = true,
|
||||
BAG_UPDATE = true,
|
||||
ITEM_LOCK_CHANGED = true,
|
||||
ACTIONBAR_SLOT_CHANGED = true,
|
||||
}
|
||||
self.frame:SetScript("OnEvent", function()
|
||||
local event = event
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
inPlw = false
|
||||
elseif event == "PLAYER_LEAVING_WORLD" then
|
||||
inPlw = true
|
||||
end
|
||||
if event and (not inPlw or not blacklist[event]) then
|
||||
self:TriggerEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
|
||||
end
|
||||
end)
|
||||
if self.delayRegistry then
|
||||
delayRegistry = self.delayRegistry
|
||||
self.frame:SetScript("OnUpdate", OnUpdate)
|
||||
end
|
||||
|
||||
self:UnregisterAllEvents()
|
||||
self:CancelAllScheduledEvents()
|
||||
|
||||
registeringFromAceEvent = true
|
||||
self:RegisterEvent("LOOT_OPENED", function()
|
||||
SendAddonMessage("LOOT_OPENED", "", "RAID")
|
||||
end)
|
||||
registeringFromAceEvent = nil
|
||||
|
||||
if not self.playerLogin then
|
||||
registeringFromAceEvent = true
|
||||
self:RegisterEvent("PLAYER_LOGIN", function()
|
||||
self.playerLogin = true
|
||||
end, true)
|
||||
registeringFromAceEvent = nil
|
||||
end
|
||||
|
||||
if not self.postInit then
|
||||
local isReload = true
|
||||
local function func()
|
||||
self.postInit = true
|
||||
self:TriggerEvent("AceEvent_FullyInitialized")
|
||||
if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
|
||||
self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
|
||||
end
|
||||
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
|
||||
self:UnregisterEvent("MEETINGSTONE_CHANGED")
|
||||
end
|
||||
if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
|
||||
self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
|
||||
end
|
||||
if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
|
||||
self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
|
||||
end
|
||||
end
|
||||
registeringFromAceEvent = true
|
||||
local f = function()
|
||||
self.playerLogin = true
|
||||
self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
|
||||
end
|
||||
self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
|
||||
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
|
||||
self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05)
|
||||
end)
|
||||
self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
|
||||
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
|
||||
registeringFromAceEvent = true
|
||||
self:UnregisterEvent("MEETINGSTONE_CHANGED")
|
||||
self:RegisterEvent("MINIMAP_ZONE_CHANGED", f, true)
|
||||
registeringFromAceEvent = nil
|
||||
end
|
||||
end)
|
||||
self:ScheduleEvent("AceEvent_FullyInitialized", func, 10)
|
||||
registeringFromAceEvent = nil
|
||||
end
|
||||
|
||||
self.super.activate(self, oldLib, oldDeactivate)
|
||||
if oldLib then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, AceEvent.activate)
|
||||
AceEvent = AceLibrary(MAJOR_VERSION)
|
||||
@@ -0,0 +1,569 @@
|
||||
--[[
|
||||
Name: AceHook-2.1
|
||||
Revision: $Rev: 17638 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceHook-2.1
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceHook-2.1
|
||||
Description: Mixin to allow for safe hooking of functions, methods, and scripts.
|
||||
Dependencies: AceLibrary, AceOO-2.0
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceHook-2.1"
|
||||
local MINOR_VERSION = "$Revision: 17638 $"
|
||||
|
||||
-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Create the library object
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
|
||||
local AceHook = AceOO.Mixin {
|
||||
"Hook",
|
||||
"HookScript",
|
||||
"SecureHook",
|
||||
"Unhook",
|
||||
"UnhookAll",
|
||||
"HookReport",
|
||||
"IsHooked",
|
||||
}
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Library Definitions
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
local protFuncs = {
|
||||
CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true,
|
||||
TurnOrActionStart = true, TurnOrActionStop = true,
|
||||
PitchUpStart = true, PitchUpStop = true,
|
||||
PitchDownStart = true, PitchDownStop = true,
|
||||
MoveBackwardStart = true, MoveBackwardStop = true,
|
||||
MoveForwardStart = true, MoveForwardStop = true,
|
||||
Jump = true, StrafeLeftStart = true,
|
||||
StrafeLeftStop = true, StrafeRightStart = true,
|
||||
StrafeRightStop = true, ToggleMouseMove = true,
|
||||
ToggleRun = true, TurnLeftStart = true,
|
||||
TurnLeftStop = true, TurnRightStart = true,
|
||||
TurnRightStop = true,
|
||||
}
|
||||
|
||||
local function issecurevariable(x)
|
||||
if protFuncs[x] then
|
||||
return 1
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local _G = getfenv(0)
|
||||
|
||||
local function hooksecurefunc(arg1, arg2, arg3)
|
||||
if type(arg1) == "string" then
|
||||
arg1, arg2, arg3 = _G, arg1, arg2
|
||||
end
|
||||
local orig = arg1[arg2]
|
||||
arg1[arg2] = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
local x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20 = orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
|
||||
arg3(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
|
||||
return x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20
|
||||
end
|
||||
end
|
||||
|
||||
local protectedScripts = {
|
||||
OnClick = true,
|
||||
}
|
||||
|
||||
|
||||
local handlers, scripts, actives, registry
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Private definitions (Not exposed)
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
local new, del
|
||||
do
|
||||
local list = setmetatable({}, {__mode = "k"})
|
||||
function new()
|
||||
local t = next(list)
|
||||
if not t then
|
||||
return {}
|
||||
end
|
||||
list[t] = nil
|
||||
return t
|
||||
end
|
||||
|
||||
function del(t)
|
||||
setmetatable(t, nil)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
list[t] = true
|
||||
end
|
||||
end
|
||||
|
||||
local function createFunctionHook(self, func, handler, orig, secure)
|
||||
if not secure then
|
||||
if type(handler) == "string" then
|
||||
-- The handler is a method, need to self it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
else
|
||||
-- secure hooks don't call the original method
|
||||
if type(handler) == "string" then
|
||||
-- The handler is a method, need to self it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function createMethodHook(self, object, method, handler, orig, secure, script)
|
||||
if script then
|
||||
if type(handler) == "string" then
|
||||
local uid
|
||||
uid = function()
|
||||
if actives[uid] then
|
||||
return self[handler](self, object)
|
||||
else
|
||||
return orig()
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function()
|
||||
if actives[uid] then
|
||||
return handler(object)
|
||||
else
|
||||
return orig()
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
elseif not secure then
|
||||
if type(handler) == "string" then
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
else
|
||||
-- secure hooks don't call the original method
|
||||
if type(handler) == "string" then
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function hookFunction(self, func, handler, secure)
|
||||
local orig = _G[func]
|
||||
|
||||
if not orig or type(orig) ~= "function" then
|
||||
AceHook:error("Attempt to hook a non-existant function %q", func)
|
||||
end
|
||||
|
||||
if not handler then
|
||||
handler = func
|
||||
end
|
||||
|
||||
if registry[self][func] then
|
||||
local uid = registry[self][func]
|
||||
|
||||
if actives[uid] then
|
||||
-- We have an active hook from this source. Don't multi-hook
|
||||
AceHook:error("%q already has an active hook from this source.", func)
|
||||
end
|
||||
|
||||
if handlers[uid] == handler then
|
||||
-- The hook is inactive, so reactivate it
|
||||
actives[uid] = true
|
||||
return
|
||||
else
|
||||
AceHook:error("There is a stale hook for %q can't hook or reactivate.", func)
|
||||
end
|
||||
end
|
||||
|
||||
if type(handler) == "string" then
|
||||
if type(self[handler]) ~= "function" then
|
||||
AceHook:error("Could not find the the handler %q when hooking function %q", handler, func)
|
||||
end
|
||||
elseif type(handler) ~= "function" then
|
||||
AceHook:error("Could not find the handler you supplied when hooking %q", func)
|
||||
end
|
||||
|
||||
local uid = createFunctionHook(self, func, handler, orig, secure)
|
||||
registry[self][func] = uid
|
||||
actives[uid] = true
|
||||
handlers[uid] = handler
|
||||
|
||||
if not secure then
|
||||
_G[func] = uid
|
||||
self.hooks[func] = orig
|
||||
else
|
||||
hooksecurefunc(func, uid)
|
||||
end
|
||||
end
|
||||
|
||||
local function unhookFunction(self, func)
|
||||
if not registry[self][func] then
|
||||
AceHook:error("Tried to unhook %q which is not currently hooked.", func)
|
||||
end
|
||||
|
||||
local uid = registry[self][func]
|
||||
|
||||
if actives[uid] then
|
||||
-- See if we own the global function
|
||||
if self.hooks[func] and _G[func] == uid then
|
||||
_G[func] = self.hooks[func]
|
||||
self.hooks[func] = nil
|
||||
registry[self][func] = nil
|
||||
handlers[uid] = nil
|
||||
scripts[uid] = nil
|
||||
actives[uid] = nil
|
||||
-- Magically all-done
|
||||
else
|
||||
actives[uid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function hookMethod(self, obj, method, handler, script, secure)
|
||||
if not handler then
|
||||
handler = method
|
||||
end
|
||||
|
||||
if not obj or type(obj) ~= "table" then
|
||||
AceHook:error("The object you supplied could not be found, or isn't a table.")
|
||||
end
|
||||
|
||||
local uid = registry[self][obj] and registry[self][obj][method]
|
||||
if uid then
|
||||
if actives[uid] then
|
||||
-- We have an active hook from this source. Don't multi-hook
|
||||
AceHook:error("%q already has an active hook from this source.", method)
|
||||
end
|
||||
|
||||
if handlers[uid] == handler then
|
||||
-- The hook is inactive, reactivate it.
|
||||
actives[uid] = true
|
||||
return
|
||||
else
|
||||
AceHook:error("There is a stale hook for %q can't hook or reactivate.", method)
|
||||
end
|
||||
end
|
||||
|
||||
if type(handler) == "string" then
|
||||
if type(self[handler]) ~= "function" then
|
||||
AceHook:error("Could not find the handler %q you supplied when hooking method %q", handler, method)
|
||||
end
|
||||
elseif type(handler) ~= "function" then
|
||||
AceHook:error("Could not find the handler you supplied when hooking method %q", method)
|
||||
end
|
||||
|
||||
local orig
|
||||
if script then
|
||||
if not obj.GetScript then
|
||||
AceHook:error("The object you supplied does not have a GetScript method.")
|
||||
end
|
||||
if not obj:HasScript(method) then
|
||||
AceHook:error("The object you supplied doesn't allow the %q method.", method)
|
||||
end
|
||||
|
||||
orig = obj:GetScript(method)
|
||||
if type(orig) ~= "function" then
|
||||
-- Sometimes there is not a original function for a script.
|
||||
orig = function() end
|
||||
end
|
||||
else
|
||||
orig = obj[method]
|
||||
end
|
||||
if not orig then
|
||||
AceHook:error("Could not find the method or script %q you are trying to hook.", method)
|
||||
end
|
||||
|
||||
if not registry[self][obj] then
|
||||
registry[self][obj] = new()
|
||||
end
|
||||
|
||||
if not self.hooks[obj] then
|
||||
self.hooks[obj] = new()
|
||||
end
|
||||
|
||||
local uid = createMethodHook(self, obj, method, handler, orig, secure, script)
|
||||
registry[self][obj][method] = uid
|
||||
actives[uid] = true
|
||||
handlers[uid] = handler
|
||||
scripts[uid] = script and true or nil
|
||||
|
||||
if script then
|
||||
obj:SetScript(method, uid)
|
||||
self.hooks[obj][method] = orig
|
||||
elseif not secure then
|
||||
obj[method] = uid
|
||||
self.hooks[obj][method] = orig
|
||||
else
|
||||
hooksecurefunc(obj, method, uid)
|
||||
end
|
||||
end
|
||||
|
||||
local function unhookMethod(self, obj, method)
|
||||
if not registry[self][obj] or not registry[self][obj][method] then
|
||||
AceHook:error("Attempt to unhook a method %q that is not currently hooked.", method)
|
||||
return
|
||||
end
|
||||
|
||||
local uid = registry[self][obj][method]
|
||||
|
||||
if actives[uid] then
|
||||
if scripts[uid] then -- If this is a script
|
||||
if obj:GetScript(method) == uid then
|
||||
-- We own the script. Revert to normal.
|
||||
obj:SetScript(method, self.hooks[obj][method])
|
||||
self.hooks[obj][method] = nil
|
||||
registry[self][obj][method] = nil
|
||||
handlers[uid] = nil
|
||||
scripts[uid] = nil
|
||||
actives[uid] = nil
|
||||
else
|
||||
actives[uid] = nil
|
||||
end
|
||||
else
|
||||
if self.hooks[obj] and self.hooks[obj][method] and obj[method] == uid then
|
||||
-- We own the method. Revert to normal.
|
||||
obj[method] = self.hooks[obj][method]
|
||||
self.hooks[obj][method] = nil
|
||||
registry[self][obj][method] = nil
|
||||
handlers[uid] = nil
|
||||
actives[uid] = nil
|
||||
else
|
||||
actives[uid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.hooks[obj] and not next(self.hooks[obj]) then
|
||||
self.hooks[obj] = del(self.hooks[obj])
|
||||
end
|
||||
if not next(registry[self][obj]) then
|
||||
registry[self][obj] = del(registry[self][obj])
|
||||
end
|
||||
end
|
||||
|
||||
-- ("function" [, handler] [, hookSecure]) or (object, "method" [, handler] [, hookSecure])
|
||||
function AceHook:Hook(object, method, handler, hookSecure)
|
||||
if type(object) == "string" then
|
||||
method, handler, hookSecure = object, method, handler
|
||||
if handler == true then
|
||||
handler, hookSecure = nil, true
|
||||
end
|
||||
if not hookSecure and issecurevariable(method) then
|
||||
AceHook:error("Attempt to hook secure function %q. Use `SecureHook' or add `true' to the argument list to override.", method)
|
||||
end
|
||||
AceHook:argCheck(handler, 3, "function", "string", "nil")
|
||||
AceHook:argCheck(hookSecure, 4, "boolean", "nil")
|
||||
hookFunction(self, method, handler, false)
|
||||
else
|
||||
if handler == true then
|
||||
handler, hookSecure = nil, true
|
||||
end
|
||||
if not hookSecure and issecurevariable(object, method) then
|
||||
AceHook:error("Attempt to hook secure method %q. Use `SecureHook' or add `true' to the argument list to override.", method)
|
||||
end
|
||||
AceHook:argCheck(object, 2, "table")
|
||||
AceHook:argCheck(method, 3, "string")
|
||||
AceHook:argCheck(handler, 4, "function", "string", "nil")
|
||||
AceHook:argCheck(hookSecure, 5, "boolean", "nil")
|
||||
hookMethod(self, object, method, handler, false, false)
|
||||
end
|
||||
end
|
||||
|
||||
-- ("function", handler) or (object, "method", handler)
|
||||
function AceHook:SecureHook(object, method, handler)
|
||||
if type(object) == "string" then
|
||||
method, handler = object, method
|
||||
AceHook:argCheck(handler, 3, "function", "string", "nil")
|
||||
hookFunction(self, method, handler, true)
|
||||
else
|
||||
AceHook:argCheck(object, 2, "table")
|
||||
AceHook:argCheck(method, 3, "string")
|
||||
AceHook:argCheck(handler, 4, "function", "string", "nil")
|
||||
hookMethod(self, object, method, handler, false, true)
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:HookScript(frame, script, handler)
|
||||
AceHook:argCheck(frame, 2, "table")
|
||||
if not frame[0] or type(frame.IsFrameType) ~= "function" then
|
||||
AceHook:error("Bad argument #2 to `HookScript'. Expected frame.")
|
||||
end
|
||||
AceHook:argCheck(script, 3, "string")
|
||||
AceHook:argCheck(handler, 4, "function", "string", "nil")
|
||||
hookMethod(self, frame, script, handler, true, false)
|
||||
end
|
||||
|
||||
-- ("function") or (object, "method")
|
||||
function AceHook:IsHooked(obj, method)
|
||||
if type(obj) == "string" then
|
||||
if registry[self][obj] and actives[registry[self][obj]] then
|
||||
return true, handlers[registry[self][obj]]
|
||||
end
|
||||
else
|
||||
AceHook:argCheck(obj, 2, "string", "table")
|
||||
AceHook:argCheck(method, 3, "string")
|
||||
if registry[self][obj] and registry[self][obj][method] and actives[registry[self][obj][method]] then
|
||||
return true, handlers[registry[self][obj][method]]
|
||||
end
|
||||
end
|
||||
|
||||
return false, nil
|
||||
end
|
||||
|
||||
-- ("function") or (object, "method")
|
||||
function AceHook:Unhook(obj, method)
|
||||
if type(obj) == "string" then
|
||||
unhookFunction(self, obj)
|
||||
else
|
||||
AceHook:argCheck(obj, 2, "string", "table")
|
||||
AceHook:argCheck(method, 3, "string")
|
||||
unhookMethod(self, obj, method)
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:UnhookAll()
|
||||
for key, value in pairs(registry[self]) do
|
||||
if type(key) == "table" then
|
||||
for method in pairs(value) do
|
||||
self:Unhook(key, method)
|
||||
end
|
||||
else
|
||||
self:Unhook(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:HookReport()
|
||||
DEFAULT_CHAT_FRAME:AddMessage("This is a list of all active hooks for this object:")
|
||||
if not next(registry[self]) then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("No hooks")
|
||||
end
|
||||
|
||||
for key, value in pairs(registry[self]) do
|
||||
if type(value) == "table" then
|
||||
for method, uid in pairs(value) do
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format("object: %s method: %q |cff%s|r%s", tostring(key), method, actives[uid] and "00ff00Active" or "ffff00Inactive", not self.hooks[key][method] and " |cff7f7fff-Secure-|r" or ""))
|
||||
end
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format("function: %q |cff%s|r%s", tostring(key), actives[value] and "00ff00Active" or "ffff00Inactive", not self.hooks[key] and " |cff7f7fff-Secure-|r" or ""))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:OnInstanceInit(object)
|
||||
if not object.hooks then
|
||||
object.hooks = new()
|
||||
end
|
||||
if not registry[object] then
|
||||
registry[object] = new()
|
||||
end
|
||||
end
|
||||
|
||||
AceHook.OnManualEmbed = AceHook.OnInstanceInit
|
||||
|
||||
function AceHook:OnEmbedDisable(target)
|
||||
self.UnhookAll(target)
|
||||
end
|
||||
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceHook = self
|
||||
|
||||
self.handlers = oldLib and oldLib.handlers or {}
|
||||
self.registry = oldLib and oldLib.registry or {}
|
||||
self.scripts = oldLib and oldLib.scripts or {}
|
||||
self.actives = oldLib and oldLib.actives or {}
|
||||
|
||||
handlers = self.handlers
|
||||
registry = self.registry
|
||||
scripts = self.scripts
|
||||
actives = self.actives
|
||||
|
||||
AceHook.super.activate(self, oldLib, oldDeactivate)
|
||||
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceHook, MAJOR_VERSION, MINOR_VERSION, activate)
|
||||
@@ -0,0 +1,757 @@
|
||||
--[[
|
||||
Name: AceLibrary
|
||||
Revision: $Rev: 17722 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Iriel (iriel@vigilance-committee.org)
|
||||
Tekkub (tekkub@gmail.com)
|
||||
Revision: $Rev: 17722 $
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceLibrary
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
|
||||
Description: Versioning library to handle other library instances, upgrading,
|
||||
and proper access.
|
||||
It also provides a base for libraries to work off of, providing
|
||||
proper error tools. It is handy because all the errors occur in the
|
||||
file that called it, not in the library file itself.
|
||||
Dependencies: None
|
||||
]]
|
||||
|
||||
local ACELIBRARY_MAJOR = "AceLibrary"
|
||||
local ACELIBRARY_MINOR = "$Revision: 17722 $"
|
||||
|
||||
if loadstring("return function(...) return ... end") and AceLibrary and AceLibrary:HasInstance(ACELIBRARY_MAJOR) then return end -- lua51 check
|
||||
local table_setn
|
||||
do
|
||||
local version = GetBuildInfo()
|
||||
if string.find(version, "^2%.") then
|
||||
-- 2.0.0
|
||||
table_setn = function() end
|
||||
else
|
||||
table_setn = table.setn
|
||||
end
|
||||
end
|
||||
|
||||
local string_gfind = string.gmatch or string.gfind
|
||||
|
||||
local _G = getfenv(0)
|
||||
local previous = _G[ACELIBRARY_MAJOR]
|
||||
if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
|
||||
|
||||
local function safecall(func,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
local success, err = pcall(func,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
if not success then geterrorhandler()(err) end
|
||||
end
|
||||
|
||||
-- @table AceLibrary
|
||||
-- @brief System to handle all versioning of libraries.
|
||||
local AceLibrary = {}
|
||||
local AceLibrary_mt = {}
|
||||
setmetatable(AceLibrary, AceLibrary_mt)
|
||||
|
||||
local tmp
|
||||
local function error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if type(self) ~= "table" then
|
||||
_G.error(string.format("Bad argument #1 to `error' (table expected, got %s)", type(self)), 2)
|
||||
end
|
||||
if not tmp then
|
||||
tmp = {}
|
||||
else
|
||||
for k in pairs(tmp) do tmp[k] = nil end
|
||||
table_setn(tmp, 0)
|
||||
end
|
||||
|
||||
table.insert(tmp, a1)
|
||||
table.insert(tmp, a2)
|
||||
table.insert(tmp, a3)
|
||||
table.insert(tmp, a4)
|
||||
table.insert(tmp, a5)
|
||||
table.insert(tmp, a6)
|
||||
table.insert(tmp, a7)
|
||||
table.insert(tmp, a8)
|
||||
table.insert(tmp, a9)
|
||||
table.insert(tmp, a10)
|
||||
table.insert(tmp, a11)
|
||||
table.insert(tmp, a12)
|
||||
table.insert(tmp, a13)
|
||||
table.insert(tmp, a14)
|
||||
table.insert(tmp, a15)
|
||||
table.insert(tmp, a16)
|
||||
table.insert(tmp, a17)
|
||||
table.insert(tmp, a18)
|
||||
table.insert(tmp, a19)
|
||||
table.insert(tmp, a20)
|
||||
|
||||
local stack = debugstack()
|
||||
if not message then
|
||||
local _,_,second = string.find(stack, "\n(.-)\n")
|
||||
message = "error raised! " .. second
|
||||
else
|
||||
for i = 1,table.getn(tmp) do
|
||||
tmp[i] = tostring(tmp[i])
|
||||
end
|
||||
for i = 1,10 do
|
||||
table.insert(tmp, "nil")
|
||||
end
|
||||
message = string.format(message, unpack(tmp))
|
||||
end
|
||||
|
||||
if getmetatable(self) and getmetatable(self).__tostring then
|
||||
message = string.format("%s: %s", tostring(self), message)
|
||||
elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
|
||||
message = string.format("%s: %s", self:GetLibraryVersion(), message)
|
||||
elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
|
||||
message = string.format("%s: %s", self.class:GetLibraryVersion(), message)
|
||||
end
|
||||
|
||||
local first = string.gsub(stack, "\n.*", "")
|
||||
local file = string.gsub(first, ".*\\(.*).lua:%d+: .*", "%1")
|
||||
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
|
||||
|
||||
local i = 0
|
||||
for s in string_gfind(stack, "\n([^\n]*)") do
|
||||
i = i + 1
|
||||
if not string.find(s, file .. "%.lua:%d+:") then
|
||||
file = string.gsub(s, "^.*\\(.*).lua:%d+: .*", "%1")
|
||||
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
|
||||
break
|
||||
end
|
||||
end
|
||||
local j = 0
|
||||
for s in string_gfind(stack, "\n([^\n]*)") do
|
||||
j = j + 1
|
||||
if j > i and not string.find(s, file .. "%.lua:%d+:") then
|
||||
_G.error(message, j + 1)
|
||||
return
|
||||
end
|
||||
end
|
||||
_G.error(message, 2)
|
||||
return
|
||||
end
|
||||
|
||||
local function assert(self, condition, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if not condition then
|
||||
if not message then
|
||||
local stack = debugstack()
|
||||
local _,_,second = string.find(stack, "\n(.-)\n")
|
||||
message = "assertion failed! " .. second
|
||||
end
|
||||
error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
return
|
||||
end
|
||||
return condition
|
||||
end
|
||||
|
||||
local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
|
||||
if type(num) ~= "number" then
|
||||
error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
|
||||
elseif type(kind) ~= "string" then
|
||||
error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
|
||||
end
|
||||
local errored = false
|
||||
arg = type(arg)
|
||||
if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
|
||||
local _,_,func = string.find(debugstack(), "`argCheck'.-([`<].-['>])")
|
||||
if not func then
|
||||
_,_,func = string.find(debugstack(), "([`<].-['>])")
|
||||
end
|
||||
if kind5 then
|
||||
error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
|
||||
elseif kind4 then
|
||||
error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
|
||||
elseif kind3 then
|
||||
error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
|
||||
elseif kind2 then
|
||||
error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
|
||||
else
|
||||
error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function pcall(self, func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = _G.pcall(func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if not a1 then
|
||||
error(self, string.gsub(a2, ".-%.lua:%d-: ", ""))
|
||||
else
|
||||
return a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
|
||||
end
|
||||
end
|
||||
|
||||
local recurse = {}
|
||||
local function addToPositions(t, major)
|
||||
if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
|
||||
rawset(t, recurse, true)
|
||||
AceLibrary.positions[t] = major
|
||||
for k,v in pairs(t) do
|
||||
if type(v) == "table" and not rawget(v, recurse) then
|
||||
addToPositions(v, major)
|
||||
end
|
||||
if type(k) == "table" and not rawget(k, recurse) then
|
||||
addToPositions(k, major)
|
||||
end
|
||||
end
|
||||
local mt = getmetatable(t)
|
||||
if mt and not rawget(mt, recurse) then
|
||||
addToPositions(mt, major)
|
||||
end
|
||||
rawset(t, recurse, nil)
|
||||
end
|
||||
end
|
||||
|
||||
local function svnRevisionToNumber(text)
|
||||
if type(text) == "string" then
|
||||
if string.find(text, "^%$Revision: (%d+) %$$") then
|
||||
return tonumber((string.gsub(text, "^%$Revision: (%d+) %$$", "%1")))
|
||||
elseif string.find(text, "^%$Rev: (%d+) %$$") then
|
||||
return tonumber((string.gsub(text, "^%$Rev: (%d+) %$$", "%1")))
|
||||
elseif string.find(text, "^%$LastChangedRevision: (%d+) %$$") then
|
||||
return tonumber((string.gsub(text, "^%$LastChangedRevision: (%d+) %$$", "%1")))
|
||||
end
|
||||
elseif type(text) == "number" then
|
||||
return text
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local crawlReplace
|
||||
do
|
||||
local recurse = {}
|
||||
local function func(t, to, from)
|
||||
if recurse[t] then
|
||||
return
|
||||
end
|
||||
recurse[t] = true
|
||||
local mt = getmetatable(t)
|
||||
setmetatable(t, nil)
|
||||
rawset(t, to, rawget(t, from))
|
||||
rawset(t, from, nil)
|
||||
for k,v in pairs(t) do
|
||||
if v == from then
|
||||
t[k] = to
|
||||
elseif type(v) == "table" then
|
||||
if not recurse[v] then
|
||||
func(v, to, from)
|
||||
end
|
||||
end
|
||||
|
||||
if type(k) == "table" then
|
||||
if not recurse[k] then
|
||||
func(k, to, from)
|
||||
end
|
||||
end
|
||||
end
|
||||
setmetatable(t, mt)
|
||||
if mt then
|
||||
if mt == from then
|
||||
setmetatable(t, to)
|
||||
elseif not recurse[mt] then
|
||||
func(mt, to, from)
|
||||
end
|
||||
end
|
||||
end
|
||||
function crawlReplace(t, to, from)
|
||||
func(t, to, from)
|
||||
for k in pairs(recurse) do
|
||||
recurse[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @function destroyTable
|
||||
-- @brief remove all the contents of a table
|
||||
-- @param t table to destroy
|
||||
local function destroyTable(t)
|
||||
setmetatable(t, nil)
|
||||
for k,v in pairs(t) do t[k] = nil end
|
||||
table_setn(t, 0)
|
||||
end
|
||||
|
||||
local function isFrame(frame)
|
||||
return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
|
||||
end
|
||||
|
||||
local new, del
|
||||
do
|
||||
local tables = setmetatable({}, {__mode = "k"})
|
||||
|
||||
function new()
|
||||
local t = next(tables)
|
||||
if t then
|
||||
tables[t] = nil
|
||||
return t
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
function del(t, depth)
|
||||
if depth and depth > 0 then
|
||||
for k,v in pairs(t) do
|
||||
if type(v) == "table" and not isFrame(v) then
|
||||
del(v, depth - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
destroyTable(t)
|
||||
tables[t] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- @function copyTable
|
||||
-- @brief Create a shallow copy of a table and return it.
|
||||
-- @param from The table to copy from
|
||||
-- @return A shallow copy of the table
|
||||
local function copyTable(from)
|
||||
local to = new()
|
||||
for k,v in pairs(from) do to[k] = v end
|
||||
table_setn(to, table.getn(from))
|
||||
setmetatable(to, getmetatable(from))
|
||||
return to
|
||||
end
|
||||
|
||||
-- @function deepTransfer
|
||||
-- @brief Fully transfer all data, keeping proper previous table
|
||||
-- backreferences stable.
|
||||
-- @param to The table with which data is to be injected into
|
||||
-- @param from The table whose data will be injected into the first
|
||||
-- @param saveFields If available, a shallow copy of the basic data is saved
|
||||
-- in here.
|
||||
-- @param list The account of table references
|
||||
-- @param list2 The current status on which tables have been traversed.
|
||||
local deepTransfer
|
||||
do
|
||||
-- @function examine
|
||||
-- @brief Take account of all the table references to be shared
|
||||
-- between the to and from tables.
|
||||
-- @param to The table with which data is to be injected into
|
||||
-- @param from The table whose data will be injected into the first
|
||||
-- @param list An account of the table references
|
||||
local function examine(to, from, list, major)
|
||||
list[from] = to
|
||||
for k,v in pairs(from) do
|
||||
if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
|
||||
if from[k] == to[k] then
|
||||
list[from[k]] = to[k]
|
||||
elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
|
||||
list[from[k]] = from[k]
|
||||
elseif not list[from[k]] then
|
||||
examine(to[k], from[k], list, major)
|
||||
end
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
function deepTransfer(to, from, saveFields, major, list, list2)
|
||||
setmetatable(to, nil)
|
||||
local createdList
|
||||
if not list then
|
||||
createdList = true
|
||||
list = new()
|
||||
list2 = new()
|
||||
examine(to, from, list, major)
|
||||
end
|
||||
list2[to] = to
|
||||
for k,v in pairs(to) do
|
||||
if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
|
||||
if saveFields then
|
||||
saveFields[k] = v
|
||||
end
|
||||
to[k] = nil
|
||||
elseif v ~= _G then
|
||||
if saveFields then
|
||||
saveFields[k] = copyTable(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
for k in pairs(from) do
|
||||
if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
|
||||
if not list2[to[k]] then
|
||||
deepTransfer(to[k], from[k], nil, major, list, list2)
|
||||
end
|
||||
to[k] = list[to[k]] or list2[to[k]]
|
||||
else
|
||||
rawset(to, k, from[k])
|
||||
end
|
||||
end
|
||||
table_setn(to, table.getn(from))
|
||||
setmetatable(to, getmetatable(from))
|
||||
local mt = getmetatable(to)
|
||||
if mt then
|
||||
if list[mt] then
|
||||
setmetatable(to, list[mt])
|
||||
elseif mt.__index and list[mt.__index] then
|
||||
mt.__index = list[mt.__index]
|
||||
end
|
||||
end
|
||||
destroyTable(from)
|
||||
if createdList then
|
||||
del(list)
|
||||
del(list2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @method TryToLoadStandalone
|
||||
-- @brief Attempt to find and load a standalone version of the requested library
|
||||
-- @param major A string representing the major version
|
||||
-- @return If library is found, return values from the call to LoadAddOn are returned
|
||||
-- If the library has been requested previously, nil is returned.
|
||||
local function TryToLoadStandalone(major)
|
||||
if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
|
||||
if AceLibrary.scannedlibs[major] then return end
|
||||
|
||||
AceLibrary.scannedlibs[major] = true
|
||||
|
||||
local name, _, _, enabled, loadable = GetAddOnInfo(major)
|
||||
if loadable then
|
||||
return LoadAddOn(name)
|
||||
end
|
||||
|
||||
for i=1,GetNumAddOns() do
|
||||
if GetAddOnMetadata(i, "X-AceLibrary-"..major) then
|
||||
local name, _, _, enabled, loadable = GetAddOnInfo(i)
|
||||
if loadable then
|
||||
return LoadAddOn(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @method IsNewVersion
|
||||
-- @brief Obtain whether the supplied version would be an upgrade to the
|
||||
-- current version. This allows for bypass code in library
|
||||
-- declaration.
|
||||
-- @param major A string representing the major version
|
||||
-- @param minor An integer or an svn revision string representing the minor version
|
||||
-- @return whether the supplied version would be newer than what is
|
||||
-- currently available.
|
||||
function AceLibrary:IsNewVersion(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
TryToLoadStandalone(major)
|
||||
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(string.format("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 3, "number")
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
return true
|
||||
end
|
||||
return data.minor < minor
|
||||
end
|
||||
|
||||
-- @method HasInstance
|
||||
-- @brief Returns whether an instance exists. This allows for optional support of a library.
|
||||
-- @param major A string representing the major version.
|
||||
-- @param minor (optional) An integer or an svn revision string representing the minor version.
|
||||
-- @return Whether an instance exists.
|
||||
function AceLibrary:HasInstance(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
TryToLoadStandalone(major)
|
||||
|
||||
if minor then
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(string.format("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 3, "number")
|
||||
if not self.libs[major] then
|
||||
return
|
||||
end
|
||||
return self.libs[major].minor == minor
|
||||
end
|
||||
return self.libs[major] and true
|
||||
end
|
||||
|
||||
-- @method GetInstance
|
||||
-- @brief Returns the library with the given major/minor version.
|
||||
-- @param major A string representing the major version.
|
||||
-- @param minor (optional) An integer or an svn revision string representing the minor version.
|
||||
-- @return The library with the given major/minor version.
|
||||
function AceLibrary:GetInstance(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
TryToLoadStandalone(major)
|
||||
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
_G.error(string.format("Cannot find a library instance of %s.", major), 2)
|
||||
return
|
||||
end
|
||||
if minor then
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(string.format("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 2, "number")
|
||||
if data.minor ~= minor then
|
||||
_G.error(string.format("Cannot find a library instance of %s, minor version %d.", major, minor), 2)
|
||||
return
|
||||
end
|
||||
end
|
||||
return data.instance
|
||||
end
|
||||
|
||||
-- Syntax sugar. AceLibrary("FooBar-1.0")
|
||||
AceLibrary_mt.__call = AceLibrary.GetInstance
|
||||
|
||||
local donothing
|
||||
|
||||
local AceEvent
|
||||
|
||||
-- @method Register
|
||||
-- @brief Registers a new version of a given library.
|
||||
-- @param newInstance the library to register
|
||||
-- @param major the major version of the library
|
||||
-- @param minor the minor version of the library
|
||||
-- @param activateFunc (optional) A function to be called when the library is
|
||||
-- fully activated. Takes the arguments
|
||||
-- (newInstance [, oldInstance, oldDeactivateFunc]). If
|
||||
-- oldInstance is given, you should probably call
|
||||
-- oldDeactivateFunc(oldInstance).
|
||||
-- @param deactivateFunc (optional) A function to be called by a newer library's
|
||||
-- activateFunc.
|
||||
-- @param externalFunc (optional) A function to be called whenever a new
|
||||
-- library is registered.
|
||||
function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
|
||||
argCheck(self, newInstance, 2, "table")
|
||||
argCheck(self, major, 3, "string")
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(string.format("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 4, "number")
|
||||
if math.floor(minor) ~= minor or minor < 0 then
|
||||
error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
|
||||
end
|
||||
argCheck(self, activateFunc, 5, "function", "nil")
|
||||
argCheck(self, deactivateFunc, 6, "function", "nil")
|
||||
argCheck(self, externalFunc, 7, "function", "nil")
|
||||
if not deactivateFunc then
|
||||
if not donothing then
|
||||
donothing = function() end
|
||||
end
|
||||
deactivateFunc = donothing
|
||||
end
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
-- This is new
|
||||
local instance = copyTable(newInstance)
|
||||
crawlReplace(instance, instance, newInstance)
|
||||
destroyTable(newInstance)
|
||||
if AceLibrary == newInstance then
|
||||
self = instance
|
||||
AceLibrary = instance
|
||||
end
|
||||
self.libs[major] = {
|
||||
instance = instance,
|
||||
minor = minor,
|
||||
deactivateFunc = deactivateFunc,
|
||||
externalFunc = externalFunc,
|
||||
}
|
||||
rawset(instance, 'GetLibraryVersion', function(self)
|
||||
return major, minor
|
||||
end)
|
||||
if not rawget(instance, 'error') then
|
||||
rawset(instance, 'error', error)
|
||||
end
|
||||
if not rawget(instance, 'assert') then
|
||||
rawset(instance, 'assert', assert)
|
||||
end
|
||||
if not rawget(instance, 'argCheck') then
|
||||
rawset(instance, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(instance, 'pcall') then
|
||||
rawset(instance, 'pcall', pcall)
|
||||
end
|
||||
addToPositions(instance, major)
|
||||
if activateFunc then
|
||||
safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil
|
||||
end
|
||||
|
||||
if externalFunc then
|
||||
for k,data in pairs(self.libs) do
|
||||
if k ~= major then
|
||||
safecall(externalFunc, instance, k, data.instance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k,data in pairs(self.libs) do
|
||||
if k ~= major and data.externalFunc then
|
||||
safecall(data.externalFunc, data.instance, major, instance)
|
||||
end
|
||||
end
|
||||
if major == "AceEvent-2.0" then
|
||||
AceEvent = instance
|
||||
end
|
||||
if AceEvent then
|
||||
AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
local instance = data.instance
|
||||
if minor <= data.minor then
|
||||
-- This one is already obsolete, raise an error.
|
||||
_G.error(string.format("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end", major, data.minor, minor, major, minor), 2)
|
||||
return
|
||||
end
|
||||
-- This is an update
|
||||
local oldInstance = new()
|
||||
|
||||
addToPositions(newInstance, major)
|
||||
local isAceLibrary = (AceLibrary == newInstance)
|
||||
local old_error, old_assert, old_argCheck, old_pcall
|
||||
if isAceLibrary then
|
||||
self = instance
|
||||
AceLibrary = instance
|
||||
|
||||
old_error = instance.error
|
||||
old_assert = instance.assert
|
||||
old_argCheck = instance.argCheck
|
||||
old_pcall = instance.pcall
|
||||
|
||||
self.error = error
|
||||
self.assert = assert
|
||||
self.argCheck = argCheck
|
||||
self.pcall = pcall
|
||||
end
|
||||
deepTransfer(instance, newInstance, oldInstance, major)
|
||||
crawlReplace(instance, instance, newInstance)
|
||||
local oldDeactivateFunc = data.deactivateFunc
|
||||
data.minor = minor
|
||||
data.deactivateFunc = deactivateFunc
|
||||
data.externalFunc = externalFunc
|
||||
rawset(instance, 'GetLibraryVersion', function(self)
|
||||
return major, minor
|
||||
end)
|
||||
if not rawget(instance, 'error') then
|
||||
rawset(instance, 'error', error)
|
||||
end
|
||||
if not rawget(instance, 'assert') then
|
||||
rawset(instance, 'assert', assert)
|
||||
end
|
||||
if not rawget(instance, 'argCheck') then
|
||||
rawset(instance, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(instance, 'pcall') then
|
||||
rawset(instance, 'pcall', pcall)
|
||||
end
|
||||
if isAceLibrary then
|
||||
for _,v in pairs(self.libs) do
|
||||
local i = type(v) == "table" and v.instance
|
||||
if type(i) == "table" then
|
||||
if not rawget(i, 'error') or i.error == old_error then
|
||||
rawset(i, 'error', error)
|
||||
end
|
||||
if not rawget(i, 'assert') or i.assert == old_assert then
|
||||
rawset(i, 'assert', assert)
|
||||
end
|
||||
if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
|
||||
rawset(i, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(i, 'pcall') or i.pcall == old_pcall then
|
||||
rawset(i, 'pcall', pcall)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if activateFunc then
|
||||
safecall(activateFunc, instance, oldInstance, oldDeactivateFunc)
|
||||
else
|
||||
safecall(oldDeactivateFunc, oldInstance)
|
||||
end
|
||||
del(oldInstance)
|
||||
|
||||
if externalFunc then
|
||||
for k,data in pairs(self.libs) do
|
||||
if k ~= major then
|
||||
safecall(externalFunc, instance, k, data.instance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
local iter
|
||||
function AceLibrary:IterateLibraries()
|
||||
if not iter then
|
||||
local function iter(t, k)
|
||||
k = next(t, k)
|
||||
if not k then
|
||||
return nil
|
||||
else
|
||||
return k, t[k].instance
|
||||
end
|
||||
end
|
||||
end
|
||||
return iter, self.libs, nil
|
||||
end
|
||||
|
||||
-- @function Activate
|
||||
-- @brief The activateFunc for AceLibrary itself. Called when
|
||||
-- AceLibrary properly registers.
|
||||
-- @param self Reference to AceLibrary
|
||||
-- @param oldLib (optional) Reference to an old version of AceLibrary
|
||||
-- @param oldDeactivate (optional) Function to deactivate the old lib
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
if not self.libs then
|
||||
if oldLib then
|
||||
self.libs = oldLib.libs
|
||||
self.scannedlibs = oldLib.scannedlibs
|
||||
end
|
||||
if not self.libs then
|
||||
self.libs = {}
|
||||
end
|
||||
if not self.scannedlibs then
|
||||
self.scannedlibs = {}
|
||||
end
|
||||
end
|
||||
if not self.positions then
|
||||
if oldLib then
|
||||
self.positions = oldLib.positions
|
||||
end
|
||||
if not self.positions then
|
||||
self.positions = setmetatable({}, { __mode = "k" })
|
||||
end
|
||||
end
|
||||
|
||||
-- Expose the library in the global environment
|
||||
_G[ACELIBRARY_MAJOR] = self
|
||||
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
if not previous then
|
||||
previous = AceLibrary
|
||||
end
|
||||
if not previous.libs then
|
||||
previous.libs = {}
|
||||
end
|
||||
AceLibrary.libs = previous.libs
|
||||
if not previous.positions then
|
||||
previous.positions = setmetatable({}, { __mode = "k" })
|
||||
end
|
||||
AceLibrary.positions = previous.positions
|
||||
AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate)
|
||||
@@ -0,0 +1,538 @@
|
||||
--[[
|
||||
Name: AceLocale-2.2
|
||||
Revision: $Rev: 17638 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceLocale-2.2
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.2
|
||||
Description: Localization library for addons to use to handle proper
|
||||
localization and internationalization.
|
||||
Dependencies: AceLibrary
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceLocale-2.2"
|
||||
local MINOR_VERSION = "$Revision: 17639 $"
|
||||
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
|
||||
local AceLocale = {}
|
||||
|
||||
local DEFAULT_LOCALE = "enUS"
|
||||
local _G = getfenv(0)
|
||||
|
||||
local BASE_TRANSLATIONS, DEBUGGING, TRANSLATIONS, BASE_LOCALE, TRANSLATION_TABLES, REVERSE_TRANSLATIONS, STRICTNESS, DYNAMIC_LOCALES, CURRENT_LOCALE, NAME
|
||||
|
||||
local rawget = rawget
|
||||
local rawset = rawset
|
||||
local type = type
|
||||
|
||||
local newRegistries = {}
|
||||
local scheduleClear
|
||||
|
||||
local lastSelf
|
||||
local __index = function(self, key)
|
||||
lastSelf = self
|
||||
local value = (rawget(self, TRANSLATIONS) or AceLocale.prototype)[key]
|
||||
rawset(self, key, value)
|
||||
return value
|
||||
end
|
||||
|
||||
local __newindex = function(self, k, v)
|
||||
if type(v) ~= "function" and type(k) ~= "table" then
|
||||
AceLocale.error(self, "Cannot change the values of an AceLocale instance.")
|
||||
end
|
||||
rawset(self, k, v)
|
||||
end
|
||||
|
||||
local __tostring = function(self)
|
||||
if type(rawget(self, 'GetLibraryVersion')) == "function" then
|
||||
return self:GetLibraryVersion()
|
||||
else
|
||||
return "AceLocale(" .. self[NAME] .. ")"
|
||||
end
|
||||
end
|
||||
|
||||
local function clearCache(self)
|
||||
if not rawget(self, BASE_TRANSLATIONS) then
|
||||
return
|
||||
end
|
||||
|
||||
local cache = self[BASE_TRANSLATIONS]
|
||||
rawset(self, REVERSE_TRANSLATIONS, nil)
|
||||
|
||||
for k in pairs(self) do
|
||||
if rawget(cache, k) ~= nil then
|
||||
self[k] = nil
|
||||
end
|
||||
end
|
||||
rawset(self, 'tmp', true)
|
||||
self.tmp = nil
|
||||
end
|
||||
|
||||
local function refixInstance(instance)
|
||||
if getmetatable(instance) then
|
||||
setmetatable(instance, nil)
|
||||
end
|
||||
local translations = instance[TRANSLATIONS]
|
||||
if translations then
|
||||
if getmetatable(translations) then
|
||||
setmetatable(translations, nil)
|
||||
end
|
||||
local baseTranslations = instance[BASE_TRANSLATIONS]
|
||||
if getmetatable(baseTranslations) then
|
||||
setmetatable(baseTranslations, nil)
|
||||
end
|
||||
if translations == baseTranslations or instance[STRICTNESS] then
|
||||
setmetatable(instance, {
|
||||
__index = __index,
|
||||
__newindex = __newindex,
|
||||
__tostring = __tostring
|
||||
})
|
||||
|
||||
setmetatable(translations, {
|
||||
__index = AceLocale.prototype
|
||||
})
|
||||
else
|
||||
setmetatable(instance, {
|
||||
__index = __index,
|
||||
__newindex = __newindex,
|
||||
__tostring = __tostring
|
||||
})
|
||||
|
||||
setmetatable(translations, {
|
||||
__index = baseTranslations,
|
||||
})
|
||||
|
||||
setmetatable(baseTranslations, {
|
||||
__index = AceLocale.prototype,
|
||||
})
|
||||
end
|
||||
else
|
||||
setmetatable(instance, {
|
||||
__index = __index,
|
||||
__newindex = __newindex,
|
||||
__tostring = __tostring,
|
||||
})
|
||||
end
|
||||
clearCache(instance)
|
||||
newRegistries[instance] = true
|
||||
scheduleClear()
|
||||
return instance
|
||||
end
|
||||
|
||||
function AceLocale:new(name)
|
||||
self:argCheck(name, 2, "string")
|
||||
|
||||
if self.registry[name] and type(rawget(self.registry[name], 'GetLibraryVersion')) ~= "function" then
|
||||
return self.registry[name]
|
||||
end
|
||||
|
||||
AceLocale.registry[name] = refixInstance({
|
||||
[STRICTNESS] = false,
|
||||
[NAME] = name,
|
||||
})
|
||||
newRegistries[AceLocale.registry[name]] = true
|
||||
return AceLocale.registry[name]
|
||||
end
|
||||
|
||||
AceLocale.prototype = { class = AceLocale }
|
||||
|
||||
function AceLocale.prototype:EnableDebugging()
|
||||
if rawget(self, BASE_TRANSLATIONS) then
|
||||
AceLocale.error(self, "Cannot enable debugging after a translation has been registered.")
|
||||
end
|
||||
rawset(self, DEBUGGING, true)
|
||||
end
|
||||
|
||||
function AceLocale.prototype:EnableDynamicLocales(override)
|
||||
AceLocale.argCheck(self, override, 2, "boolean", "nil")
|
||||
if not override and rawget(self, BASE_TRANSLATIONS) then
|
||||
AceLocale.error(self, "Cannot enable dynamic locales after a translation has been registered.")
|
||||
end
|
||||
if not rawget(self, DYNAMIC_LOCALES) then
|
||||
rawset(self, DYNAMIC_LOCALES, true)
|
||||
if rawget(self, BASE_LOCALE) then
|
||||
if not rawget(self, TRANSLATION_TABLES) then
|
||||
rawset(self, TRANSLATION_TABLES, {})
|
||||
end
|
||||
self[TRANSLATION_TABLES][self[BASE_LOCALE]] = self[BASE_TRANSLATIONS]
|
||||
self[TRANSLATION_TABLES][self[CURRENT_LOCALE]] = self[TRANSLATIONS]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceLocale.prototype:RegisterTranslations(locale, func)
|
||||
AceLocale.argCheck(self, locale, 2, "string")
|
||||
AceLocale.argCheck(self, func, 3, "function")
|
||||
|
||||
if locale == rawget(self, BASE_LOCALE) then
|
||||
AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale)
|
||||
end
|
||||
|
||||
if rawget(self, BASE_TRANSLATIONS) and GetLocale() ~= locale then
|
||||
if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then
|
||||
if not rawget(self, TRANSLATION_TABLES) then
|
||||
rawset(self, TRANSLATION_TABLES, {})
|
||||
end
|
||||
if self[TRANSLATION_TABLES][locale] then
|
||||
AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale)
|
||||
end
|
||||
local t = func()
|
||||
func = nil
|
||||
if type(t) ~= "table" then
|
||||
AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
|
||||
end
|
||||
self[TRANSLATION_TABLES][locale] = t
|
||||
t = nil
|
||||
end
|
||||
func = nil
|
||||
return
|
||||
end
|
||||
local t = func()
|
||||
func = nil
|
||||
if type(t) ~= "table" then
|
||||
AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
|
||||
end
|
||||
|
||||
rawset(self, TRANSLATIONS, t)
|
||||
if not rawget(self, BASE_TRANSLATIONS) then
|
||||
rawset(self, BASE_TRANSLATIONS, t)
|
||||
rawset(self, BASE_LOCALE, locale)
|
||||
for key,value in pairs(t) do
|
||||
if value == true then
|
||||
t[key] = key
|
||||
end
|
||||
end
|
||||
else
|
||||
for key, value in pairs(self[TRANSLATIONS]) do
|
||||
if not rawget(self[BASE_TRANSLATIONS], key) then
|
||||
AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale)
|
||||
end
|
||||
if value == true then
|
||||
AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", rawget(self, BASE_LOCALE), locale)
|
||||
end
|
||||
end
|
||||
end
|
||||
rawset(self, CURRENT_LOCALE, locale)
|
||||
refixInstance(self)
|
||||
if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then
|
||||
if not rawget(self, TRANSLATION_TABLES) then
|
||||
rawset(self, TRANSLATION_TABLES, {})
|
||||
end
|
||||
self[TRANSLATION_TABLES][locale] = t
|
||||
end
|
||||
t = nil
|
||||
end
|
||||
|
||||
function AceLocale.prototype:SetLocale(locale)
|
||||
AceLocale.argCheck(self, locale, 2, "string", "boolean")
|
||||
if not rawget(self, DYNAMIC_LOCALES) then
|
||||
AceLocale.error(self, "Cannot call `SetLocale' without first calling `EnableDynamicLocales'.")
|
||||
end
|
||||
if not rawget(self, TRANSLATION_TABLES) then
|
||||
AceLocale.error(self, "Cannot call `SetLocale' without first calling `RegisterTranslations'.")
|
||||
end
|
||||
if locale == true then
|
||||
locale = GetLocale()
|
||||
if not self[TRANSLATION_TABLES][locale] then
|
||||
locale = self[BASE_LOCALE]
|
||||
end
|
||||
end
|
||||
|
||||
if self[CURRENT_LOCALE] == locale then
|
||||
return
|
||||
end
|
||||
|
||||
if not self[TRANSLATION_TABLES][locale] then
|
||||
AceLocale.error(self, "Locale %q not registered.", locale)
|
||||
end
|
||||
|
||||
self[TRANSLATIONS] = self[TRANSLATION_TABLES][locale]
|
||||
self[CURRENT_LOCALE] = locale
|
||||
refixInstance(self)
|
||||
end
|
||||
|
||||
function AceLocale.prototype:GetLocale()
|
||||
if not rawget(self, TRANSLATION_TABLES) then
|
||||
AceLocale.error(self, "Cannot call `GetLocale' without first calling `RegisterTranslations'.")
|
||||
end
|
||||
return self[CURRENT_LOCALE]
|
||||
end
|
||||
|
||||
local function iter(t, position)
|
||||
return (next(t, position))
|
||||
end
|
||||
|
||||
function AceLocale.prototype:IterateAvailableLocales()
|
||||
if not rawget(self, DYNAMIC_LOCALES) then
|
||||
AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `EnableDynamicLocales'.")
|
||||
end
|
||||
if not rawget(self, TRANSLATION_TABLES) then
|
||||
AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `RegisterTranslations'.")
|
||||
end
|
||||
return iter, self[TRANSLATION_TABLES], nil
|
||||
end
|
||||
|
||||
function AceLocale.prototype:HasLocale(locale)
|
||||
if not rawget(self, DYNAMIC_LOCALES) then
|
||||
AceLocale.error(self, "Cannot call `HasLocale' without first calling `EnableDynamicLocales'.")
|
||||
end
|
||||
AceLocale.argCheck(self, locale, 2, "string")
|
||||
return rawget(self, TRANSLATION_TABLES) and self[TRANSLATION_TABLES][locale] ~= nil
|
||||
end
|
||||
|
||||
function AceLocale.prototype:SetStrictness(strict)
|
||||
AceLocale.argCheck(self, strict, 2, "boolean")
|
||||
local mt = getmetatable(self)
|
||||
if not mt then
|
||||
AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.")
|
||||
end
|
||||
if not rawget(self, TRANSLATIONS) then
|
||||
AceLocale.error(self, "No translations registered.")
|
||||
end
|
||||
rawset(self, STRICTNESS, strict)
|
||||
refixInstance(self)
|
||||
end
|
||||
|
||||
local function initReverse(self)
|
||||
rawset(self, REVERSE_TRANSLATIONS, {})
|
||||
local alpha = self[TRANSLATIONS]
|
||||
local bravo = self[REVERSE_TRANSLATIONS]
|
||||
for base, localized in pairs(alpha) do
|
||||
bravo[localized] = base
|
||||
end
|
||||
end
|
||||
|
||||
function AceLocale.prototype:GetTranslation(text)
|
||||
AceLocale.argCheck(self, text, 1, "string", "number")
|
||||
if not rawget(self, TRANSLATIONS) then
|
||||
AceLocale.error(self, "No translations registered")
|
||||
end
|
||||
return self[text]
|
||||
end
|
||||
|
||||
function AceLocale.prototype:GetStrictTranslation(text)
|
||||
AceLocale.argCheck(self, text, 1, "string", "number")
|
||||
local x = rawget(self, TRANSLATIONS)
|
||||
if not x then
|
||||
AceLocale.error(self, "No translations registered")
|
||||
end
|
||||
local value = rawget(x, text)
|
||||
if value == nil then
|
||||
AceLocale.error(self, "Translation %q does not exist for locale %s", text, self[CURRENT_LOCALE])
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
function AceLocale.prototype:GetReverseTranslation(text)
|
||||
local x = rawget(self, REVERSE_TRANSLATIONS)
|
||||
if not x then
|
||||
if not rawget(self, TRANSLATIONS) then
|
||||
AceLocale.error(self, "No translations registered")
|
||||
end
|
||||
initReverse(self)
|
||||
x = self[REVERSE_TRANSLATIONS]
|
||||
end
|
||||
local translation = x[text]
|
||||
if not translation then
|
||||
AceLocale.error(self, "Reverse translation for %q does not exist", text)
|
||||
end
|
||||
return translation
|
||||
end
|
||||
|
||||
function AceLocale.prototype:GetIterator()
|
||||
local x = rawget(self, TRANSLATIONS)
|
||||
if not x then
|
||||
AceLocale.error(self, "No translations registered")
|
||||
end
|
||||
return next, x, nil
|
||||
end
|
||||
|
||||
function AceLocale.prototype:GetReverseIterator()
|
||||
local x = rawget(self, REVERSE_TRANSLATIONS)
|
||||
if not x then
|
||||
if not rawget(self, TRANSLATIONS) then
|
||||
AceLocale.error(self, "No translations registered")
|
||||
end
|
||||
initReverse(self)
|
||||
x = self[REVERSE_TRANSLATIONS]
|
||||
end
|
||||
return next, x, nil
|
||||
end
|
||||
|
||||
function AceLocale.prototype:HasTranslation(text)
|
||||
AceLocale.argCheck(self, text, 1, "string", "number")
|
||||
local x = rawget(self, TRANSLATIONS)
|
||||
if not x then
|
||||
AceLocale.error(self, "No translations registered")
|
||||
end
|
||||
return rawget(x, text) and true
|
||||
end
|
||||
|
||||
function AceLocale.prototype:HasReverseTranslation(text)
|
||||
local x = rawget(self, REVERSE_TRANSLATIONS)
|
||||
if not x then
|
||||
if not rawget(self, TRANSLATIONS) then
|
||||
AceLocale.error(self, "No translations registered")
|
||||
end
|
||||
initReverse(self)
|
||||
x = self[REVERSE_TRANSLATIONS]
|
||||
end
|
||||
return x[text] and true
|
||||
end
|
||||
|
||||
function AceLocale.prototype:Debug()
|
||||
if not rawget(self, DEBUGGING) then
|
||||
return
|
||||
end
|
||||
local words = {}
|
||||
local locales = {"enUS", "ruRU", "deDE", "frFR", "koKR", "zhCN", "zhTW", "esES"}
|
||||
local localizations = {}
|
||||
DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---")
|
||||
for _,locale in ipairs(locales) do
|
||||
if not self[TRANSLATION_TABLES][locale] then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q not found", locale))
|
||||
else
|
||||
localizations[locale] = self[TRANSLATION_TABLES][locale]
|
||||
end
|
||||
end
|
||||
local localeDebug = {}
|
||||
for locale, localization in pairs(localizations) do
|
||||
localeDebug[locale] = {}
|
||||
for word in pairs(localization) do
|
||||
if type(localization[word]) == "table" then
|
||||
if type(words[word]) ~= "table" then
|
||||
words[word] = {}
|
||||
end
|
||||
for bit in pairs(localization[word]) do
|
||||
if type(localization[word][bit]) == "string" then
|
||||
words[word][bit] = true
|
||||
end
|
||||
end
|
||||
elseif type(localization[word]) == "string" then
|
||||
words[word] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
for word in pairs(words) do
|
||||
if type(words[word]) == "table" then
|
||||
for bit in pairs(words[word]) do
|
||||
for locale, localization in pairs(localizations) do
|
||||
if not rawget(localization, word) or not localization[word][bit] then
|
||||
localeDebug[locale][word .. "::" .. bit] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
for locale, localization in pairs(localizations) do
|
||||
if not rawget(localization, word) then
|
||||
localeDebug[locale][word] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for locale, t in pairs(localeDebug) do
|
||||
if not next(t) then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q complete", locale))
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q missing:", locale))
|
||||
for word in pairs(t) do
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format(" %q", word))
|
||||
end
|
||||
end
|
||||
end
|
||||
DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---")
|
||||
end
|
||||
|
||||
setmetatable(AceLocale.prototype, {
|
||||
__index = function(self, k)
|
||||
if type(k) ~= "table" and k ~= 0 and k ~= "GetLibraryVersion" and k ~= "error" and k ~= "assert" and k ~= "argCheck" and k ~= "pcall" then -- HACK: remove "GetLibraryVersion" and such later.
|
||||
AceLocale.error(lastSelf or self, "Translation %q does not exist.", k)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
})
|
||||
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceLocale = self
|
||||
|
||||
self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
|
||||
self.registry = oldLib and oldLib.registry or {}
|
||||
self.BASE_TRANSLATIONS = oldLib and oldLib.BASE_TRANSLATIONS or {}
|
||||
self.DEBUGGING = oldLib and oldLib.DEBUGGING or {}
|
||||
self.TRANSLATIONS = oldLib and oldLib.TRANSLATIONS or {}
|
||||
self.BASE_LOCALE = oldLib and oldLib.BASE_LOCALE or {}
|
||||
self.TRANSLATION_TABLES = oldLib and oldLib.TRANSLATION_TABLES or {}
|
||||
self.REVERSE_TRANSLATIONS = oldLib and oldLib.REVERSE_TRANSLATIONS or {}
|
||||
self.STRICTNESS = oldLib and oldLib.STRICTNESS or {}
|
||||
self.NAME = oldLib and oldLib.NAME or {}
|
||||
self.DYNAMIC_LOCALES = oldLib and oldLib.DYNAMIC_LOCALES or {}
|
||||
self.CURRENT_LOCALE = oldLib and oldLib.CURRENT_LOCALE or {}
|
||||
|
||||
BASE_TRANSLATIONS = self.BASE_TRANSLATIONS
|
||||
DEBUGGING = self.DEBUGGING
|
||||
TRANSLATIONS = self.TRANSLATIONS
|
||||
BASE_LOCALE = self.BASE_LOCALE
|
||||
TRANSLATION_TABLES = self.TRANSLATION_TABLES
|
||||
REVERSE_TRANSLATIONS = self.REVERSE_TRANSLATIONS
|
||||
STRICTNESS = self.STRICTNESS
|
||||
NAME = self.NAME
|
||||
DYNAMIC_LOCALES = self.DYNAMIC_LOCALES
|
||||
CURRENT_LOCALE = self.CURRENT_LOCALE
|
||||
|
||||
|
||||
local GetTime = GetTime
|
||||
local timeUntilClear = GetTime() + 5
|
||||
scheduleClear = function()
|
||||
if next(newRegistries) then
|
||||
self.frame:Show()
|
||||
timeUntilClear = GetTime() + 5
|
||||
end
|
||||
end
|
||||
|
||||
if not self.registry then
|
||||
self.registry = {}
|
||||
else
|
||||
for name, instance in pairs(self.registry) do
|
||||
local name = name
|
||||
local mt = getmetatable(instance)
|
||||
setmetatable(instance, nil)
|
||||
instance[NAME] = name
|
||||
local strict
|
||||
if instance[STRICTNESS] ~= nil then
|
||||
strict = instance[STRICTNESS]
|
||||
elseif instance[TRANSLATIONS] ~= instance[BASE_TRANSLATIONS] then
|
||||
if getmetatable(instance[TRANSLATIONS]).__index == oldLib.prototype then
|
||||
strict = true
|
||||
end
|
||||
end
|
||||
instance[STRICTNESS] = strict and true or false
|
||||
refixInstance(instance)
|
||||
end
|
||||
end
|
||||
|
||||
self.frame:SetScript("OnEvent", scheduleClear)
|
||||
self.frame:SetScript("OnUpdate", function() -- (this, elapsed)
|
||||
if timeUntilClear - GetTime() <= 0 then
|
||||
self.frame:Hide()
|
||||
for k in pairs(newRegistries) do
|
||||
clearCache(k)
|
||||
newRegistries[k] = nil
|
||||
k = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
self.frame:UnregisterAllEvents()
|
||||
self.frame:RegisterEvent("ADDON_LOADED")
|
||||
self.frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
self.frame:Show()
|
||||
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate)
|
||||
@@ -0,0 +1,462 @@
|
||||
--[[
|
||||
Name: AceModuleCore-2.0
|
||||
Revision: $Rev: 17998 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceModuleCore-2.0
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceModuleCore-2.0
|
||||
Description: Mixin to provide a module system so that modules or plugins can
|
||||
use an addon as its core.
|
||||
Dependencies: AceLibrary, AceOO-2.0, AceAddon-2.0, AceEvent-2.0 (optional), Compost-2.0 (optional)
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceModuleCore-2.0"
|
||||
local MINOR_VERSION = "$Revision: 17998 $"
|
||||
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
|
||||
|
||||
local function safecall(func,a,b,c,d,e,f,g)
|
||||
local success, err = pcall(func,a,b,c,d,e,f,g)
|
||||
if not success then geterrorhandler()(err) end
|
||||
end
|
||||
|
||||
local table_setn
|
||||
do
|
||||
local version = GetBuildInfo()
|
||||
if string.find(version, "^2%.") then
|
||||
-- 2.0.0
|
||||
table_setn = function() end
|
||||
else
|
||||
table_setn = table.setn
|
||||
end
|
||||
end
|
||||
|
||||
local new, del
|
||||
do
|
||||
local list = setmetatable({}, {__mode = 'k'})
|
||||
function new()
|
||||
local t = next(list)
|
||||
if t then
|
||||
list[t] = nil
|
||||
return t
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
function del(t)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
table_setn(t, 0)
|
||||
list[t] = true
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
|
||||
local AceModuleCore = AceOO.Mixin {
|
||||
"NewModule",
|
||||
"HasModule",
|
||||
"GetModule",
|
||||
"IsModule",
|
||||
"IterateModules",
|
||||
"SetModuleMixins",
|
||||
"SetModuleClass",
|
||||
"IsModuleActive",
|
||||
"ToggleModuleActive"
|
||||
}
|
||||
local AceEvent
|
||||
|
||||
local Compost = AceLibrary:HasInstance("Compost-2.0") and AceLibrary("Compost-2.0")
|
||||
|
||||
local function getlibrary(lib)
|
||||
if type(lib) == "string" then
|
||||
return AceLibrary(lib)
|
||||
else
|
||||
return lib
|
||||
end
|
||||
end
|
||||
|
||||
local tmp
|
||||
function AceModuleCore:NewModule(name, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if not self.modules then
|
||||
AceModuleCore:error("CreatePrototype() must be called before attempting to create a new module.", 2)
|
||||
end
|
||||
AceModuleCore:argCheck(name, 2, "string")
|
||||
if string.len(name) == 0 then
|
||||
AceModuleCore:error("Bad argument #2 to `NewModule`, string must not be empty")
|
||||
end
|
||||
if self.modules[name] then
|
||||
AceModuleCore:error("The module %q has already been registered", name)
|
||||
end
|
||||
|
||||
if not tmp then
|
||||
tmp = {}
|
||||
end
|
||||
if a1 then table.insert(tmp, a1)
|
||||
if a2 then table.insert(tmp, a2)
|
||||
if a3 then table.insert(tmp, a3)
|
||||
if a4 then table.insert(tmp, a4)
|
||||
if a5 then table.insert(tmp, a5)
|
||||
if a6 then table.insert(tmp, a6)
|
||||
if a7 then table.insert(tmp, a7)
|
||||
if a8 then table.insert(tmp, a8)
|
||||
if a9 then table.insert(tmp, a9)
|
||||
if a10 then table.insert(tmp, a10)
|
||||
if a11 then table.insert(tmp, a11)
|
||||
if a12 then table.insert(tmp, a12)
|
||||
if a13 then table.insert(tmp, a13)
|
||||
if a14 then table.insert(tmp, a14)
|
||||
if a15 then table.insert(tmp, a15)
|
||||
if a16 then table.insert(tmp, a16)
|
||||
if a17 then table.insert(tmp, a17)
|
||||
if a18 then table.insert(tmp, a18)
|
||||
if a19 then table.insert(tmp, a19)
|
||||
if a20 then table.insert(tmp, a20)
|
||||
end end end end end end end end end end end end end end end end end end end end
|
||||
for k,v in ipairs(tmp) do
|
||||
tmp[k] = getlibrary(v)
|
||||
end
|
||||
|
||||
if self.moduleMixins then
|
||||
for _,mixin in ipairs(self.moduleMixins) do
|
||||
local exists = false
|
||||
for _,v in ipairs(tmp) do
|
||||
if mixin == v then
|
||||
exists = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not exists then
|
||||
table.insert(tmp, mixin)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local module = AceOO.Classpool(self.moduleClass, unpack(tmp)):new(name)
|
||||
self.modules[name] = module
|
||||
module.name = name
|
||||
module.title = name
|
||||
|
||||
AceModuleCore.totalModules[module] = self
|
||||
|
||||
if AceEvent then
|
||||
AceEvent:TriggerEvent("Ace2_ModuleCreated", module)
|
||||
end
|
||||
|
||||
for k in pairs(tmp) do
|
||||
tmp[k] = nil
|
||||
end
|
||||
table_setn(tmp, 0)
|
||||
return module
|
||||
end
|
||||
|
||||
function AceModuleCore:HasModule(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if a1 then if not self.modules[a1] then return false end
|
||||
if a2 then if not self.modules[a2] then return false end
|
||||
if a3 then if not self.modules[a3] then return false end
|
||||
if a4 then if not self.modules[a4] then return false end
|
||||
if a5 then if not self.modules[a5] then return false end
|
||||
if a6 then if not self.modules[a6] then return false end
|
||||
if a7 then if not self.modules[a7] then return false end
|
||||
if a8 then if not self.modules[a8] then return false end
|
||||
if a9 then if not self.modules[a9] then return false end
|
||||
if a10 then if not self.modules[a10] then return false end
|
||||
if a11 then if not self.modules[a11] then return false end
|
||||
if a12 then if not self.modules[a12] then return false end
|
||||
if a13 then if not self.modules[a13] then return false end
|
||||
if a14 then if not self.modules[a14] then return false end
|
||||
if a15 then if not self.modules[a15] then return false end
|
||||
if a16 then if not self.modules[a16] then return false end
|
||||
if a17 then if not self.modules[a17] then return false end
|
||||
if a18 then if not self.modules[a18] then return false end
|
||||
if a19 then if not self.modules[a19] then return false end
|
||||
if a20 then if not self.modules[a20] then return false end
|
||||
end end end end end end end end end end end end end end end end end end end end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function AceModuleCore:GetModule(name)
|
||||
if not self.modules then
|
||||
AceModuleCore:error("Error initializing class. Please report error.")
|
||||
end
|
||||
if not self.modules[name] then
|
||||
AceModuleCore:error("Cannot find module %q.", name)
|
||||
end
|
||||
return self.modules[name]
|
||||
end
|
||||
|
||||
function AceModuleCore:IsModule(module)
|
||||
if self == AceModuleCore then
|
||||
return AceModuleCore.totalModules[module]
|
||||
else
|
||||
for k,v in pairs(self.modules) do
|
||||
if v == module then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function AceModuleCore:IterateModules()
|
||||
local t = new()
|
||||
for k in pairs(self.modules) do
|
||||
table.insert(t, k)
|
||||
end
|
||||
table.sort(t)
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
local x = t[i]
|
||||
if x then
|
||||
return x, self.modules[x]
|
||||
else
|
||||
t = del(t)
|
||||
return nil
|
||||
end
|
||||
end, nil, nil
|
||||
end
|
||||
|
||||
function AceModuleCore:SetModuleMixins(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if self.moduleMixins then
|
||||
AceModuleCore:error('Cannot call "SetModuleMixins" twice')
|
||||
elseif not self.modules then
|
||||
AceModuleCore:error("Error initializing class. Please report error.")
|
||||
elseif next(self.modules) then
|
||||
AceModuleCore:error('Cannot call "SetModuleMixins" after "NewModule" has been called.')
|
||||
end
|
||||
|
||||
self.moduleMixins = Compost and Compost:Acquire(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) or {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20}
|
||||
for k,v in ipairs(self.moduleMixins) do
|
||||
self.moduleMixins[k] = getlibrary(v)
|
||||
end
|
||||
end
|
||||
|
||||
function AceModuleCore:SetModuleClass(class)
|
||||
class = getlibrary(class)
|
||||
AceModuleCore:assert(AceOO.inherits(class, AceOO.Class), "Bad argument #2 to `SetModuleClass' (Class expected)")
|
||||
if not self.modules then
|
||||
AceModuleCore:error("Error initializing class. Please report error.")
|
||||
end
|
||||
if self.customModuleClass then
|
||||
AceModuleCore:error("Cannot call `SetModuleClass' twice.")
|
||||
end
|
||||
self.customModuleClass = true
|
||||
self.moduleClass = class
|
||||
self.modulePrototype = class.prototype
|
||||
end
|
||||
|
||||
function AceModuleCore:ToggleModuleActive(module, state)
|
||||
AceModuleCore:argCheck(module, 2, "table", "string")
|
||||
AceModuleCore:argCheck(state, 3, "nil", "boolean")
|
||||
|
||||
if type(module) == "string" then
|
||||
if not self:HasModule(module) then
|
||||
AceModuleCore:error("Cannot find module %q", module)
|
||||
end
|
||||
module = self:GetModule(module)
|
||||
else
|
||||
if not self:IsModule(module) then
|
||||
AceModuleCore:error("%q is not a module", module)
|
||||
end
|
||||
end
|
||||
|
||||
local disable
|
||||
if state == nil then
|
||||
disable = self:IsModuleActive(module)
|
||||
else
|
||||
disable = not state
|
||||
if disable ~= self:IsModuleActive(module) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if type(module.ToggleActive) == "function" then
|
||||
return module:ToggleActive(not disable)
|
||||
elseif AceOO.inherits(self, "AceDB-2.0") then
|
||||
if not self.db or not self.db.raw then
|
||||
AceModuleCore:error("Cannot toggle a module until `RegisterDB' has been called and `ADDON_LOADED' has been fireed.")
|
||||
end
|
||||
if type(self.db.raw.disabledModules) ~= "table" then
|
||||
self.db.raw.disabledModules = Compost and Compost:Acquire() or {}
|
||||
end
|
||||
local _,profile = self:GetProfile()
|
||||
if type(self.db.raw.disabledModules[profile]) ~= "table" then
|
||||
self.db.raw.disabledModules[profile] = Compost and Compost:Acquire() or {}
|
||||
end
|
||||
if type(self.db.raw.disabledModules[profile][module.name]) ~= "table" then
|
||||
self.db.raw.disabledModules[profile][module.name] = disable or nil
|
||||
end
|
||||
if not disable then
|
||||
if not next(self.db.raw.disabledModules[profile]) then
|
||||
if Compost then
|
||||
Compost:Reclaim(self.db.raw.disabledModules[profile])
|
||||
end
|
||||
self.db.raw.disabledModules[profile] = nil
|
||||
end
|
||||
if not next(self.db.raw.disabledModules) then
|
||||
if Compost then
|
||||
Compost:Reclaim(self.db.raw.disabledModules)
|
||||
end
|
||||
self.db.raw.disabledModules = nil
|
||||
end
|
||||
end
|
||||
else
|
||||
if type(self.disabledModules) ~= "table" then
|
||||
self.disabledModules = Compost and Compost:Acquire() or {}
|
||||
end
|
||||
self.disabledModules[module.name] = disable or nil
|
||||
end
|
||||
if AceOO.inherits(module, "AceAddon-2.0") then
|
||||
local AceAddon = AceLibrary("AceAddon-2.0")
|
||||
if not AceAddon.addonsStarted[module] then
|
||||
return
|
||||
end
|
||||
end
|
||||
if not disable then
|
||||
local current = module.class
|
||||
while true do
|
||||
if current == AceOO.Class then
|
||||
break
|
||||
end
|
||||
if current.mixins then
|
||||
for mixin in pairs(current.mixins) do
|
||||
if type(mixin.OnEmbedEnable) == "function" then
|
||||
safecall(mixin.OnEmbedEnable, mixin, module)
|
||||
end
|
||||
end
|
||||
end
|
||||
current = current.super
|
||||
end
|
||||
if type(module.OnEnable) == "function" then
|
||||
safecall(module.OnEnable, module)
|
||||
end
|
||||
if AceEvent then
|
||||
AceEvent:TriggerEvent("Ace2_AddonEnabled", module)
|
||||
end
|
||||
else
|
||||
local current = module.class
|
||||
while true do
|
||||
if current == AceOO.Class then
|
||||
break
|
||||
end
|
||||
if current.mixins then
|
||||
for mixin in pairs(current.mixins) do
|
||||
if type(mixin.OnEmbedDisable) == "function" then
|
||||
safecall(mixin.OnEmbedDisable, mixin, module)
|
||||
end
|
||||
end
|
||||
end
|
||||
current = current.super
|
||||
end
|
||||
if type(module.OnDisable) == "function" then
|
||||
safecall(module.OnDisable, module)
|
||||
end
|
||||
if AceEvent then
|
||||
AceEvent:TriggerEvent("Ace2_AddonDisabled", module)
|
||||
end
|
||||
end
|
||||
return not disable
|
||||
end
|
||||
|
||||
function AceModuleCore:IsModuleActive(module)
|
||||
AceModuleCore:argCheck(module, 2, "table", "string")
|
||||
|
||||
if AceModuleCore == self then
|
||||
self:argCheck(module, 2, "table")
|
||||
|
||||
local core = AceModuleCore.totalModules[module]
|
||||
if not core then
|
||||
self:error("Bad argument #2 to `IsModuleActive'. Not a module")
|
||||
end
|
||||
return core:IsModuleActive(module)
|
||||
end
|
||||
|
||||
if type(module) == "string" then
|
||||
if not self:HasModule(module) then
|
||||
AceModuleCore:error("Cannot find module %q", module)
|
||||
end
|
||||
module = self:GetModule(module)
|
||||
else
|
||||
if not self:IsModule(module) then
|
||||
AceModuleCore:error("%q is not a module", module)
|
||||
end
|
||||
end
|
||||
|
||||
if type(module.IsActive) == "function" then
|
||||
return module:IsActive()
|
||||
elseif AceOO.inherits(self, "AceDB-2.0") then
|
||||
local _,profile = self:GetProfile()
|
||||
return not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[profile] or not self.db.raw.disabledModules[profile][module.name]
|
||||
else
|
||||
return not self.disabledModules or not self.disabledModules[module.name]
|
||||
end
|
||||
end
|
||||
|
||||
function AceModuleCore:OnInstanceInit(target)
|
||||
if target.modules then
|
||||
AceModuleCore:error("OnInstanceInit cannot be called twice")
|
||||
end
|
||||
target.modules = Compost and Compost:Acquire() or {}
|
||||
|
||||
target.moduleClass = AceOO.Class("AceAddon-2.0")
|
||||
target.modulePrototype = target.moduleClass.prototype
|
||||
end
|
||||
|
||||
AceModuleCore.OnManualEmbed = AceModuleCore.OnInstanceInit
|
||||
|
||||
function AceModuleCore.OnEmbedProfileDisable(AceModuleCore, self, newProfile)
|
||||
if not AceOO.inherits(self, "AceDB-2.0") then
|
||||
return
|
||||
end
|
||||
local _,currentProfile = self:GetProfile()
|
||||
for k, module in pairs(self.modules) do
|
||||
if type(module.IsActive) == "function" or type(module.ToggleActive) == "function" then
|
||||
-- continue
|
||||
else
|
||||
local currentActive = not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[currentProfile] or not self.db.raw.disabledModules[currentProfile][module.name]
|
||||
local newActive = not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[newProfile] or not self.db.raw.disabledModules[newProfile][module.name]
|
||||
if currentActive ~= newActive then
|
||||
self:ToggleModuleActive(module)
|
||||
if not self.db.raw.disabledModules then
|
||||
self.db.raw.disabledModules = {}
|
||||
end
|
||||
if not self.db.raw.disabledModules[currentProfile] then
|
||||
self.db.raw.disabledModules[currentProfile] = {}
|
||||
end
|
||||
self.db.raw.disabledModules[currentProfile][module.name] = not currentActive or nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceModuleCore = self
|
||||
|
||||
if oldLib then
|
||||
self.totalModules = oldLib.totalModules
|
||||
end
|
||||
if not self.totalModules then
|
||||
self.totalModules = {}
|
||||
end
|
||||
|
||||
self.super.activate(self, oldLib, oldDeactivate)
|
||||
end
|
||||
|
||||
local function external(self, major, instance)
|
||||
if major == "Compost-2.0" then
|
||||
Compost = instance
|
||||
elseif major == "AceEvent-2.0" then
|
||||
AceEvent = instance
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceModuleCore, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
|
||||
AceModuleCore = AceLibrary(MAJOR_VERSION)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+872
@@ -0,0 +1,872 @@
|
||||
-- No PerfBoost v2, no need for settings
|
||||
local has_perf_boost = pcall(GetCVar, "PB_Enabled")
|
||||
if not has_perf_boost then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost|cffffaaaa not present hiding settings.")
|
||||
return
|
||||
end
|
||||
|
||||
PerfBoost = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceDebug-2.0", "AceModuleCore-2.0", "AceConsole-2.0", "AceDB-2.0", "AceHook-2.1")
|
||||
PerfBoost:RegisterDB("PerfBoostSettingsDB")
|
||||
PerfBoost:RegisterDefaults("profile", {
|
||||
per_character_settings = false,
|
||||
previous_player_render_dist = nil,
|
||||
})
|
||||
PerfBoost.frame = CreateFrame("Frame", "PerfBoost", UIParent)
|
||||
|
||||
BINDING_HEADER_PERFBOOST = "PerfBoost";
|
||||
BINDING_NAME_PERFBOOSTENABLE = "Toggles whether perfboot is enabled/disabled";
|
||||
BINDING_NAME_PBHIDEALLPLAYERS = "Toggle hide all players (overrides other settings)";
|
||||
BINDING_NAME_PBTOGGLEPLAYERRENDERIST = "Toggle 0 player render distance (hides all players respecting other settings)";
|
||||
BINDING_NAME_PBSHOWALLPLAYERS = "Toggle show all players (overrides other settings)";
|
||||
BINDING_NAME_PBCYCLEPLAYERVISIBILITY = "Cycle player visibility: show all -> hide all -> normal";
|
||||
|
||||
-- used when turning on per character settings
|
||||
function PerfBoost:SavePerCharacterSettings()
|
||||
local function saveNestedSettings(args)
|
||||
for settingKey, settingData in pairs(args) do
|
||||
if string.find(settingKey, "PB_") == 1 and settingData.get and settingData.set then
|
||||
settingData.set(settingData.get()) -- trigger the set function for each setting with the current value
|
||||
elseif settingData.args then
|
||||
saveNestedSettings(settingData.args)
|
||||
end
|
||||
end
|
||||
end
|
||||
saveNestedSettings(PerfBoost.cmdtable.args)
|
||||
end
|
||||
|
||||
function PerfBoost:ApplySavedSettings()
|
||||
local function applyNestedSettings(args)
|
||||
for settingKey, settingData in pairs(args) do
|
||||
if string.find(settingKey, "PB_") == 1 and settingData.set then
|
||||
if PerfBoost.db.profile[settingKey] ~= nil then
|
||||
settingData.set(PerfBoost.db.profile[settingKey])
|
||||
end
|
||||
elseif settingData.args then
|
||||
applyNestedSettings(settingData.args)
|
||||
end
|
||||
end
|
||||
end
|
||||
applyNestedSettings(PerfBoost.cmdtable.args)
|
||||
end
|
||||
|
||||
function PerfBoost:OnEnable()
|
||||
-- if per character settings are enabled, apply them
|
||||
if PerfBoost.db.profile.per_character_settings then
|
||||
PerfBoost:ApplySavedSettings()
|
||||
end
|
||||
end
|
||||
|
||||
PerfBoost.cmdtable = {
|
||||
type = "group",
|
||||
handler = PerfBoost,
|
||||
args = {
|
||||
per_character_settings = {
|
||||
type = "toggle",
|
||||
name = "Enable Per Character Settings",
|
||||
desc = "Whether to use per character settings for all of the PB_ settings. This will cause settings saved in your character's PerfBoostSettings.lua to override any global settings in Config.wtf.",
|
||||
order = 1,
|
||||
get = function()
|
||||
return PerfBoost.db.profile.per_character_settings
|
||||
end,
|
||||
set = function(v)
|
||||
if v ~= PerfBoost.db.profile.per_character_settings then
|
||||
PerfBoost.db.profile.per_character_settings = v
|
||||
if v == true then
|
||||
PerfBoost:SavePerCharacterSettings()
|
||||
end
|
||||
end
|
||||
end,
|
||||
},
|
||||
PB_Enabled = {
|
||||
type = "toggle",
|
||||
name = "Enable Performance Boost",
|
||||
desc = "Enable/disable all performance boost features",
|
||||
order = 5,
|
||||
get = function()
|
||||
return GetCVar("PB_Enabled") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_Enabled = v
|
||||
if v == true then
|
||||
SetCVar("PB_Enabled", "1")
|
||||
else
|
||||
SetCVar("PB_Enabled", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
PB_ShowAllPlayers = {
|
||||
type = "toggle",
|
||||
name = "Show All Players (Overrides other settings)",
|
||||
desc = "Show all players regardless of distance and other render settings. Has priority over hide all players.",
|
||||
order = 6,
|
||||
get = function()
|
||||
return GetCVar("PB_ShowAllPlayers") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_ShowAllPlayers = v
|
||||
if v == true then
|
||||
SetCVar("PB_ShowAllPlayers", "1")
|
||||
else
|
||||
SetCVar("PB_ShowAllPlayers", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
PB_HideAllPlayers = {
|
||||
type = "toggle",
|
||||
name = "Hide All Players (Overrides other settings)",
|
||||
desc = "Hide all players regardless of other render settings",
|
||||
order = 7,
|
||||
get = function()
|
||||
return GetCVar("PB_HideAllPlayers") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_HideAllPlayers = v
|
||||
if v == true then
|
||||
SetCVar("PB_HideAllPlayers", "1")
|
||||
else
|
||||
SetCVar("PB_HideAllPlayers", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
spacera = {
|
||||
type = "header",
|
||||
name = " ",
|
||||
order = 10,
|
||||
},
|
||||
|
||||
rendering = {
|
||||
type = "group",
|
||||
name = "Rendering Settings",
|
||||
desc = "Configure all rendering and visibility options",
|
||||
order = 15,
|
||||
args = {
|
||||
PB_AlwaysRenderRaidMarks = {
|
||||
type = "toggle",
|
||||
name = "Always Render Raid Marks",
|
||||
desc = "Whether to always render raid marks",
|
||||
order = 1,
|
||||
get = function()
|
||||
return GetCVar("PB_AlwaysRenderRaidMarks") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_AlwaysRenderRaidMarks = v
|
||||
if v == true then
|
||||
SetCVar("PB_AlwaysRenderRaidMarks", "1")
|
||||
else
|
||||
SetCVar("PB_AlwaysRenderRaidMarks", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
PB_AlwaysRenderPVP = {
|
||||
type = "toggle",
|
||||
name = "Always Render PVP Players",
|
||||
desc = "Whether to always render players flagged for PVP",
|
||||
order = 2,
|
||||
get = function()
|
||||
return GetCVar("PB_AlwaysRenderPVP") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_AlwaysRenderPVP = v
|
||||
if v == true then
|
||||
SetCVar("PB_AlwaysRenderPVP", "1")
|
||||
else
|
||||
SetCVar("PB_AlwaysRenderPVP", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
PB_AlwaysRenderPlayersWithAggro = {
|
||||
type = "toggle",
|
||||
name = "Always Render Players With Aggro",
|
||||
desc = "Whether to always render players who have aggro from enemies",
|
||||
order = 3,
|
||||
get = function()
|
||||
return GetCVar("PB_AlwaysRenderPlayersWithAggro") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_AlwaysRenderPlayersWithAggro = v
|
||||
if v == true then
|
||||
SetCVar("PB_AlwaysRenderPlayersWithAggro", "1")
|
||||
else
|
||||
SetCVar("PB_AlwaysRenderPlayersWithAggro", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
PB_AlwaysRenderPlayers = {
|
||||
type = "text",
|
||||
name = "Always Render Players (ENTER to save)",
|
||||
desc = "Comma separated list of playernames to always render regardless of other settings",
|
||||
usage = "Name1,Name2,etc",
|
||||
order = 4,
|
||||
get = function()
|
||||
return GetCVar("PB_AlwaysRenderPlayers") or ""
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_AlwaysRenderPlayers = v
|
||||
SetCVar("PB_AlwaysRenderPlayers", v)
|
||||
end,
|
||||
},
|
||||
|
||||
PB_NeverRenderPlayers = {
|
||||
type = "text",
|
||||
name = "Never Render Players (ENTER to save)",
|
||||
desc = "Comma separated list of playernames to never render regardless of other settings",
|
||||
usage = "Name1,Name2,etc",
|
||||
order = 5,
|
||||
get = function()
|
||||
return GetCVar("PB_NeverRenderPlayers") or ""
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_NeverRenderPlayers = v
|
||||
SetCVar("PB_NeverRenderPlayers", v)
|
||||
end,
|
||||
},
|
||||
|
||||
spacer_player = {
|
||||
type = "header",
|
||||
name = "Player Distances",
|
||||
order = 10,
|
||||
},
|
||||
|
||||
PB_PlayerRenderDist = {
|
||||
type = "range",
|
||||
name = "Default Player Render Distance",
|
||||
desc = "Max distance to render players when not in combat",
|
||||
order = 11,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_PlayerRenderDist")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_PlayerRenderDist = v
|
||||
SetCVar("PB_PlayerRenderDist", tostring(v))
|
||||
end,
|
||||
},
|
||||
PB_PlayerRenderDistInCombat = {
|
||||
type = "range",
|
||||
name = "In Combat Player Render Distance",
|
||||
desc = "Max distance to render players when in combat",
|
||||
order = 12,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_PlayerRenderDistInCombat")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_PlayerRenderDistInCombat = v
|
||||
SetCVar("PB_PlayerRenderDistInCombat", tostring(v))
|
||||
end,
|
||||
},
|
||||
PB_PlayerRenderDistInCities = {
|
||||
type = "range",
|
||||
name = "In Cities Player Render Distance",
|
||||
desc = "Max distance to render players when in cities",
|
||||
order = 13,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_PlayerRenderDistInCities")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_PlayerRenderDistInCities = v
|
||||
SetCVar("PB_PlayerRenderDistInCities", tostring(v))
|
||||
end,
|
||||
},
|
||||
|
||||
spacer_trash = {
|
||||
type = "header",
|
||||
name = "Trash Units",
|
||||
order = 20,
|
||||
},
|
||||
|
||||
PB_TrashUnitRenderDist = {
|
||||
type = "range",
|
||||
name = "Default Trash Unit (lvl < 63) Render Distance",
|
||||
desc = "Max distance to render trash units when not in combat",
|
||||
order = 21,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_TrashUnitRenderDist")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_TrashUnitRenderDist = v
|
||||
SetCVar("PB_TrashUnitRenderDist", tostring(v))
|
||||
end,
|
||||
},
|
||||
PB_TrashUnitRenderDistInCombat = {
|
||||
type = "range",
|
||||
name = "In Combat Trash Unit (lvl < 63) Render Distance",
|
||||
desc = "Max distance to render trash units when in combat",
|
||||
order = 22,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_TrashUnitRenderDistInCombat")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_TrashUnitRenderDistInCombat = v
|
||||
SetCVar("PB_TrashUnitRenderDistInCombat", tostring(v))
|
||||
end,
|
||||
},
|
||||
|
||||
spacer_pets = {
|
||||
type = "header",
|
||||
name = "Pets & Summons",
|
||||
order = 30,
|
||||
},
|
||||
|
||||
PB_PetRenderDist = {
|
||||
type = "range",
|
||||
name = "Default Pet Render Distance",
|
||||
desc = "Max distance to render pets when not in combat. Your own pet is always shown.",
|
||||
order = 31,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_PetRenderDist")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_PetRenderDist = v
|
||||
SetCVar("PB_PetRenderDist", tostring(v))
|
||||
end,
|
||||
},
|
||||
PB_PetRenderDistInCombat = {
|
||||
type = "range",
|
||||
name = "In Combat Pet Render Distance",
|
||||
desc = "Max distance to render pets when in combat. Your own pet is always shown.",
|
||||
order = 32,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_PetRenderDistInCombat")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_PetRenderDistInCombat = v
|
||||
SetCVar("PB_PetRenderDistInCombat", tostring(v))
|
||||
end,
|
||||
},
|
||||
|
||||
PB_SummonRenderDist = {
|
||||
type = "range",
|
||||
name = "Default Totem/Guardian Render Distance",
|
||||
desc = "Max distance to render unnamed summons when not in combat. Your own totems and guardians are always shown.",
|
||||
order = 33,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_SummonRenderDist")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_SummonRenderDist = v
|
||||
SetCVar("PB_SummonRenderDist", tostring(v))
|
||||
end,
|
||||
},
|
||||
PB_SummonRenderDistInCombat = {
|
||||
type = "range",
|
||||
name = "In Combat Totem/Guardian Render Distance",
|
||||
desc = "Max distance to render unnamed summons when in combat. Your own totems and guardians are always shown.",
|
||||
order = 34,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_SummonRenderDistInCombat")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_SummonRenderDistInCombat = v
|
||||
SetCVar("PB_SummonRenderDistInCombat", tostring(v))
|
||||
end,
|
||||
},
|
||||
|
||||
spacer_corpse = {
|
||||
type = "header",
|
||||
name = "Other Objects",
|
||||
order = 40,
|
||||
},
|
||||
|
||||
PB_CorpseRenderDist = {
|
||||
type = "range",
|
||||
name = "Corpse Render Distance",
|
||||
desc = "Max distance to render corpses",
|
||||
order = 41,
|
||||
min = -1,
|
||||
max = 100,
|
||||
step = 1,
|
||||
get = function()
|
||||
local val = GetCVar("PB_CorpseRenderDist")
|
||||
return val and tonumber(val) or 0
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_CorpseRenderDist = v
|
||||
SetCVar("PB_CorpseRenderDist", tostring(v))
|
||||
end,
|
||||
},
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
spells = {
|
||||
type = "group",
|
||||
name = "Spell Visual Settings",
|
||||
desc = "Configure spell visual effects and filtering",
|
||||
order = 20,
|
||||
args = {
|
||||
PB_ShowPlayerSpellVisuals = {
|
||||
type = "toggle",
|
||||
name = "Show Other Player Spell Visuals",
|
||||
desc = "Whether to show spell visual effects from other players. This includes spell casts, ranged weapon projectiles, wanding, not sure what else.",
|
||||
order = 1,
|
||||
get = function()
|
||||
return GetCVar("PB_ShowPlayerSpellVisuals") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_ShowPlayerSpellVisuals = v
|
||||
if v == true then
|
||||
SetCVar("PB_ShowPlayerSpellVisuals", "1")
|
||||
else
|
||||
SetCVar("PB_ShowPlayerSpellVisuals", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
PB_ShowPlayerGroundEffects = {
|
||||
type = "toggle",
|
||||
name = "Show Other Player Ground Effects",
|
||||
desc = "Whether to show ground effects from players",
|
||||
order = 2,
|
||||
get = function()
|
||||
return GetCVar("PB_ShowPlayerGroundEffects") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_ShowPlayerGroundEffects = v
|
||||
if v == true then
|
||||
SetCVar("PB_ShowPlayerGroundEffects", "1")
|
||||
else
|
||||
SetCVar("PB_ShowPlayerGroundEffects", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
PB_ShowPlayerAuraVisuals = {
|
||||
type = "toggle",
|
||||
name = "Show Other Player Aura Visuals",
|
||||
desc = "Whether to show aura visual effects on players",
|
||||
order = 3,
|
||||
get = function()
|
||||
return GetCVar("PB_ShowPlayerAuraVisuals") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_ShowPlayerAuraVisuals = v
|
||||
if v == true then
|
||||
SetCVar("PB_ShowPlayerAuraVisuals", "1")
|
||||
else
|
||||
SetCVar("PB_ShowPlayerAuraVisuals", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
PB_ShowUnitAuraVisuals = {
|
||||
type = "toggle",
|
||||
name = "Show Unit Aura Visuals",
|
||||
desc = "Whether to show aura visual effects on units (NPCs, mobs)",
|
||||
order = 4,
|
||||
get = function()
|
||||
return GetCVar("PB_ShowUnitAuraVisuals") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_ShowUnitAuraVisuals = v
|
||||
if v == true then
|
||||
SetCVar("PB_ShowUnitAuraVisuals", "1")
|
||||
else
|
||||
SetCVar("PB_ShowUnitAuraVisuals", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
PB_HideSpellsForHiddenPlayers = {
|
||||
type = "toggle",
|
||||
name = "Hide Spells for Hidden Players",
|
||||
desc = "Hide spell visuals from players that are hidden due to render distance or other settings",
|
||||
order = 5,
|
||||
get = function()
|
||||
return GetCVar("PB_HideSpellsForHiddenPlayers") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_HideSpellsForHiddenPlayers = v
|
||||
if v == true then
|
||||
SetCVar("PB_HideSpellsForHiddenPlayers", "1")
|
||||
else
|
||||
SetCVar("PB_HideSpellsForHiddenPlayers", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
spacer_spells = {
|
||||
type = "header",
|
||||
order = 10,
|
||||
},
|
||||
|
||||
PB_HiddenSpellIds = {
|
||||
type = "text",
|
||||
name = "Always Hidden Spell IDs (ENTER to save)",
|
||||
desc = "Comma separated list of spell IDs to hide visuals for",
|
||||
usage = "1234,5678,etc",
|
||||
order = 11,
|
||||
get = function()
|
||||
return GetCVar("PB_HiddenSpellIds") or ""
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_HiddenSpellIds = v
|
||||
SetCVar("PB_HiddenSpellIds", v)
|
||||
end,
|
||||
},
|
||||
|
||||
PB_AlwaysShownSpellIds = {
|
||||
type = "text",
|
||||
name = "Always Shown Spell IDs (ENTER to save)",
|
||||
desc = "Comma separated list of spell IDs to always show visuals for, overriding other settings",
|
||||
usage = "1234,5678,etc",
|
||||
order = 12,
|
||||
get = function()
|
||||
return GetCVar("PB_AlwaysShownSpellIds") or ""
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_AlwaysShownSpellIds = v
|
||||
SetCVar("PB_AlwaysShownSpellIds", v)
|
||||
end,
|
||||
},
|
||||
|
||||
PB_ApplyHiddenSpellIdsToMe = {
|
||||
type = "toggle",
|
||||
name = "Apply Hidden Spell IDs to Me",
|
||||
desc = "Whether to apply the hidden spell IDs list to your own character's spells",
|
||||
order = 13,
|
||||
get = function()
|
||||
return GetCVar("PB_ApplyHiddenSpellIdsToMe") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_ApplyHiddenSpellIdsToMe = v
|
||||
if v == true then
|
||||
SetCVar("PB_ApplyHiddenSpellIdsToMe", "1")
|
||||
else
|
||||
SetCVar("PB_ApplyHiddenSpellIdsToMe", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
spacer_main = {
|
||||
type = "header",
|
||||
name = " ",
|
||||
order = 25,
|
||||
},
|
||||
|
||||
PB_FilterGuidEvents = {
|
||||
type = "toggle",
|
||||
name = "Filter GUID Events",
|
||||
desc = "Filters out generally unnecessary superwow GUID-based events to reduce event spam and improve performance. Blocks events like UNIT_AURA, UNIT_HEALTH, UNIT_MANA when triggered with a guid instead of a string like 'player' or 'raid1', while preserving commonly used guid events like UNIT_COMBAT and UNIT_MODEL_CHANGED.",
|
||||
order = 30,
|
||||
get = function()
|
||||
return GetCVar("PB_FilterGuidEvents") == "1"
|
||||
end,
|
||||
set = function(v)
|
||||
PerfBoost.db.profile.PB_FilterGuidEvents = v
|
||||
if v == true then
|
||||
SetCVar("PB_FilterGuidEvents", "1")
|
||||
else
|
||||
SetCVar("PB_FilterGuidEvents", "0")
|
||||
end
|
||||
end,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
local deuce = PerfBoost:NewModule("PerfBoost Options Menu")
|
||||
deuce.hasFuBar = IsAddOnLoaded("FuBar") and FuBar
|
||||
deuce.consoleCmd = not deuce.hasFuBar
|
||||
|
||||
PerfBoostOptions = AceLibrary("AceAddon-2.0"):new("AceDB-2.0", "FuBarPlugin-2.0")
|
||||
PerfBoostOptions.name = "FuBar - PerfBoost"
|
||||
PerfBoostOptions.hasIcon = "Interface\\Icons\\Spell_Nature_Strength"
|
||||
PerfBoostOptions.defaultMinimapPosition = 180
|
||||
PerfBoostOptions.independentProfile = true
|
||||
PerfBoostOptions.hideWithoutStandby = false
|
||||
|
||||
PerfBoostOptions.OnMenuRequest = PerfBoost.cmdtable
|
||||
local args = AceLibrary("FuBarPlugin-2.0"):GetAceOptionsDataTable(PerfBoostOptions)
|
||||
for k, v in pairs(args) do
|
||||
if PerfBoostOptions.OnMenuRequest.args[k] == nil then
|
||||
PerfBoostOptions.OnMenuRequest.args[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
SLASH_PBENABLE1, SLASH_PBENABLE2 = '/pbenable', '/perfboostenable'
|
||||
function SlashCmdList.PBENABLE(msg, editbox)
|
||||
local v = not (GetCVar("PB_Enabled") == "1")
|
||||
PerfBoost.db.profile.PB_Enabled = v
|
||||
if v == true then
|
||||
SetCVar("PB_Enabled", "1")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r enabled")
|
||||
else
|
||||
SetCVar("PB_Enabled", "0")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r disabled")
|
||||
end
|
||||
end
|
||||
|
||||
SLASH_PBALWAYSRENDER1, SLASH_PBALWAYSRENDER2 = '/pbalwaysrender', '/pbar'
|
||||
function SlashCmdList.PBALWAYSRENDER(msg, editbox)
|
||||
local target = UnitName("target")
|
||||
if not target then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r No target selected")
|
||||
return
|
||||
end
|
||||
|
||||
local current = GetCVar("PB_AlwaysRenderPlayers") or ""
|
||||
local names = {}
|
||||
if current ~= "" then
|
||||
for name in string.gfind(current, "([^,]+)") do
|
||||
name = string.gsub(name, "^%s*(.-)%s*$", "%1")
|
||||
if name ~= "" then
|
||||
names[name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if names[target] then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r " .. target .. " is already in always render list")
|
||||
return
|
||||
end
|
||||
|
||||
names[target] = true
|
||||
local newList = ""
|
||||
for name in pairs(names) do
|
||||
if newList == "" then
|
||||
newList = name
|
||||
else
|
||||
newList = newList .. "," .. name
|
||||
end
|
||||
end
|
||||
|
||||
PerfBoost.db.profile.PB_AlwaysRenderPlayers = newList
|
||||
SetCVar("PB_AlwaysRenderPlayers", newList)
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Added " .. target .. " to always render list")
|
||||
end
|
||||
|
||||
SLASH_PBNEVERRENDER1, SLASH_PBNEVERRENDER2 = '/pbneverrender', '/pbnr'
|
||||
function SlashCmdList.PBNEVERRENDER(msg, editbox)
|
||||
local target = UnitName("target")
|
||||
if not target then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r No target selected")
|
||||
return
|
||||
end
|
||||
|
||||
local current = GetCVar("PB_NeverRenderPlayers") or ""
|
||||
local names = {}
|
||||
if current ~= "" then
|
||||
for name in string.gfind(current, "([^,]+)") do
|
||||
name = string.gsub(name, "^%s*(.-)%s*$", "%1")
|
||||
if name ~= "" then
|
||||
names[name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if names[target] then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r " .. target .. " is already in never render list")
|
||||
return
|
||||
end
|
||||
|
||||
names[target] = true
|
||||
local newList = ""
|
||||
for name in pairs(names) do
|
||||
if newList == "" then
|
||||
newList = name
|
||||
else
|
||||
newList = newList .. "," .. name
|
||||
end
|
||||
end
|
||||
|
||||
PerfBoost.db.profile.PB_NeverRenderPlayers = newList
|
||||
SetCVar("PB_NeverRenderPlayers", newList)
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Added " .. target .. " to never render list")
|
||||
end
|
||||
|
||||
SLASH_PBALWAYSRENDERREMOVE1, SLASH_PBALWAYSRENDERREMOVE2 = '/pbalwaysrenderremove', '/pbarr'
|
||||
function SlashCmdList.PBALWAYSRENDERREMOVE(msg, editbox)
|
||||
local target = UnitName("target")
|
||||
if not target then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r No target selected")
|
||||
return
|
||||
end
|
||||
|
||||
local current = GetCVar("PB_AlwaysRenderPlayers") or ""
|
||||
local names = {}
|
||||
if current ~= "" then
|
||||
for name in string.gfind(current, "([^,]+)") do
|
||||
name = string.gsub(name, "^%s*(.-)%s*$", "%1")
|
||||
if name ~= "" and name ~= target then
|
||||
names[name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local newList = ""
|
||||
for name in pairs(names) do
|
||||
if newList == "" then
|
||||
newList = name
|
||||
else
|
||||
newList = newList .. "," .. name
|
||||
end
|
||||
end
|
||||
|
||||
PerfBoost.db.profile.PB_AlwaysRenderPlayers = newList
|
||||
SetCVar("PB_AlwaysRenderPlayers", newList)
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Removed " .. target .. " from always render list")
|
||||
end
|
||||
|
||||
SLASH_PBNEVERRENDERREMOVE1, SLASH_PBNEVERRENDERREMOVE2 = '/pbneverrenderremove', '/pbnrr'
|
||||
function SlashCmdList.PBNEVERRENDERREMOVE(msg, editbox)
|
||||
local target = UnitName("target")
|
||||
if not target then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r No target selected")
|
||||
return
|
||||
end
|
||||
|
||||
local current = GetCVar("PB_NeverRenderPlayers") or ""
|
||||
local names = {}
|
||||
if current ~= "" then
|
||||
for name in string.gfind(current, "([^,]+)") do
|
||||
name = string.gsub(name, "^%s*(.-)%s*$", "%1")
|
||||
if name ~= "" and name ~= target then
|
||||
names[name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local newList = ""
|
||||
for name in pairs(names) do
|
||||
if newList == "" then
|
||||
newList = name
|
||||
else
|
||||
newList = newList .. "," .. name
|
||||
end
|
||||
end
|
||||
|
||||
PerfBoost.db.profile.PB_NeverRenderPlayers = newList
|
||||
SetCVar("PB_NeverRenderPlayers", newList)
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Removed " .. target .. " from never render list")
|
||||
end
|
||||
|
||||
SLASH_PBALWAYSRENDERCLEAR1, SLASH_PBALWAYSRENDERCLEAR2 = '/pbalwaysrenderclear', '/pbarc'
|
||||
function SlashCmdList.PBALWAYSRENDERCLEAR(msg, editbox)
|
||||
PerfBoost.db.profile.PB_AlwaysRenderPlayers = ""
|
||||
SetCVar("PB_AlwaysRenderPlayers", "")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Cleared always render list")
|
||||
end
|
||||
|
||||
SLASH_PBNEVERRENDERCLEAR1, SLASH_PBNEVERRENDERCLEAR2 = '/pbneverrenderclear', '/pbnrc'
|
||||
function SlashCmdList.PBNEVERRENDERCLEAR(msg, editbox)
|
||||
PerfBoost.db.profile.PB_NeverRenderPlayers = ""
|
||||
SetCVar("PB_NeverRenderPlayers", "")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Cleared never render list")
|
||||
end
|
||||
|
||||
SLASH_PBHIDEALLPLAYERS1, SLASH_PBHIDEALLPLAYERS2 = '/pbhideallplayers', '/pbhap'
|
||||
function SlashCmdList.PBHIDEALLPLAYERS(msg, editbox)
|
||||
local v = not (GetCVar("PB_HideAllPlayers") == "1")
|
||||
PerfBoost.db.profile.PB_HideAllPlayers = v
|
||||
if v == true then
|
||||
SetCVar("PB_HideAllPlayers", "1")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Hide all players enabled")
|
||||
else
|
||||
SetCVar("PB_HideAllPlayers", "0")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Hide all players disabled")
|
||||
end
|
||||
end
|
||||
|
||||
SLASH_PBSHOWALLPLAYERS1, SLASH_PBSHOWALLPLAYERS2 = '/pbshowallplayers', '/pbsap'
|
||||
function SlashCmdList.PBSHOWALLPLAYERS(msg, editbox)
|
||||
local v = not (GetCVar("PB_ShowAllPlayers") == "1")
|
||||
PerfBoost.db.profile.PB_ShowAllPlayers = v
|
||||
if v == true then
|
||||
SetCVar("PB_ShowAllPlayers", "1")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Show all players enabled")
|
||||
else
|
||||
SetCVar("PB_ShowAllPlayers", "0")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Show all players disabled")
|
||||
end
|
||||
end
|
||||
|
||||
SLASH_PBCYCLEPLAYERVISIBILITY1, SLASH_PBCYCLEPLAYERVISIBILITY2 = '/pbcycleplayervisibility', '/pbcycle'
|
||||
function SlashCmdList.PBCYCLEPLAYERVISIBILITY(msg, editbox)
|
||||
local showAll = GetCVar("PB_ShowAllPlayers") == "1"
|
||||
local hideAll = GetCVar("PB_HideAllPlayers") == "1"
|
||||
|
||||
if not showAll and not hideAll then
|
||||
-- Normal -> Show All
|
||||
PerfBoost.db.profile.PB_ShowAllPlayers = true
|
||||
PerfBoost.db.profile.PB_HideAllPlayers = false
|
||||
SetCVar("PB_ShowAllPlayers", "1")
|
||||
SetCVar("PB_HideAllPlayers", "0")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Show all players enabled")
|
||||
elseif showAll and not hideAll then
|
||||
-- Show All -> Hide All
|
||||
PerfBoost.db.profile.PB_ShowAllPlayers = false
|
||||
PerfBoost.db.profile.PB_HideAllPlayers = true
|
||||
SetCVar("PB_ShowAllPlayers", "0")
|
||||
SetCVar("PB_HideAllPlayers", "1")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Hide all players enabled")
|
||||
else
|
||||
-- Hide All (or both) -> Normal
|
||||
PerfBoost.db.profile.PB_ShowAllPlayers = false
|
||||
PerfBoost.db.profile.PB_HideAllPlayers = false
|
||||
SetCVar("PB_ShowAllPlayers", "0")
|
||||
SetCVar("PB_HideAllPlayers", "0")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Normal player rendering enabled")
|
||||
end
|
||||
end
|
||||
|
||||
SLASH_PBTOGGLEPLAYERRENDERIST1, SLASH_PBTOGGLEPLAYERRENDERIST2 = '/pbtoggleplayerrenderist', '/pbtrd'
|
||||
function SlashCmdList.PBTOGGLEPLAYERRENDERIST(msg, editbox)
|
||||
local currentDist = PerfBoost.db.profile.PB_PlayerRenderDist
|
||||
|
||||
if PerfBoost.db.profile.previous_player_render_dist ~= nil then
|
||||
-- restore previous value
|
||||
local restoreValue = PerfBoost.db.profile.previous_player_render_dist
|
||||
PerfBoost.db.profile.PB_PlayerRenderDist = restoreValue
|
||||
SetCVar("PB_PlayerRenderDist", tostring(restoreValue))
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Player render distance restored to " .. restoreValue)
|
||||
PerfBoost.db.profile.previous_player_render_dist = nil
|
||||
else
|
||||
-- Save current value and set PB_PlayerRenderDist to 0
|
||||
PerfBoost.db.profile.previous_player_render_dist = currentDist
|
||||
PerfBoost.db.profile.PB_PlayerRenderDist = 0
|
||||
SetCVar("PB_PlayerRenderDist", "0")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00PerfBoost:|r Player render distance set to 0 (saved: " .. currentDist .. ")")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user