Game Development Community

TGB 1.7.3 Beta1 - Torque Script Bug

by Michael Woerister · in Torque Game Builder · 05/16/2008 (8:13 am) · 7 replies

Hi,

I think I discovered a bug in Torquescript when calling a ConsoleMethod fully qualified on an object. Maybe I've missed the latest changes in TS but the following code should be legal, shouldn't it?

function SceneClass::freezePlatforms( %this )
{
	%platformSet = %this.platformSet;
	%count = %platformSet.getCount();
	
	for ( %i = 0; %i < %count ; %i++ )
	{
		%obj = %platformSet.getObject( %i );
		%obj.savePhysicsSetup();
		
		//%obj.setLinearVelocity( "0 0" ); // <- this works
		t2dSceneObject::setLinearVelocity( %obj, "0 0" ); // <- this does not work
		
		%obj.setAngularVelocity( 0 );
	}
}

t2dSceneObject::setLinearVelocity() is called directly on %obj. In debug build this breaks because it obviously tries to call the method on %this instead of %obj. In a release build the call is just silently ignored.

A TGB project with a repro of the bug can be found here:
http://www.unet.univie.ac.at/~a0402917/TSBugRepro.zip

#1
05/16/2008 (8:23 am)
%obj.setLinearVelocity( "0 0" );
Is correct

You don't want to call a function via namespace unless there is only one of those objects, In my experiance the other approach is mostly applied for gui objects
#2
05/16/2008 (8:24 am)
Hi Michael.

I've never heard of/seen that calling convention for consoleMethods, only script defined "oop" "methods". I may of course have just missed it.

Ian
#3
05/16/2008 (8:33 am)
Isn't calling via namespace the only way one can override console methods in script? Like this:
function Platform::setLinearVelocity( %this, %v )
{
    // do some stuff only needed by this class

    // call the parent
    t2dSceneObject::setLinearVelocity( %this, %v );
}

This works just fine and I've used things like this a few times but maybe it was never legal in the first place?
#4
05/16/2008 (12:36 pm)
I see no problem with your code. I have used that, shall we say calling convention, for overloading script methods as well. When you say it isn't working ... what is it doing / any errors? Also, when you say in calls it on %this instead of %obj ... um, why? I don't see any obvious reason it would do that.
#5
05/17/2008 (1:52 am)
I don't see an obvious reason either. But in debug mode this assertion (part of the ConsoleMethod macro) fails:
AssertFatal( dynamic_cast<className*>( object ), "Object passed to " #name " is not a " #className "!" );

The debugger shows that the object actually is a t2dSceneGraph. The reason is probably this code section in compiledEval.cc:
case Namespace::Entry::VoidCallbackType:
                        nsEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
                        if(code[ip] != OP_STR_TO_NONE)
                           Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip-4), fnName, functionName);
                        
                        STR.popFrame();
                        STR.setStringValue("");
                        break;

The function is automatically called on %this, regardless of what is actually the target object. callArgv[1] would contain the right object. It seems that this expression a few lines up evaluates to true...
if(callType == FuncCallExprNode::FunctionCall)
... and therefore gEvalState.thisObject is not updated.

The callType only is set to MethodCall in FuncCallExprNode::alloc() if the function was called with a preceeding dot. Maybe namespace entries could be marked as console methods in the ConsoleMethod macro (via the ConsoleConstructor) and then FuncCallExprNode::alloc() could look that info up?

The problem is the direct namespace call works by chance if %this is the right object. That doesn't seem clean to me.
#6
05/17/2008 (5:53 am)
That is odd because when I use :: it does not seem to pass %this automatically. For example..

function Grunt::setOwningPlayer( %this, %player )
{
   GroundUnit::setOwningPlayer( %this, %player );

I always have to pass the %this parameter manually. Then again, this is a 1.7.3 bug report post, so this is probably do to recent changes, good find!
#7
05/17/2008 (7:08 am)
Hi James,

%this isn't passed automatically in my example either. The object the method is invoked on always has to be passed to the function if called with this namespace call explicitly. A problem only occurs when the given object is not the same object as %this in the calling function. Like in my example above.

The TorqueScript quick reference states that the 2 calling modes are equivalent:
http://tdn.garagegames.com/wiki/TorqueScript_Quick_Reference_2#function

And this article on TDN does so too:
http://tdn.garagegames.com/wiki/TorqueScript#Console_Methods
Quote:
Lastly, we can force Torque to call a specific instance as follows:
NetObject::hi(1000);

And this section here says so too:
http://www.garagegames.com/docs/tge/general/ch05s04.php

This is clearly a bug in the interpreter.