Thread Tools Display Modes
09-06-15, 08:52 AM   #1
Nikita S. Doroshenko
A Cyclonian
 
Nikita S. Doroshenko's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2015
Posts: 45
Is it OK to copy Blizzard functions and hooksecure their function with tweaked copy?

I want to change Blizzard's function FriendsFrame_UpdateFriends() to add my buttons in to each frame of long scroll-able list of friends.

So i made hooksecurefunc("FriendsFrame_UpdateFriends", FriendsFrame_UpdateFriendsCopy)

FriendsFrame_UpdateFriendsCopy() is copy of FriendsFrame_UpdateFriends(), but with a few new lines of code.

Is it OK to do so, or is there better way to bulk change each frame of long scroll-able list? because i think hooksecure function is not same for future proof (for future updates).

PS I tried to make for loop for this scroll-able frame to manually attach my buttons in to each frame of scroll-able frame, but this buttons looks hardcoded, and i can't controll them regardless of hidden parent frames parameters that are only available in FriendsFrame_UpdateFriends().

Last edited by Nikita S. Doroshenko : 09-06-15 at 08:58 AM.
  Reply With Quote
09-06-15, 10:24 AM   #2
Nimhfree
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 267
The thing to remember is when you hook a function you are really just adding your function to be called after Blizzard's function is called. So, you typically would not repeat what Blizzard is doing in your function.

If you want to do something before a Blizzard function does its work you can replace the Blizzard function using a technique where you get the pointer to the Blizzard function, then define your function with the same name as the Blizzard function to implement your new code, and have your code then call the original Blizzard function. This technique can be used to do other things like control whether you even want to call the original Blizzard function as well.

I have not looked specifically at what you are trying to do, but sometimes you need not replace or alter any Blizzard function. You might be able to add items to a Blizzard data structure, or some other technique that allows you to get your data into the Blizzard system without touching the actual routines that manipulate that data. You just need to investigate how things are done and the best way to augment that system.
  Reply With Quote
09-07-15, 12:52 AM   #3
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
It sounds like you do want to hook the function, but you don't want your hook function to be a copy of the original function. Your hook function should only do whatever needs to be done in addition to what the original function already does. For example, if you wanted to show a button on each friend that you could click to whisper that friend, but hide the button for offline friends, you could do this:

lua Code:
  1. local function whisperButton_OnClick(self)
  2.     if self:GetParent().buttonType == FRIENDS_BUTTON_TYPE_BNET then
  3.         ChatFrame_SendSmartTell(self.friendName)
  4.     else
  5.         ChatFrame_SendTell(self.friendName)
  6.     end
  7. end
  8.  
  9. local function whisperButton_OnEnter(self)
  10.     GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT")
  11.     GameTooltip:SetText("Click to whisper " .. self.friendName)
  12. end
  13.  
  14. hooksecurefunc("FriendsFrame_UpdateFriends", function()
  15.     local friends = FriendsFrameFriendsScrollFrame.buttons
  16.     for i = 1, #friends do
  17.         local friend = friends[i]
  18.         if friend:IsShown() then
  19.             -- This friends list row is displayed.
  20.             -- Create a whisper button if this row doesn't have one already.
  21.             if not friend.whisperButton then
  22.                 local whisperButton = CreateFrame("Button", nil, friend, "UIPanelButtonTemplate")
  23.                 whisperButton:SetScript("OnClick", whisperButton_OnClick)
  24.                 whisperButton:SetScript("OnEnter", whisperButton_OnEnter)
  25.                 whisperButton:SetScript("OnLeave", GameTooltip_Hide)
  26.                 whisperButton:SetSize(26, 26)
  27.                 whisperButton:SetText("W")
  28.                 friend.whisperButton = whisperButton
  29.             end
  30.             -- Update the whisper button.
  31.             local friendName, isOnline, _
  32.             if friend.buttonType == FRIENDS_BUTTON_TYPE_BNET then
  33.                 -- Battle.net friends, move the button left of the game icon.
  34.                 _, friendName, _, _, _, _, isOnline = BNGetFriendInfo(friend.id)
  35.                 friend.whisperButton:SetPoint("RIGHT", friend.gameIcon, "LEFT")
  36.             else
  37.                 -- Regular friend, move the button to the right.
  38.                 friendName, _, _, _, isOnline = GetFriendInfo(friend.id)
  39.                 friend.whisperButton:SetPoint("RIGHT", friend)
  40.             end
  41.             -- Show or hide the whisper button based on the friend's online status.
  42.             if isOnline then
  43.                 friend.whisperButton.friendName = friendName
  44.                 friend.whisperButton:Show()
  45.             else
  46.                 friend.whisperButton:Hide()
  47.             end
  48.         elseif friend.whisperButton then
  49.             -- This friends list row is not displayed.
  50.             -- Hide its whisper button if it has one.
  51.             friend.whisperButton:Hide()
  52.         end
  53.     end
  54. end)
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
09-07-15, 10:35 AM   #4
Nikita S. Doroshenko
A Cyclonian
 
Nikita S. Doroshenko's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2015
Posts: 45
Originally Posted by Phanx View Post
It sounds like you do want to hook the function, but you don't want your hook function to be a copy of the original function. Your hook function should only do whatever needs to be done in addition to what the original function already does. For example, if you wanted to show a button on each friend that you could click to whisper that friend, but hide the button for offline friends, you could do this:

lua Code:
  1. local function whisperButton_OnClick(self)
  2.     if self:GetParent().buttonType == FRIENDS_BUTTON_TYPE_BNET then
  3.         ChatFrame_SendSmartTell(self.friendName)
  4.     else
  5.         ChatFrame_SendTell(self.friendName)
  6.     end
  7. end
  8.  
  9. local function whisperButton_OnEnter(self)
  10.     GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT")
  11.     GameTooltip:SetText("Click to whisper " .. self.friendName)
  12. end
  13.  
  14. hooksecurefunc("FriendsFrame_UpdateFriends", function()
  15.     local friends = FriendsFrameFriendsScrollFrame.buttons
  16.     for i = 1, #friends do
  17.         local friend = friends[i]
  18.         if friend:IsShown() then
  19.             -- This friends list row is displayed.
  20.             -- Create a whisper button if this row doesn't have one already.
  21.             if not friend.whisperButton then
  22.                 local whisperButton = CreateFrame("Button", nil, friend, "UIPanelButtonTemplate")
  23.                 whisperButton:SetScript("OnClick", whisperButton_OnClick)
  24.                 whisperButton:SetScript("OnEnter", whisperButton_OnEnter)
  25.                 whisperButton:SetScript("OnLeave", GameTooltip_Hide)
  26.                 whisperButton:SetSize(26, 26)
  27.                 whisperButton:SetText("W")
  28.                 friend.whisperButton = whisperButton
  29.             end
  30.             -- Update the whisper button.
  31.             local friendName, isOnline, _
  32.             if friend.buttonType == FRIENDS_BUTTON_TYPE_BNET then
  33.                 -- Battle.net friends, move the button left of the game icon.
  34.                 _, friendName, _, _, _, _, isOnline = BNGetFriendInfo(friend.id)
  35.                 friend.whisperButton:SetPoint("RIGHT", friend.gameIcon, "LEFT")
  36.             else
  37.                 -- Regular friend, move the button to the right.
  38.                 friendName, _, _, _, isOnline = GetFriendInfo(friend.id)
  39.                 friend.whisperButton:SetPoint("RIGHT", friend)
  40.             end
  41.             -- Show or hide the whisper button based on the friend's online status.
  42.             if isOnline then
  43.                 friend.whisperButton.friendName = friendName
  44.                 friend.whisperButton:Show()
  45.             else
  46.                 friend.whisperButton:Hide()
  47.             end
  48.         elseif friend.whisperButton then
  49.             -- This friends list row is not displayed.
  50.             -- Hide its whisper button if it has one.
  51.             friend.whisperButton:Hide()
  52.         end
  53.     end
  54. end)
This is awesome example! Thank you Phanx!

Only thing I can't understand, is how to update this whisperButton on frame scroll. The main problem is that when i scroll down, the buttons are not changes, and they only changes when FriendsFrame_UpdateFriends() function triggers. And this function triggers only when someone login/logout.

I search blizzard code in FriendsFrame.lua for scroll update function, only found this line of code:

Lua Code:
  1. function FriendsFrame_OnLoad(self)
  2. -- ...
  3.     local scrollFrame = FriendsFrameFriendsScrollFrame;
  4.     scrollFrame.update = FriendsFrame_UpdateFriends;
  5.     FriendsFrameFriendsScrollFrameScrollBarTrack:Hide();
  6.     FriendsFrameFriendsScrollFrameScrollBar.doNotHide = true;
  7.     HybridScrollFrame_CreateButtons(scrollFrame, "FriendsFrameButtonTemplate");
  8. -- ...
  9. end

Can't figure out by myself, how to apply update for this buttons each time user uses scroll. Will appreciate for your help.
  Reply With Quote
09-09-15, 11:59 PM   #5
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Try adding:

Code:
FriendsFrameFriendsScrollFrame.update = function() return FriendsFrame_Update() end
at the end of your code.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
09-10-15, 04:05 AM   #6
Nikita S. Doroshenko
A Cyclonian
 
Nikita S. Doroshenko's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2015
Posts: 45
Originally Posted by Phanx View Post
Try adding:

Code:
FriendsFrameFriendsScrollFrame.update = function() return FriendsFrame_Update() end
at the end of your code.
Thank you Phanx! I didn't realized that one line of code could fix this! I really should spend more time on learning and understanding how functions works with each other and how to manipulate them.

i just want to add, that I changed FriendsFrame_Update() to FriendsFrame_UpdateFriends() because first one FriendsFrame_Update() only works when user scroll with mouse wheel, but while dragging Scroll Thumb, frame was lagging like hell, so I changed it to FriendsFrame_UpdateFriends().

Everything looks and works perfectly! You saved me many hours! I very appreciate your help Phanx!

PS. Unfortunately after testing this method uses lot's on CPU power, and scrolling up and down friend list, makes my addon worst cpu efficient, not sure if it's normal for such a thing, but i'll try to think how to optimize it, if i'll find something i'll post solution here, maybe it's just not possible.

Last edited by Nikita S. Doroshenko : 09-10-15 at 04:15 AM.
  Reply With Quote
09-16-15, 04:24 PM   #7
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Nikita S. Doroshenko View Post
Unfortunately after testing this method uses lot's on CPU power, and scrolling up and down friend list, makes my addon worst cpu efficient, not sure if it's normal for such a thing, but i'll try to think how to optimize it, if i'll find something i'll post solution here, maybe it's just not possible.
It depends entirely on what you're doing inside your function. Make sure you're not re-creating your objects every time the function runs; that seems like the most likely cause for excessive CPU usage here.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Is it OK to copy Blizzard functions and hooksecure their function with tweaked copy?


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off