Elitist Jerks
Register
Blogs
Forums


Go Back   Elitist Jerks » User Interface and AddOns

Reply
 
LinkBack Thread Tools
Old 12/10/07, 3:46 PM   #1
 sp00n
banned
 
Night Elf Rogue
 
Wrathbringer (EU)
[Help] Fixing an old addon with tainting problems

Hi there together.

Since Blizzard added the "Interface action failed because of an addon" message and despite having run WoWAceUpdater several times since then, I still encountered this error and finally decided to see by what it is caused.
So I went with /console taintLog 1 and after some fights looked at the taint.log file, which presented me with quite a lot of lines. Many of them had a reference to Omen and VisualThemes, but I was quite confident that they weren't the real cause of these messages, but rather a side effect.
I think I was able to track it down to my beloved ZAutoStrip, a really really old addon which let's me unequip my weapons in combat (before a wipe), or unequip everything as soon as I drop combat.
Now I admit that the unequip everything option has somewhat lost it's beauty since you stay in combat all the time during a bossfight rather than having one second of out of combat time when vanishing, but I still like the opportunity to unequip my weapons with one single click.

The addon still works flawlessly, but I fear it is tainting some functions, by the unsecured use of the PickupInventoryItem (and PickupContainerItem?) call.

I was trying to fix this by myself, but so far wasn't successful in doing so, so I'd like to ask for some help here. Of course, if you know another addon with the same functionality - simple one click to strip all weapons in combat, and maybe strip everything when dropping out of combat, with one click and without the need to place a macro in an action bar button - I'd take that as well.

Here are some code excerpts, where I think the tainting begins:
function ZAutoStrip_OnEvent()
[...]
	elseif (event == "PLAYER_REGEN_ENABLED" and ZAutoStripAutoStrip) then
		ZAutoStripUnequipValuables()
	end
end
function ZAutoStripUnequipValuables()
	ZAutoStripAutoStrip = nil;
	ZAutoStripAutoCast:Hide();
	local count = 1;
	local a = PickupContainerItem;
	for i=1,GetContainerNumSlots(0) do
		if not GetContainerItemLink(0,i) then
			if count <= 11 then
				if ZAutoStripUnequipValuables2(count) then
					i = i - 1;
				else
[...]
function ZAutoStripUnequipValuables2(i)
	local a = PickupInventoryItem;
	local b = GetInventoryItemLink;
	if i == 1 then
		if not b("player",16) then
			return true;
		end
		a(16);	-- Main Hand
	elseif i == 2 then
[...]
I tried multiple things, but none of them worked:

1)
I placed two lines at the end of the lua files, namely:
hooksecurefunc("PickupInventoryItem", ZAutoStripUnequipValuables);
hooksecurefunc("PickupContainerItem", ZAutoStripUnequipValuables2(i));


This seemed to work, but freezed my WoW when I clicked it (out of combat). My equipment was placed in my bags though when I logged back in. :x


2)
In ZAutoStripUnequipValuables I replaced every instance of
if ZAutoStripUnequipValuables2(count) then
with
if hooksecurefunc("PickupInventoryItem", ZAutoStripUnequipValuables2(count)) then

Result: LUA error, addon wouldn't load.


3)
In ZAutoStrip_OnEvent() I replaced
ZAutoStripUnequipValuables()
with
hooksecurefunc("PickupInventoryItem", ZAutoStripUnequipValuables);

Result: Addon loads, works fine, even in combat, but I still receive "Interface action failed" errors.


Could someone lend my a hand, or point me to a tutorial on how to fix this? I couldn't find a reasonable explanation how to fix an addon, besides "use hooksecurefunc!", which basically wasn't a too great help, as you can see by my attempts.


Offline
Reply With Quote
Old 12/11/07, 5:31 AM   #2
koaschten
In the rear with the gear!
 
koaschten's Avatar
 
Worgen Rogue
 
Auchindoun (EU)
I know you asked about fixing that particular addon, but i assume you already use outfitter, closetgnome or some similar addon. Why don't you simply create a gear set with empty weapon slots and the other slots flagged as "don't care about". Works like a charm for me with closetgnome.

How to get an Android Authenticator on your PC. (updated feb'11)

Germany Offline
Reply With Quote
Old 12/11/07, 8:50 AM   #3
 sp00n
banned
 
Night Elf Rogue
 
Wrathbringer (EU)
Originally Posted by koaschten View Post
I know you asked about fixing that particular addon, but i assume you already use outfitter, closetgnome or some similar addon. Why don't you simply create a gear set with empty weapon slots and the other slots flagged as "don't care about". Works like a charm for me with closetgnome.
Yeah I though about that, but I'd require two clicks for my wardrobe to have that functionality (one right click on the button, and then choosing the right outfit), plus the additional chance of fucking up and choosing the wrong itemset when things have to be fast (you know, 500 hp, no cooldown available, and a DoT happily ticking on you).


Offline
Reply With Quote
Old 12/11/07, 8:57 AM   #4
xiaoxin21
Don Flamenco
 
No account
Human Mage
 
No WoW Account
Not too sure about outfitter as I dont use it. However for Closet Gnome with the Closet Gnome OhNoes addon, you can set auto unequip your gear at a certain % of your hp. Also by creating an empty gear set in Closet Gnome, you can bind it to a key and just press it when you want to unequip. So there is no need for 2 clicks

Offline
Reply With Quote
Old 12/11/07, 9:00 AM   #5
Lybohske
Glass Joe
 
Tauren Hunter
 
Khadgar
Most wardrobe mods allow you to script changing item sets, ClosetGnome does and ItemRack did the last time I used it. I use the following macro with ClosetGnome:

/cast Feign Death
/script ClosetGnome:WearSet('Naked')

You may also want to look at ZHunterMod, it is by the same author of zAutoStrip and actually contains zAutoStrip. It appears Zanzer just no longer keeps them separate.

Offline
Reply With Quote
Old 12/11/07, 9:27 AM   #6
Caldar
Asleep at the wheel...
 
Caldar's Avatar
 
Human Priest
 
Feathermoon
Originally Posted by koaschten View Post
I know you asked about fixing that particular addon, but i assume you already use outfitter, closetgnome or some similar addon. Why don't you simply create a gear set with empty weapon slots and the other slots flagged as "don't care about". Works like a charm for me with closetgnome.

ClosetGnome_OhNoes does exactly what your trying to achieve. If you don't already use CG, perhaps you can use the code for suggestions.

Offline
Reply With Quote
Old 12/11/07, 11:56 AM   #7
Dralmoo
Don Flamenco
 
Orc Hunter
 
Shadowmoon
Maybe too offtopic for this forum but even if the simplest solution is to use something else, I'd be interested in an answer to this as an example of a more general guide to retrofitting old addons, if anyone can provide one

Offline
Reply With Quote
Old 12/12/07, 3:37 AM   #8
 sp00n
banned
 
Night Elf Rogue
 
Wrathbringer (EU)
Thank you for all the responses, however I wanted to preserve the functionality of one separate button for unequipping my weapons/equipment, without having to use a macro or filling up an action bar slot.

Originally Posted by Lybohske View Post
You may also want to look at ZHunterMod, it is by the same author of zAutoStrip and actually contains zAutoStrip. It appears Zanzer just no longer keeps them separate.
I think this is the solution for me. However Zanza, the author, did not use secure hooks in his updated version, but simply limited the functionality to only weapons while in combat (as opposed to everything as in my antique version).


The point still stands though, and here I agree with Dralmoo, it would be good to know how you would have fixed such an addon, in case I stumble across another one and/or ZAutoStrip wasn't the only reason for the tainting messages.


Offline
Reply With Quote
Old 12/13/07, 7:23 AM   #9
sarf
Great Tiger
 
sarf's Avatar
 
Fars
Human Paladin
 
No WoW Account (EU)
First the solution...

WARNING:
Total drycode here. Not tested on animals. Please refrain from using this to control nuclear reactors and/or raid main tanks.
Thank you.

ZAutoStrip actually does not seem to do any tainting in the relevant sections.

However, what it does is that it tries to unequip everything instead of just main hand, off hand and ranged.

I have recoded some stuff that (ought to) unequip and - potentially - re-equip your weapons.

Here are some code that should make it possible to unequip and re-equip your stuff:

ZAutoStripLastFreeSlot = {};

ZAutoStripRemovedList = {};
ZAutoStripInventorySlots = { 16, 17 };

-- Note that totems/relics/librams lack durability, so those do not need to be unequpped.
local c = nil;
_, c = GetClass("player");
if ( c ~= "SHAMAN" ) and ( c == "PALADIN" ) and ( c == "DRUID" ) then table.insert(ZAutoStripInventorySlots, 18); end

function ZAutoStrip_Remove()
	ZAutoStripLastFreeSlot.bag = nil;
	ZAutoStripLastFreeSlot.slot = nil;
	local b, s;
	for key, value in pairs(ZAutoStripInventorySlots) do
		if ( ZAutoStrip_HasSlot(value) ) then
			b, s = ZAutoStrip_RemoveSlot(value);
			if ( not b ) then
				-- message about failing to remove slot due to lack of inventory space
				return;
			else
				local arr = ZAutoStripRemovedList[value];
				if ( not arr ) then arr = {}; ZAutoStripRemovedList[value] = arr; end
				arr.b = b;
				arr.s = s;
			end
		end
	end
end

function ZAutoStrip_FindFreeSlot()
	local bag = 0;
	local slot = 1;
	if ( ZAutoStripLastFreeSlot.bag ) and ( ZAutoStripLastFreeSlot.slot ) then
		bag = ZAutoStripLastFreeSlot.bag;
		slot = ZAutoStripLastFreeSlot.slot + 1;
	end
	local b, s = ZAutoStrip_FindFreeSlot_Inner(bag, slot);
	if ( not b ) or ( not s ) and ( ( bag > 0 ) or ( slot > 1 ) ) then
		b, s = ZAutoStrip_FindFreeSlot_Inner(0, 1, bag, slot);
	end
	if ( b ) and ( s ) then
		ZAutoStripLastFreeSlot.bag = b;
		ZAutoStripLastFreeSlot.slot = s;
	end
	return b, s;
end

function ZAutoStrip_FindFreeSlot_Inner(startBag, startSlot, endBag, endSlot)
	if ( not endBag ) then endBag = 4; end
	local curBag, curSlot;
	local maxSlot = 0;
	for curBag = startBag, 4 do
		maxSlot = GetContainerNumSlots(curBag);
		if ( endBag == curBag ) and ( endSlot ) then
			maxSlot = endSlot;
		end
		for curSlot = startSlot, maxSlot do
			if ( not GetContainerItemLink(curBag, curSlot ) then
				return curBag, curSlot;
			end
		end
		startSlot = 1;
	end
end

function ZAutoStrip_RemoveSlot(slot)
	local b, s = ZAutoStrip_FindFreeSlot();
	if ( b ) and ( s ) then
		PickupInventoryItem(slot);
		PickupContainerItem(b, s);
		return b, s;
	end
end

function ZAutoStrip_HasSlot(slot)
	return ( GetInventoryItemLink("player", slot) ~= nil );
end

function ZAutoStrip_PutOn()
	local bag, slot;
	for key, value in pair(ZAutoStripRemovedList) do
		bag = value.b;
		slot = value.s;
		if ( bag ) and ( slot ) then
			PickupContainerItem(bag, slot);
			PickupInventoryItem(key);
			ZAutoStripLastFreeSlot.bag = bag;
			ZAutoStripLastFreeSlot.bag = slot;
			value.b = nil;
			value.s = nil;
		end
	end
end

What you ought to change in that file is this part:
function ZAutoStripUnequipValuables()
	ZAutoStripAutoStrip = nil;
	ZAutoStripAutoCast:Hide();
	...
to

function ZAutoStripUnequipValuables()
	ZAutoStripAutoStrip = nil;
	ZAutoStripAutoCast:Hide();
	ZAutoStrip_Remove();
The code still lacks some safeguards - not putting on stuff if you have put on stuff since unequipping, checking so that what is in the bag and slot is actually what was unequipped etc but that is left as an exercise for the reader.

Next post: Secure function hooking and you!

Offline
Reply With Quote
Old 12/13/07, 7:44 AM   #10
sarf
Great Tiger
 
sarf's Avatar
 
Fars
Human Paladin
 
No WoW Account (EU)
... and then the lecture

All right, so what is secure function hooking and why is it used?

What is taint?

I have only a cursory view of this, being mainly a pre-2.0 addon author (and not doing much of anything except non-tainting-related coding in 2.0+, mainly my SpellChecker2 - aka "Rose Tinted Glasses for the Grammatically Sensitive").

First, a small history lesson - in the times of yore, when Frost Mages ruled the damage meters in MC and Alterac Valley was a longlasting affair, people hooked Blizzard functions for fun and profit. This was done for one of two reasons - changing their functionality ("no, you may NOT cancel your flask buff!") and for informational purposes ("so, trying to cancel Flask buffs, are we? <sends a whisper to raid leader about sexual preference>").

Secure function hooking (hooksecurefunc) is used for the latter of these - when you want to be notified that a certain function has been called and with what parameters it was called - for instance, that a certain message has been sent in a whisper by the user.

You can no longer prevent Blizzard functions from doing their stuff without tainting them.

However, a quick info about what ZAutoStrip - it does not seem to actually hook any secure functions, it merely tries to use them.

Writing "local a = PickupContainerItem;" simply means that doing "a(16)" is the same as writing "PickupContainerItem(16)" - my assumption is that ZAutoStrip was first conceived as a Blizzard macro, where the amount of characters you use has an impact.
Or perhaps the author likes short function names.

In any case, the code you have cited should not cause any taint.

Do note, however, that what
hooksecurefunc("PickupInventoryItem", ZAutoStripUnequipValuables);
does is to make the ZAutoStripUnequipValuables function be called after every call to PickupInventoryItem. This is probably a bad thing.


Over to "taint" and why it is bad (and not just for the people allergic to demons).

Taint is imposed when a non-Blizzard-certified piece of code modifies a Blizzard-certified piece of code. The places where changes are made are flagged as "tainted" (as is, incidentally, all non-Blizzard-certified code AFAIK).

When the LUA interpreter runs a chunk of code, and it encounters a tainted piece, all code that runs from then on in that particular chunk is considered to be in a tainted state (and can no longer do no-taint-only cool stuff).

Example (non-real) piece of Blizzard code:
function Blizzard_CoolStuff(a)
	if ( Blizzard_DoFunkyCheck() ) and ( a == 2 ) then 
		Blizzard_PerformCoolStuff(a);
	end
	Blizzard_PokeFunAtRaiders();
end
Now, if we change Blizzard_DoFunkyCheck with our evil, tainted paw, Blizzard_PerformCoolStuff (which requires non-tainted state) will not work nor will Blizzard_PokeFunAtRaiders.

If, however, Blizzard_PerformCoolStuff is tainted, but actually not used (a == 1), then Blizzard_PokeFunAtRaiders can be run without any taint.

I hope this has shed some light on taint and secure function hooking.

If I am wrong in my assumptions, then I would ask that someone with more knowledge mock me and respond with a better explanation.

Offline
Reply With Quote
Old 12/14/07, 8:23 PM   #11
valex
Glass Joe
 
Undead Priest
 
Spinebreaker
Outfitter. The clothing mod, allows you to create partial sets... So lets say, for instance, you want to leave everything on your toon on, but unequip your weapons.

Step 1. You simply create an outfit called "Wiping", check the weapons and unequip them, thus saving the "Wiping" outfit and allowing it to just remove your weapons when you select that outfit. Then you hit the down arrow next to you new outfit and select Keybinding, put it to whichever outfit you wish to bind it (outfit 1) and proceed to step 2.

Step 2. You wanted to be able to do this in 1 keypress. Goto your Keybindings interface in the main menu, scroll down until you see "Outfitter" and in Outfit 1 just bind a key. Done.

Win Win, you get an awesome addon and you dont have to modify ancient code.

Val

Offline
Reply With Quote
Reply

Go Back   Elitist Jerks » User Interface and AddOns

Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
NPC problems world User Interface and AddOns 3 11/30/07 1:24 PM
[Warlock] Fixing my PVE gear's gems Isildien The Dung Heap 4 06/26/07 7:44 AM
Fixing Protection Potions for TBC Zarel Public Discussion 28 04/12/07 2:52 PM