Help! RemoveAddedForm bugged, fails after first use; data co

Post » Tue Jun 19, 2012 1:28 pm

I am experiencing some very odd and potentially seriously bugged behavior with the formlist function RemoveAddedForm. In a nutshell, it only seems to be working the first time it is called on a formlist; subsequent calls seem to lead to data corruption. Hopefully someone will be able to tell me that I'm being an idiot and doing something wrong.

The details. I have the following script on several non-respawning chests. In the ESP, the chests are empty, and the basic idea is that the player can use a chest to add and remove apparel/armor, and then the formlist passed as a property will update accordingly. There's some other code because my follower won't wear elven gear or heavy armor for personal reasons, but I think it is ignorable--the main issue seems to be with the OnItemRemoved event, where I've added some debug messaging.

Scriptname ESFAelaOutfitChestScript extends ObjectReference  FormList Property OutfitFList AutoKeyword[] Property KeywordElvenGear AutoKeyword Property KeywordHeavyGear AutoEvent OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)	if akBaseItem as Armor		Bool bIsOkay = true		Int index = 0		while index < KeywordElvenGear.Length			if akBaseItem.HasKeyword(KeywordElvenGear[index])				Debug.MessageBox("\"I don't use that fancy elven kit. Give me gear made of hide from the beasts of Skyrim, and fine northern steel.\"")				bIsOkay = false				index = KeywordElvenGear.Length			endif			index = index + 1		endwhile		if akBaseItem.HasKeyword(KeywordHeavyGear)			Debug.MessageBox("\"That's not my style. I fight best when I'm light on my feet.\"")			bIsOkay = false		endif		if bIsOkay == false			if akItemReference == None				Self.RemoveItem(akBaseItem, aiItemCount, true, Game.GetPlayer())			else				Self.RemoveItem(akItemReference, aiItemCount, true, Game.GetPlayer())			endif		else			if OutfitFList.HasForm(akBaseItem as Form) == false				OutfitFList.AddForm(akBaseItem as Form)			endif		endif	else		if akSourceContainer == Game.GetPlayer()			Debug.Notification("Only base armor and clothing (unenchanted or improved by the player) can be added.")		endif		if akItemReference == None			Self.RemoveItem(akBaseItem, Self.GetItemCount(akBaseItem), true, Game.GetPlayer())		else			Self.RemoveItem(akItemReference, 1, true, Game.GetPlayer())		endif	endifEndEventEvent OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)	Debug.MessageBox("Remove triggered!")	if OutfitFList.HasForm(akBaseItem as Form)		OutfitFList.RemoveAddedForm(akBaseItem as Form)		Debug.MessageBox("Item Removed: " + akBaseItem)	endif	if OutfitFList.HasForm(akBaseItem as Form)		Debug.MessageBox("Not removed!")	else		Debug.MessageBox("Removed!")	endifEndEvent

I've also created a messagebox that uses GetSize on the formlists, and lists the forms they contain.

Okay, so when I first add items to the chests, everything works fine, and persists that way betwen saved games. In this screenshot made today I've just loaded a save made a day or two ago, after I added the initial items:

http://steamcommunity.com/profiles/76561198044640415/screenshot/524906243885237879/

However, when I try to alter the gear in one of the chests, strange things begin to happen. The "Remove triggered!" and "Item Removed:" messages always appear, but only the first item--it doesn't matter which--that I remove triggers the "Removed!" message; subsequent items taken trigger "Not removed!" For example, immediately after I took the previous screenshot, I tried removing all three items in the Outfit 1 chest and adding three new ones. What resulted was this:

http://steamcommunity.com/profiles/76561198044640415/screenshot/524906243885236174/

Five items in the formlist. (And no relevant error messages in the Papyrus log.)

Bad enough, but I then immediately made a save, quit the game, restarted and loaded that save, and I saw this:

http://steamcommunity.com/profiles/76561198044640415/screenshot/524906243885224330/

Outfit 1 had been completely corrupted--GetSize returned 6 items but somehow only 5 were displayable, and those 5 had little relation to what had been in the list before the save. (Locations?!?)

So...what is going on?
User avatar
Amanda Furtado
 
Posts: 3454
Joined: Fri Dec 15, 2006 4:22 pm

Post » Tue Jun 19, 2012 6:43 pm

I doubt this is whats causing the problem, but you shouldn't need to do this
(akBaseItem as Form)
since akBaseItem is already a form, casting it to a form is redundant (maybe script breaking?)
User avatar
Nuno Castro
 
Posts: 3414
Joined: Sat Oct 13, 2007 1:40 am

Post » Tue Jun 19, 2012 6:36 pm

Thanks for the reply, and it's a good thought. However, all those casts are something I added only after noticing the problems, and as far as I can tell the casting doesn't cause any new problems (as indeed it shouldn't): there are no errors in the log, and the code works as expected--up until I try to use RemoveAddedForm at least.

(The casts are there because when I started examining the formlists, I saw that a few items were type Armor rather than type Form. An early hypothesis I had was that RemoveAddedForm was failing because of the type differences, so I first tried to make sure everything I added and tried to remove was a Form. That didn't help, though.)
User avatar
Kelvin
 
Posts: 3405
Joined: Sat Nov 17, 2007 10:22 am

Post » Wed Jun 20, 2012 2:24 am

well if you want to get technical, everything in the game is a "form" since the Form script is the prime parent of all scripts in the game.

I haven't yet tried editing formlists on the fly...maybe something is going on when you remove a form that's in the middle of the list or something? Do formlists work like arrays in that the GetAt() address of a form doesn't change if another item is taken out that preceded it in the list, or would the items after the removed form automatically fill in the now empty slot and thus have their "GetAt()" address changed?
User avatar
Elizabeth Davis
 
Posts: 3406
Joined: Sat Aug 18, 2007 10:30 am

Post » Wed Jun 20, 2012 2:53 am

I don't think you can have empty entries in a formlist; removing an item should cause the items below it to move a spot up in the list. Unlike arrays, you don't need to define their size in advance.

If removing items from formlists is truly bugged, I may switch to using arrays...I think they should do what I need, I will just need to write some array management functions.
User avatar
Dorian Cozens
 
Posts: 3398
Joined: Sat May 26, 2007 9:47 am

Post » Tue Jun 19, 2012 6:32 pm

well if you want to get technical, everything in the game is a "form" since the Form script is the prime parent of all scripts in the game.
I thought this a while ago as well, but SmkViper corrected me. http://www.creationkit.com/Alias_Script and http://www.creationkit.com/ActiveMagicEffect_Script are also native "base" scripts.

Just a few irrelevant comments - you pretty much only ever need to use "Self" when passing that information to a function as a parameter, or if you need to cast the "Self" object to another type in order to call a function. The following two lines of code are exactly the same, except I don't know if the compiler's optimisations are good enough to make them as fast as one another:
Self.RemoveItem(akBaseItem, Self.GetItemCount(akBaseItem), true, Game.GetPlayer())
RemoveItem(akBaseItem, GetItemCount(akBaseItem), true, Game.GetPlayer())
And as cscottydont mentioned, you never need to cast an object to its current type. Casting it to a parent type is also usually not necessary, as the compiler can do this automatically. That's only necessary if you need to call a version of a function that's been overridden in a more derived type.

From what you saw, I'd say you're right that http://www.creationkit.com/RemoveAddedForm_-_FormList appears to be broken. It's only used once in Skyrim's vanilla scripts, in this line in MQ206ThroatoftheWorldTriggerScript.psc:
DisableList.RemoveAddedForm(akActionRef)
Given that it's never used in a way that would reveal that it's broken, I think it's not too unlikely that it is, in fact, broken.

One other approach you could try would be to use http://www.creationkit.com/Revert_-_FormList, and rebuild the list. It would probably be considerably slower, but might be good enough for your purposes.

Cipscis
User avatar
amhain
 
Posts: 3506
Joined: Sun Jan 07, 2007 12:31 pm

Post » Tue Jun 19, 2012 3:44 pm

Hi,
if can help you i made it an experiment :
I have 3 NPC and 3 different script :

NPC1 have this script attached :
Scriptname AI_ADD_FORMLIST2 extends ActorFormList Property AI_MEMORY_FL autoEvent OnInit()AI_MEMORY_FL.addform(SELF)registerforSingleupdate(20)EndEventEvent OnUpdate()debug.notification("Tolgo un inserimento")AI_MEMORY_FL.RemoveAddedForm(self)EndEvent

NPC2 and NPC3 this :


Scriptname AI_ADD_FORMLIST extends ActorFormList Property AI_MEMORY_FL autoEvent OnInit()AI_MEMORY_FL.addform(SELF)registerforupdate(60)EndEventint contEvent OnUpdate()cont += 1if cont == 1AI_MEMORY_FL.removeaddedform(SELF)elseAI_MEMORY_FL.addform(SELF)endifEndEvent

The third script is attached to a Quest, and is always running :


Scriptname AI_LIBRARY_TEST EXTENDS Quest conditionalFaction Property FazioneB autoActor Property AgenteGenerico autoFormList Property AI_MEMORY_FL autoint index = 0Event OnInit()registerForUpdate(30)debug.notification("Classe Inizializzata")EndEventEvent OnUpdate()debug.notification("Grandezza : " + AI_MEMORY_FL.GetSize())While (index < AI_MEMORY_FL.GetSize())debug.notification("Inserimento :  " + AI_MEMORY_FL.GetAt(index) )index += 1EndWhileEndEvent


- At first update the third script say correctly that there are 3 form in the list
-At second update the script notify that there are only 2 form in the list (the third one is been removed from NPC1 script)
- At third update the script notify that the formlist is empty (NPC2 and NPC3 were removed from the list)
-At fourth update the script notify that there are 2 form in the list (NPC2 and NPC3 have been added to the list again)

For what i see it seem that removeaddedform has worked as intended.
User avatar
Floor Punch
 
Posts: 3568
Joined: Tue May 29, 2007 7:18 am

Post » Tue Jun 19, 2012 5:48 pm

Thank you both for your help, Cipscis and marcaurelio745.

I'm not sure why your test case is working, marcaurelio745, and my case is not. Hmm. Maybe I am adding and removing items into and out of the formlist too quickly? I'll need to investigate it more.
User avatar
Aman Bhattal
 
Posts: 3424
Joined: Sun Dec 17, 2006 12:01 am

Post » Wed Jun 20, 2012 3:46 am

I don't think you can have empty entries in a formlist; removing an item should cause the items below it to move a spot up in the list. Unlike arrays, you don't need to define their size in advance.

If removing items from formlists is truly bugged, I may switch to using arrays...I think they should do what I need, I will just need to write some array management functions.

There's always Linked Lists (See my sig) - Created dynamically at runtime, no max size, other than render limits if you're using physical objects for the nodes,and they're near the player.
User avatar
trisha punch
 
Posts: 3410
Joined: Thu Jul 13, 2006 5:38 am

Post » Tue Jun 19, 2012 3:58 pm

Hey there. I also have the same very problem and I do think RemoveAddedForm is broken. I've made simple tests with it using only AddForm and RemoveAddedForm and I can't remove more than one form from the lists. It also corrupts data on save and sometimes crashes on load or when running RemoveAddedForm() on the list. It works alright to remove a single form. But that's about it.

Now i'll see if I can understand this linked list thing and see if it works for me. Or maybe arrays. *sigh*



EDIT:

Oh yeah, also it's worth to mention that, when working with a list containing 10 previously added forms (using the ck) and 10 forms added via AddForm(), I could remove the last form group one by one using RemoveAddedForm. But when I tried this with a list with 2 previously added forms and 10 forms added via AddForm(), I could remove only 2 of the last group of 10 using RemoveAddedForm(). So, there's either something really fishy about this function or it's just my noobness at work. Please let me know which is it! lol

If I missed any news on this bug - if it's a bug at all - let us know. If there's someone using RemoveAddedForm without problems, please let us know how! =)
User avatar
Beast Attire
 
Posts: 3456
Joined: Tue Oct 09, 2007 5:33 am


Return to V - Skyrim