|Go to Page...|
|Thread Tools||Display Modes|
|07/06/21, 09:28 PM||#1|
How to get a PreHook or PostHook to work?
So I have a simple problem I'd like to solve.
When in Battlegrounds, I'd like the scoreboard to show both the account name and the character name, not just one or the other.
So a player would show up in the scoreboard as:
@someplayer (Some Character)
The battleground LUA code (https://esoapi.uesp.net/100035/src/i...board.lua.html) contains the following:
function Battleground_Scoreboard_Player_Row:UpdateRow() local data = self.data local primaryName = ZO_GetPrimaryPlayerName(data.displayName, data.characterName) local formattedName = zo_strformat(SI_PLAYER_NAME, primaryName)
If I wanted to just hook the Battleground_Scoreboard_Player_Row:UpdateRow function so that I could replace the call to ZO_GetPrimaryPlayerName with my own function, how do I do that?
Specifically, what I'm unclear on is in my function that is called, how do I have access to the data that the real Battleground_Scoreboard_Player_Row:UpdateRow function has? Because my function would replace that call to ZO_GetPrimaryPlayerName with my own code.
I hope this makes sense. This is opaque as there isn't much documentation.
|07/07/21, 01:22 AM||#2|
You need to find out what the "object" the "class" Battleground_Scoreboard_Player_Row is referencing to.
If e.g. Battleground_Scoreboard_Player_Row = ZO_Object or ZO_SubClass there will be some kind of global object like
BATTLEGROUND_KEYBOARD.list or similar where you will find the rows in.
e.g. see the class def
Most times it either defined in the XML files via the OnInitialization or within the lua file. at the bottom of the class/file
BATTLEGROUND_KEYBOARD = ZO_Battleground_Scoreboard_Player_Row:New(control) or similar.
Unfortunately it is using an object pool (a pool of controls that will be re-used, as the scrolling is not creating new controls but re-using other ones created before. e.. show 10 rows = create 10 controls. On scrolling re-assign row 11 to 1, 12 to 2 and so on.
There does not seem to exist and object variable you could hook into as all is local.
But the factory function PlayerRowFactory of the control pool is used within
So the created object of Battleground_Scoreboard_Alliance_Panel will have the rows within self.sortedPlayerRows
And this alliance panel will be created as a loop here:
And assigned to self.alliancePanels
where self = Battleground_Scoreboard_Fragment
And the global for that fragment is assigned here:
BATTLEGROUND_SCOREBOARD_FRAGMENT = Battleground_Scoreboard_Fragment:New(control)
So BATTLEGROUND_SCOREBOARD_FRAGMENT.alliancePanels contains the panels of the alliances.
And each alliancePanel should have a list of sortedPlayerRows.
You can use merTorchbug or zgoo addons to inspect the BATTLEGROUND_SCOREBOARD_FRAGMENT and click throught the attributes and tables below, e.g. the __index shows you the functions and attributes of the "classes" it derives from.
So you can check what each panels in BATTLEGROUND_SCOREBOARD_FRAGMENT.alliancePanels sortedPlayerRows looks like, and if the function
"UpdateRow" is given there.
If this is the case build some loops like this in the end
Could be that rowData contains a .control which actually is teh control of the row and you need to posthook into than then, instead of rowData.
Call these hooks on start of your addon or via a callback function to BATTLEGROUND_SCOREBOARD_FRAGMENT:StateChange
See the wiki:
You could also try to use a handler of the row to set the hook at
rowData (or rowData.control) :SetHandler("OnEffectivelyShown", function(rowControl)
--do your changes here
You could change rowControl.data.displayName or rowControl.data.characterName then to contain both, char and displayName according to your needs.
The normal UpdateRow function would use this then via ZO_GetPrimaryPlayerName and just output both.
But it could be that some other functions of the row will just overwrite your changes again then, as they get called after the handler OnEffectivelyShown was fired.
But also make sure the handler will only be added once as the controls are re-used via the control pool!
Maybe this all is not needed and you could even directly posthook into the "class" function like this:
SecurePostHook(Battleground_Scoreboard_Player_Row, "UpdateRow", yourcallbackfunc)
Sometimes ZOs also provides global funcitons like ZO_BattlegroundKeyboard_OnRowUpdate which reference these lines directly, so you are able to hook these directly
e.g. there exists ZO_Battleground_Scoreboard_Player_Row_OnMouseDown
Check the source files of the battleground how it is build and how to find the object to hook into:
Last edited by Baertram : 07/07/21 at 01:28 AM.
|07/07/21, 08:34 AM||#3|
Baertram, I greatly appreciate your detailed response.
I'm still digesting it, but it's clear that I would have been flailing trying to figure out how this works, so thanks so much for sharing your knowledge generously!
|07/08/21, 08:44 AM||#4|
You can try this approach instead of hooks:
I don't even know if it'll work, but theoretically it should Unfortunately, hooks have very limited use, so if you want to change ZOS code, then you'll probably need to do it the "dirty" way.
|07/08/21, 11:40 AM||#5|
Yes, it should work as well. But I'd always prefer the secure post hook instead of overwriting the code in total.
It should do the trick to change the contents of the name label without breaking other code that prehooks the same variable e.g.
Depending on the load order of the addons you use this is more stable, or at least does not break other addons.
But depending on the use case andy.s is correct. You often cannot achieve the stuff you want with a hook and need to overwrite the functions too.
|ESOUI » Developer Discussions » General Authoring Discussion » How to get a PreHook or PostHook to work?|