Returning an object from a member

Moderator: MacroQuest Developers

kellewic
a lesser mummy
a lesser mummy
Posts: 38
Joined: Tue Jun 08, 2004 2:27 am
Location: AZ

Returning an object from a member

Post by kellewic » Fri Jun 02, 2006 1:30 am

Ok, I have an objectdef member that returns another objectdef... problem is all the variables inside the returned objectdef get cleared upon returning it. I can reset them fine in client code and they operate normally, but if all the object member variables are cleared, they lose their state.

Actually 'cleared' is not the correct term... it seems all object-scoped variables declared get reset to their initial values when being returned from a member call.

Any ideas on why this might be happening? Thanks.

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Fri Jun 02, 2006 11:11 am

That depends on what exactly you're doing to return the object. If you use return and give it a value, the object that was available will be destroyed and replaced with one initialized with the given value. You can use return with no value if you need to return early and avoid destroying the object. What you need to do is use the "Returning" object that gets initialized when your member function is called (e.g. ${Returning.SomeVariable}). Note that this object will be initialized with empty parameters when the function enters scope.

It might be better to give me a code sample of what you're trying to do
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

kellewic
a lesser mummy
a lesser mummy
Posts: 38
Joined: Tue Jun 08, 2004 2:27 am
Location: AZ

Post by kellewic » Fri Jun 02, 2006 10:42 pm

Lax wrote: It might be better to give me a code sample of what you're trying to do
Ok, here is the code I am using:


Packs.inc

Code: Select all

objectdef InvPack
{
	variable byte slot

	method Open()
	{
		if (!${Window[pack${This.slot}].Open} && ${This.IsSlotValid})
		{
			nomodkey EQitemnotify pack${This.slot} rightmouseup
		}
	}

	method Close()
	{
		if (${Window[pack${This.slot}].Open} && ${This.IsSlotValid})
		{
			nomodkey EQitemnotify pack${This.slot} rightmouseup
		}
	}

	member ToText()
	{
		if (${This.IsSlotValid})
		{
			return pack${This.slot}
		}

		return pack99
	}

	member:string GetIndex(int ID)
	{
		if (${This.IsSlotValid} && ${ID} >= 1 && ${ID} <= ${InvSlot[${This.ToText}].Item.Container})
		{
			return ${InvSlot[${This.ToText}].Item.Item[${ID}]}
		}

		return NULL
	}

	member:bool IsSlotValid()
	{
		if (${This.slot} >= 1 && ${This.slot} <= 8 && ${InvSlot[pack${This.slot}].Item.Container} > 0)
		{
			return TRUE
		}

		return FALSE
	}
}


objectdef Inventory
{
	variable InvPack packs[8]

	method Initialize()
	{
		variable byte slot = 0

		while (${slot:Inc} <= 8)
		{
			packs[${slot}].slot:Set[${slot}]
		}
	}

	member:InvPack Pack(int x)
	{
		if (${x} >= 1 && ${x} <= 8)
		{
			return packs[${x}]
		}
	}

	method Open()
	{
		variable byte slot = 0

		while (${slot:Inc} <= 8)
		{
			packs[${slot}]:Open
		}
	}

	method Close()
	{
		variable byte slot = 0

		while (${slot:Inc} <= 8)
		{
			packs[${slot}]:Close
		}
	}
}
Here is a part of the script that uses Packs.inc. I only included the relevant pieces as it's pretty long (fishing.iss)

Code: Select all

variable string xmlSettingsFile = ${LavishScript.HomeDirectory}/Scripts/fishing/fishing.xml
variable collection:int items
variable collection:int poles
variable Inventory inventory

function main()
{
	ext -require ISXEQ
	call init
	call checkPole
}

function init()
{
	variable string poleSet = SettingXML[${xmlSettingsFile}].Set["Fishing Poles"]
	variable byte x = 0
	variable string myPole

	/* Gather up all fishing pole data */
	while (${x:Inc} <= ${${poleSet}.Keys})
	{
		poles:Set[${${poleSet}.Key[${x}]}, ${x}]
	}
}

function checkPole()
{
	if (!${InvSlot[mainhand].Item.Type(exists)} || ${InvSlot[mainhand].Item.Type.NotEqual[Fishing Pole]})
	{
		variable int poleSlot = 0

		if (${poles.FirstKey(exists)})
		{
			do
			{
				poleSlot:Set[${FindItem[=${poles.CurrentKey}].InvSlot}]

				if (${poleSlot} > 0)
				{
					Break
				}
			}
			while (${poles.NextKey(exists)})
		}

		variable InvPack ff = inventory.Pack[1]
		;ff.slot:Set[3]

		echo ${ff}

		;echo ${inventory.Pack[1]}
	}
}
checkPole() is where I was going to open the inventory via the objectdefs and get my fishing pole and do the necessary swapping. It's not finished as I ran into the problem of not getting the actual InvPack I requested. The InvPack.slot always ends up as zero (default value).

I've tried implementing Inventory.Pack as a function as well and then using Return, but it always makes packs[x] a mutablestring so when I then try to call InvPack members, I get an error cause mutablestring doesn't have those members/methods.

Is it even possible to return an objectdef intact?

Thanks.

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Sat Jun 03, 2006 11:39 am

Is it even possible to return an objectdef intact?
Not in this fashion.

Code: Select all

   member:InvPack Pack(int x)
   {
      if (${x} >= 1 && ${x} <= 8)
      {
         return packs[${x}]
      }
   } 
Here's the thing. What you're ending up doing is creating a new InvPack object, and initializing it with the value "packs[${x}]", which might be packs[1] for example. Unless your InvPack object's Initialize function is going to handle a parameter equal to "packs[1]", this isn't going to work. This is exactly equivalent to the following:

Code: Select all

variable InvPack Returning=packs[1]
What you're wanting to do is pass the value by reference, not create a new object. To pass by reference, use the "variable" type, which can be initialized with the name of any currently in-scope variable. The variable can go out of scope, e.g. calling another function with a reference to a local variable works just fine. However, it will cause a crash if the variable was DESTROYED instead of simply being out of scope

Code: Select all

   member:variable Pack(int x)
   {
      if (${x} >= 1 && ${x} <= 8)
      {
         return packs[${x}]
      }
   } 
Also, you dont need to check if x is a valid value, unless you're going to specifically do something if it's not. Either way, it would be returning NULL from the function.

Code: Select all

  member:variable Pack(int x)
   {
         return packs[${x}]
   } 
packs[0] is NULL, and so is packs[9].
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

kellewic
a lesser mummy
a lesser mummy
Posts: 38
Joined: Tue Jun 08, 2004 2:27 am
Location: AZ

Post by kellewic » Sat Jun 03, 2006 4:22 pm

Lax wrote: What you're wanting to do is pass the value by reference, not create a new object. To pass by reference, use the "variable" type, which can be initialized with the name of any currently in-scope variable. The variable can go out of scope, e.g. calling another function with a reference to a local variable works just fine. However, it will cause a crash if the variable was DESTROYED instead of simply being out of scope

Code: Select all

   member:variable Pack(int x)
   {
      if (${x} >= 1 && ${x} <= 8)
      {
         return packs[${x}]
      }
   } 
Yes, that is exactly what I want.. a reference to the previously created InvPack... unfortunately I can't get it :)

I tried what you suggested above and it still doesn't work. Maybe I'm not doing the assignment right or something, but I can't even find a reference to the above syntax in any other code or docs so I'm kind of stabbing in the dark.

Hell, I just realized the following actually isn't even correct:

Code: Select all

    variable InvPack i = inventory.packs[2]
I failed to realize that the assignment really isn't an assignment, but equivalent to:

Code: Select all

    InvPack:Inventory[inventory.packs[2]]
which equals to 'inventory.packs[2]' being made a '0' since Initialize is expecting a byte. The following, I now realize is correct:

Code: Select all

    variable InvPack i = 2
This call:

Code: Select all

    inventory.Packs[2]
doesn't even work. Ends up giving me "Unknown command inventory.Packs[2]" so I am at a loss to figure out exactly how I get a reference to an objectdef via another objectdef. I can't assign it, I can't call it directly...

I can't really figure out what's going on... the following:

Code: Select all

	member:variable Pack(int x)
	{
		echo X: ${x}
		return packs[${x}]
	}
isn't even being called when I do:

Code: Select all

    echo ${inventory.Packs[2]}
There is not 'X: 2' being echo'd

I would expect ' echo ${inventory.Packs[2]}' to output 'pack2' via InvPack's GetText, which I assume is called when you echo an object kind of like Java's toString().

Sorry, but I'm kind of frustrated at the moment :) It just doesn't make sense to me. I mean I am no stranger to coding and I've tried every possible way I can think of to make this code work. I just want to abstract the long MQ2 calls into objectdefs so my actual code is easier to deal with.

Thanks for all your help so far. I hope the crash reports I send help. Just seems like the LavishScript isn't yet resilient to user idiocy :) Specifically when I try to call NextKey on an empty collection... it doesn't like that :) I have no doubt it will get there though.

iluvseq
Clueless Mudslinger
Posts: 269
Joined: Mon Apr 14, 2003 10:05 am

Post by iluvseq » Sat Jun 03, 2006 5:58 pm

kellewic wrote:I can't really figure out what's going on... the following:

Code: Select all

	member:variable Pack(int x)
	{
		echo X: ${x}
		return packs[${x}]
	}
isn't even being called when I do:

Code: Select all

    echo ${inventory.Packs[2]}
There is not 'X: 2' being echo'd

I would expect ' echo ${inventory.Packs[2]}' to output 'pack2' via InvPack's GetText, which I assume is called when you echo an object kind of like Java's toString().
You setup a member 'Pack' but are trying to test it by calling .Packs[] ?

ie: echo ${inventroy.Packs[2]} won't be calling the member Pack, so your echo X line won't get called...

I'm sure it's not entirely that simple, but it does look like part of the problem, from here...

kellewic
a lesser mummy
a lesser mummy
Posts: 38
Joined: Tue Jun 08, 2004 2:27 am
Location: AZ

Post by kellewic » Sat Jun 03, 2006 6:15 pm

iluvseq wrote: You setup a member 'Pack' but are trying to test it by calling .Packs[] ?

ie: echo ${inventroy.Packs[2]} won't be calling the member Pack, so your echo X line won't get called...

I'm sure it's not entirely that simple, but it does look like part of the problem, from here...
Yeah, I am retarded on that one. Code typo. When I correct it, it now gives:

Code: Select all

Could not initialize variable object for function return value
Dumping script stack
--------------------
-->C:/Program Files/InnerSpace/Scripts/Packs.inc:74 Atom00000328() {
C:/Program Files/InnerSpace/Scripts/fishing.iss:151 checkPole() inventory.Pack[2]:Open
C:/Program Files/InnerSpace/Scripts/fishing.iss:60 main() call checkPole