Game Development Community

Local variable in console not working?

by EricCartman · in Technical Issues · 02/03/2005 (10:37 pm) · 18 replies

Hi,

I am having a strange problem.

When I type: echo(MissionCleanup.getCount); in console, it returns 4
but when I type: %count=MissionCleanup.getCount(); echo(%count); now it returns nothing...

Why?

Thanks

#1
02/03/2005 (11:49 pm)
Try using $count. I dont think the % sign variables persist in the console.
#2
02/03/2005 (11:54 pm)
Commands executed on the console "command line" are done so in "imediate mode"

Once the parser hits a ; it evaluates that command in it's own memory space and after it completes, cleans up the memory and returns control to check for a new command to evaluate. If there isn't one it ends.

So yes you can have many seperate commands executed on one "return key" in the console... but each one is performed seperatly in it's own call. So when the next command is parsed any local variable used goes away.
#3
02/04/2005 (3:23 am)
To expand on what Owen and Harold have already explained...


A "$" variable is normally called a "Global" variable but could also be accurately described as a "permenant" variable. It is global in the sense that any function can access it at any time no matter if the function is script or engine based. It is permenant in the respect that it stays in memory and retains it's data untill such time as it's deleted or muted and the data integrity is maintained untill such time as it is told to change it's data to something else. The data can be altered by you, the scripts, the engine, or even an outside source such as a web database or external application.

A "%" variable is normally called a "Local" or also correctly described as a "temporary" variable. It is local to the function that created it and will be parsed from memory at the termination of the function. If the data in a local is needed elsewhere it will be passed to another function which will form a new local to represent the passed data or it can be handed off to a global variable($) for storage till needed. It can be passed to both the scripts or the engine but ONLY during the time when the current function which created it is still being processed. A local cannot exist outside of a function because it will be parsed the instant it is created.


Although it is pointless to do it this way, this line...

echo(%count = missioncleanup.getcount());

would return the same data (the count of 4) as this line...

echo(missioncleanup.getcount());


However you could echo and set a global at the same time by using...

echo($count = missioncleanup.getcount());

because the parser would set the variable of $count to the missioncleanup group count and then it would echo the result to the console. But the $count variable would remain in memory despite the way it was declared in the echo.


You could also use these lines to create a boolean True/Flase checks in a similar fashion.

echo(missioncleanup.getcount() > 5);
echo(%count = missioncleanup.getcount() > 5);

Both would return a 0(zero == False) as the group count is 4 which is not greater than 5 and these lines...

echo(missioncleanup.getcount() < 5);
echo(%count = missioncleanup.getcount() < 5);

would both return a 1(one == True) because 4 is less than 5.


Many times the question "Which should I use where?" comes up regarding these two types of variables to which there is no one correct answer. The best answer I can give is to say that you should ALWAYS use local(%) variables everywhere untill such time when you realize that you need to hold onto data for an extended period of time. Extended time is defined as from the moment the current function terminates till such time as the data is no longer needed.
#4
02/04/2005 (2:53 pm)
Wow, thanks guys for the detail explanatation. So, is this temporary local variable thing only for the console commands, or is it the same for the scripts as well. For example, if I write a script called the testcmd.cs, and use local variables in there. would each variable disappear after each ";"?

THanks again
#5
02/04/2005 (3:04 pm)
@Eric: no, but they would "disappear" after the scope that they were declared in ended. For example, if you declare them at the very beginning of the function, they would disappear once the function ended. If you declared them within a { ... } block, they would be out of scope once the block ends.
#6
02/04/2005 (3:05 pm)
Gonzo's definition applies to TorqueScript in general... the console is unique in that after each ; the memory is cleaned... in script you could reference local (%) variables within that function... for example
function displayNum(%this)
{
     %num = 0;
     %num++;
     echo(%num);
}
this function would echo "1" to the console.
function displayNum(%this)
{
     %num = 0
     incrementNum();
     echo(%num);

}

function incrementNum(%this)
{
      %num++;
}
this would only display "0"...

function displayNum(%this)
{
     %num = 0
     %num = incrementNum(%num);
     echo(%num);

}

function incrementNum(%this, %num)
{
      %num++;
      return %num;
}
this would display "1" however
#7
02/04/2005 (7:06 pm)
Nice work Matthew. But your last function will return a "-1" because you were using a namespace method and your data is in the wrong spot.


Just to add a few more examples to the scope of this discussion so that the difference between a global and local is completely clear...

function displayNum(%this)
{
     %num = 0;

     incrementNum(%num);

     echo(%num);

}

function incrementNum(%num)
{
      %num++;
}

As matthew explained, this set of functions will echo will return "0" because the local is being passed, but not passed back. I've made some very distinct changes to Matthews code to demonstrate a direct pass of data and what happens to that data. First we set %num to equal "0", and then we pass the data to "incrementNum()". When "incrementNum(%num)" gets passed the %num variable, it will equal "0", and then it will increase %num to "1" by means of the operator "++". However, when "incrementNum(%num)" finishes the %num that it is calculating will be purged from memory and then "displayNum()" will finish the remainder of it's commands by echoing it's local %num which was set to "0". Now take a look at the following function...

function displayNum()
{
     $num = 0;

     incrementNum();

     echo($num);

}

function incrementNum()
{
      $num++;
}


Now with these functions there is no data being passed between them at all, but this "displayNum()" function will return a "1" to the console because we set a Global variable to "0" and then called our "incrementNum()" function which increased the value of the Global variable via the "++" operator and when it finished the "displayNum()" finished it's commands by echoing the $num variable which was increased by one. The one thing globals and locals both have in common is that they are "instant" at the time they are declared. So when we returned to the first function the $num variable had already been increased by one before the function had finished so the new value was there when we came back and we didn't even have to send it to alter it. You could get the same result of "1" using the following functions without passing any data and despite the fact that the variable was created after we started "displayNum()"...


function displayNum()
{
     incrementNum();

     echo($num);
}

function incrementNum()
{
      $num = 1;
}


You will get the value of "1" from these as well despite the fact nothing was declared at all...


function displayNum()
{
     echo( incrementNum() );
}

function incrementNum()
{
      return 1;
}


And just to throw a monkey wrench into the works, this will return a "1" as well(the %num to %abc was done intentionally to show that what you name your variables does not matter when dealing with Locals because the value of the Local(or Global) is passed and not the Local itself)...

function displayNum()
{
     echo( incrementNum(%num = 0) );
}

function incrementNum(%abc)
{
      return %abc++;
}


And finally to really boggle the mind, these functions will return "1" as well...


function displayNum()
{
     echo( incrementNum(%num = 0) );
}

function incrementNum(%abc)
{
      return %abc == 0;
}


Now my friend you have a class A education in TorqueScript variable declarations and uses. You are well on your way to being a TorqueMaster.


:-)
#8
02/05/2005 (2:27 am)
I can't "excellent!!" enough guys. thank you.

now, I still can't understand:
function incrementNum(%this, %num)
{
      %num++;
      return %num;
}

what is "%this", and how would this function be called?

Thanks again.
#9
02/05/2005 (3:55 am)
Prepare to meet the next awesome power in TGE...

:-D


This can be tricky stuff to grasp here, but once you get this down, man is it fun. Ok, lets start with the basics.


function playerSlapsOrc()
{
	// Get orc and smack it
}

This function is pretty well a utility function that has one purpose. To alter or calculate some data and possibly send it back. It's usually limted to specific data but when used creatively can still be a very powerful efficient function. It cannot be passed any data from another function and would be called by simply having the line "playerSlapsOrc();". We can increase it's capabilities greatly by just passing it one variable like so...

function playerSlapsOrc(%orc)
{
	// Get %orc and smack it
}

Not only do you get the ability to specify which orc to hit via "playerSlapsOrc(%orc);", but the function can also operate exactly like it used to in the previous function because you do not HAVE to pass any data to it and all "playerSlapsOrc();" (You have to design a data/no-data function to work that way). But you could add a switch/case to that type of function and the possibilities grow tremendously. But even still it's quite limited to the depth at which it can perform. Not very flexible at all. If you wanted to be able to give the player score for example you would need to know what player had smacked the orc, so you could send "playerSlapsOrc(%player, %orc);" to the following function...

function playerSlapsOrc(%player, %orc)
{
	// Get %orc and smack it and score %player 5 points
}


Which would give you the ability to smack any orc with any player and score the player 5 points. A lot more functionality than you had in the beginning. Or you could expand your function to the next level like so...

function Player::SlapsOrc(%player, %orc)
{
	// Get %orc and smack it and score %player 5 points
}


Yeah yeah, I know, "What's the joke?" Well, there are two ways to access that function, the first is "Player::SlapsOrc(%player, %orc);" which is NOT recommend at any time untill you know for sure you have no other way to do it(very rare). The other way, which is the correct way is to use this "%player.SlapsOrc(%orc);". This is known as a namespace function. By tagging the function onto the players ID# (%player), you declared to the engine that you wanted this object handled in a very different manner than usual. To save space here, check out This Thread for a detailed explanation of what makes this type of functionality sooooooo much more versitile and powerful overall. Once you read it you'll understand why you can actually reverse your data through that function and have Orcs start smacking players and scoring points if you want just by calling "%orc.SlapsOrc(%player);"

When you tag a function to the object, the object ID# goes with it always. It will always be the first value in your recieving function. So the following command "%player.doFoo();" would be handled in...

function Player::doFoo(%player)
{
    //  boo hoo foo
}

"%player" and "%this" is best explained Right Here . "Tagged" functions can ONLY be performed on an an actual game object. The following functions would either produce console spam or possibly even crash you...

function doSomeMath()
{
	%value = 5 * 5;

	%value.findTheSquareRoot();
}

because 25 is either not an object, not supported by it's own function, or a piece of the hierarchy that you didn't want to mess with because it crashed you. 25 in this instance is nothing but a numeric value. So to find the square you would have to wrap %value the old fashion way of "findTheSquareRoot(%value);" passed to...

function findTheSquareRoot(%value)
{
      //return the square of %value
}
#10
02/06/2005 (11:42 am)
I stand corrected, thanks for catching that Gonzo, was at work when posting it and was a little loopy


As Gonzo included an example I was refering to a namespace function in a regular function...

I'll include some more examples... (lol maybe will help by correcting myself)
lately I've been working on a journal system... here is a function from it (maybe can show some good use for this as well)

here is a "writeClass()" function to the "JournalDemo" namespace... now the JournalDemo is a gui, so it attaches this function to its namespace... to perform this function in script I would type
"JournalDemo.writeClass("entry", "name", "Quest Person 4");"

function JournalDemo::writeClass(%this, %class, %property, %value)
{
	$journalMainTags[$mainTagCount] = %class;
	$mainTagCount++;
	%this.writeProperty(%class, %property);
	%this.addInstance(%class, %property, %value);
	$journalArrayCount++;
}

now since its in a namespace, designated by the "::" when I call this function the first variable is itself, which would be the JournalDemo object... that way I can then type
"%this.writeProperty(%class, %property);"
because this function is a JournalDemo namespace function also... its the same as typing
"JournalDemo.writeProperty(%class, %property);"

this way If I ever rename the GUI.. say to Journal... I won't have to replace all the "JournalDemo." functions.. since they are %this, I would just have to change the function calls... "JournalDemo::"...

hope this helps
#11
03/07/2005 (4:04 am)
Hi all,

For me when i try this "%count=MissionCleanup.getCount(); echo(%count);" in the console it returns the correct value?? I'm using the latest tge 1.3.0 on windows xp pro. However when i call the same command from c++ Con::evaluate("%count=MissionCleanup.getCount(); echo(%count);" ) it crashes torque. So i used the remote debugger to see what the error was and i found the following error: "Accessing local variable in global scope... failed".

Just wondering how come it worked in the console but when using c++ evaluate it crashes?

Thanks
#12
03/07/2005 (6:08 am)
@Portalguy,

I beleive that's because when you type your command in the console you create ( and destroy ) a new scope for every line. When you issue the command thru Con::evaluate, you are using the global scope for default.

Try using Con::evaluate("{%count=MissionCleanup.getCount(); echo(%count);}" ) ( curly braces added).
#13
03/07/2005 (6:24 am)
Wow, what a great explanation of logic and this scripting language, rather than the stock, "...you've got the code...", reaction. Thanks, Gongo,Matthew,LabRat, et al...
#14
03/07/2005 (7:10 am)
Bruno thanks for the help, unfortunatly it didn't work. I got syntax error. Also when trying it through the console i get the same error.

Could you think of any other way?.

Thanks again
#15
03/07/2005 (12:36 pm)
Sorry, that's because TScript syntax doesn't really support braces not connected to a function or other special commands.

Try
Con::evaluate("if(1){%count=MissionCleanup.getCount(); echo(%count);}" )
#16
03/18/2005 (7:41 pm)
So here's a problem I've been having. I've been attempting to follow the weapon ammo resource set up here:

http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=1786

However, for some reason I am finding trouble passing local variables between functions.

First, however, I just want to confirm that you can't pass a member of a datablock to a function, but instead you have to pass the whole datablock. Is that correct?

Second, here's the code I've been using:

function ShapeBase::AddItemHUD(%this, %user, %data)
{
	%check = -1;
	
	Echo("I'm in AddItemHUD");
	
	for(%i = 0; %i < 5; %i++)
	{
		if(%this.InvIndices[%i] $= "empty" && %check $= -1)
		{
			Echo(found);
			%check = %i;
		}
	}
	
	Echo("Check is " @ %check);
	
	Echo ("Pickupname is " @ %data.pickupName);
	%this.InvIndices[%check] = %data.pickupName;
	
	Echo("InvIndices is now " @ %this.InvIndices[%check]);
	
	%this.client.UpdateInventoryHud(%data, %user, %check);
}

That's the first function that passes the info. Here's the second function that receives the info:

function GameConnection::UpdateInventoryHUD(%client, %data, %index)
{
	echo("Index on server is " @ %index);
	commandToClient(%client, 'UpdateInventory', %index, %data );
}

Here's the console output I get:

I'm in AddItemHUD
found
Check is 0
Pickupname is Glue
InvIndices is now Glue
Index on server is 1489

It seems that the function "UpdateInventoryHUD" is receiving the address of index and not the value. At least, that's my C/C++ mind working. What the heck is going on here?
#17
03/19/2005 (6:34 am)
Aren't you missing a parameter over there ? Shouldn't Function #2 be :
UpdateInventoryHUD(%this,%data,%user,%check) ?

Keep in mind that since you are calling this as an object method, the object's ID will be the first parameter.
#18
03/27/2005 (9:08 pm)
Yeah i realized that later.

**Remembers to test first, post second**