Package problems
by John Vanderbeck · in Torque Game Engine · 06/29/2004 (10:51 am) · 37 replies
Hey all,
I'm finally finding more free time and am going back to code that I haven't touched in a while which is always hard.
Anyway, I have a dynamic plugin system I previously wrote that uses packages and suddenly it isn't working tight anymore. I KNOW this worked before so I am really really stumped.
The meat of the system is in this code:
The .CS files are prevoiously loaded at startup. In this code it basically activates the package for the correct layout plugin, then calls the common functions, then deactivates the package. Like I said this used to work fine.
However all of a sudden, it isn't. The first package activated gets used everytime, even though the code does indeed call for the other packages. Here is a snippet of the console log to show what I mean:
Does anyone see something i'm missing? Because I can't find anything wrong. The package names match up exactly with the appropriate .CS file. I already double checked that. For reference though, here is one of the plugin files.
I'm finally finding more free time and am going back to code that I haven't touched in a while which is always hard.
Anyway, I have a dynamic plugin system I previously wrote that uses packages and suddenly it isn't working tight anymore. I KNOW this worked before so I am really really stumped.
The meat of the system is in this code:
// Load the plugin for the layout option specified
%code = "activatePackage(GUILayout_" @ %layout @ ");";
eval(%code);
echo(%code);
echo("Positioning control");
if (!determineControlPosition(%control, %this, %param1, %param2))
{
echo("ERROR: TGUIBuilder -> TGUISet -> addControl -> Failed to properly determine control position using the layout specified. Ensure that you specified a valid layout option (layout options ARE case sensitive. 'above' is not the same as 'Above') and that the layout parameters are correct.");
return false;
}
%code = "deactivatePackage(GUILayout_" @ %layout @ ");";
eval(%code);
echo(%code);The .CS files are prevoiously loaded at startup. In this code it basically activates the package for the correct layout plugin, then calls the common functions, then deactivates the package. Like I said this used to work fine.
However all of a sudden, it isn't. The first package activated gets used everytime, even though the code does indeed call for the other packages. Here is a snippet of the console log to show what I mean:
activatePackage(GUILayout_Anchor); Positioning control In Layout: Anchor deactivatePackage(GUILayout_Anchor); activatePackage(GUILayout_Below); Positioning control In Layout: Anchor deactivatePackage(GUILayout_Below); activatePackage(GUILayout_Absolute); Positioning control In Layout: Anchor deactivatePackage(GUILayout_Absolute); activatePackage(GUILayout_Anchor); Positioning control In Layout: Anchor deactivatePackage(GUILayout_Anchor); activatePackage(GUILayout_Below); Positioning control In Layout: Anchor deactivatePackage(GUILayout_Below); activatePackage(GUILayout_Below); Positioning control In Layout: Anchor deactivatePackage(GUILayout_Below); activatePackage(GUILayout_Below); Positioning control In Layout: Anchor deactivatePackage(GUILayout_Below); activatePackage(GUILayout_Absolute); Positioning control In Layout: Anchor deactivatePackage(GUILayout_Absolute); Displaying Menu: ROOT
Does anyone see something i'm missing? Because I can't find anything wrong. The package names match up exactly with the appropriate .CS file. I already double checked that. For reference though, here is one of the plugin files.
package GUILayout_Below
{
function determineControlPosition(%control, %set, %param1, %param2)
{
echo("In Layout: Below");
%baseControl = %set.getBaseControl(%param1);
if (%baseControl != 0)
{
%baseX = %baseControl.x;
%baseY = %baseControl.y + %baseControl.extentY;
}
else
{
echo("ERROR: TGUIBuilder -> TGUISet -> addControl -> GUILayout_Below -> Unable to position control relative to default control, because the default control is invalid. A control must have been added to the set before this one.");
return false;
}
if (%param2 !$= "")
{
%baseY = %baseY + %set.getPosition(%param2, "y");
}
else
{
%baseY = %baseY + %set.defaultVerticalSpacing;
}
%control.x = %baseX;
%control.y = %baseY;
}
};
#22
Truthfully though, I don't think packages were originally designed for overloading non memeber functions. Tribes 2 used them in a rather simple manner to change the scoring characteristics of game types. But it just so happens that packages were found to be usefull for a much wider variety of uses, especially for client-side scripting. SO I imagine it would probably be worth someones time to eventually figure out a fix for the source. Now if I could just find that magic wand....
07/01/2004 (6:44 pm)
AH good!Truthfully though, I don't think packages were originally designed for overloading non memeber functions. Tribes 2 used them in a rather simple manner to change the scoring characteristics of game types. But it just so happens that packages were found to be usefull for a much wider variety of uses, especially for client-side scripting. SO I imagine it would probably be worth someones time to eventually figure out a fix for the source. Now if I could just find that magic wand....
#23
07/01/2004 (9:25 pm)
If anyone finds fixes, I'd be happy to see if they belong in HEAD.
#24
I've run into a similar issue and would like to know what class you are using for your function's namespace. Martin refered me to this thread (Thanks Martin), and I'm definitely hoping to find a solution. I've tried resolving this with a script object and it's namespace, and it did not work:
Also tried ShapeBaseData, with direct calls and a bogus instance ID:
There exists the high possibility of my having made a dumb mistake(s), but I'm feeling like this should work, so knowing exactly how you resolved your issue would be very nice.
Thanks!
Ed M.
08/10/2004 (7:46 pm)
John, I've run into a similar issue and would like to know what class you are using for your function's namespace. Martin refered me to this thread (Thanks Martin), and I'm definitely hoping to find a solution. I've tried resolving this with a script object and it's namespace, and it did not work:
$LessonObjectInstance = new ScriptObject( LessonObjectClass ) {
LessonCount = 0;
};
package TP0 {
function LessonObjectClass::TestIt( %this ) {
echo("TP0::TestIt()");
}
};
package TP1 {
function LessonObjectClass::TestIt( %this ) {
echo("TP1::TestIt()");
}
};
package BP {
function LessonObjectClass::PrepIt( %this ) {
echo("BP::PrepIt()");
}
};
function whack0() {
%name = "TP0";
%testName = stripChars( %name, " ");
echo("Load package:" @ %name);
deactivatePackage(BP);
activatePackage(BP);
activatePackage(%testName);
$LessonObjectInstance.PrepIt();
$LessonObjectInstance.TestIt();
}
function whack1() {
%name = "TP1";
%testName = stripChars( %name, " ");
echo("Load package:" @ %name);
deactivatePackage(BP);
activatePackage(BP);
activatePackage(%testName);
$LessonObjectInstance.PrepIt();
$LessonObjectInstance.TestIt();
}
function whack2(%name) {
%testName = stripChars( %name, " ");
echo("Load package:" @ %name);
deactivatePackage(BP);
activatePackage(BP);
activatePackage(%testName);
$LessonObjectInstance.PrepIt();
$LessonObjectInstance.TestIt();
}Also tried ShapeBaseData, with direct calls and a bogus instance ID:
package TP0 {
function ShapeBaseData::TestIt( %this ) {
echo("TP0::TestIt()");
}
};
package TP1 {
function ShapeBaseData::TestIt( %this ) {
echo("TP1::TestIt()");
}
};
package BP {
function ShapeBaseData::PrepIt( %this ) {
echo("BP::PrepIt()");
}
};
function whack0() {
%name = "TP0";
%testName = stripChars( %name, " ");
echo("Load package:" @ %name);
deactivatePackage(BP);
activatePackage(BP);
activatePackage(%testName);
ShapeBaseData::PrepIt(0);
ShapeBaseData::TestIt(0);
}
function whack1() {
%name = "TP1";
%testName = stripChars( %name, " ");
echo("Load package:" @ %name);
deactivatePackage(BP);
activatePackage(BP);
activatePackage(%testName);
ShapeBaseData::PrepIt(0);
ShapeBaseData::TestIt(0);
}
function whack2(%name) {
%testName = stripChars( %name, " ");
echo("Load package:" @ %name);
deactivatePackage(BP);
activatePackage(BP);
activatePackage(%testName);
ShapeBaseData::PrepIt(0);
ShapeBaseData::TestIt(0);
}There exists the high possibility of my having made a dumb mistake(s), but I'm feeling like this should work, so knowing exactly how you resolved your issue would be very nice.
Thanks!
Ed M.
#25
08/11/2004 (1:39 pm)
Ed, in the case of my code, the functino simply became a member of the gui control object, which is a simple ScriptObject. When I get home from work I will dig up the code and show you.
#26
First off I have a custom object called TGUISet. This is simply a ScriptObject, created dynamicly as needed.
For the package function that gets overriden per package, I made that function a member of TGUISet in order to get this working.. Here is an example of the packaged code, then a call that activates that packaged code.
08/11/2004 (5:43 pm)
Ok Ed, i'm home from work now so let me put some more information in here for oyu.First off I have a custom object called TGUISet. This is simply a ScriptObject, created dynamicly as needed.
function TGUIBuilder::createSet(%this)
{
if (%this.numSets >= %this.maxSets)
{
echo("ERROR: TGUIBuilder -> createSet -> The maximum amount of sets (" @ %this.maxSets @ ") have already been created.");
return 0;
}
%this.nextID++;
%this.sets[%this.nextID] = new ScriptObject(TGUISet);
%set = %this.sets[%this.nextID];
if (%set == 0)
{
echo("ERROR: TGUIBuilder -> createSet -> Failed to allocate memory for a new set.");
%this.nextID--;
return 0;
}
%set.id = %this.nextID;
%this.numSets++;
%set.init();
return %set;
}For the package function that gets overriden per package, I made that function a member of TGUISet in order to get this working.. Here is an example of the packaged code, then a call that activates that packaged code.
package GUILayout_Above
{
function TGUISet::determineControlPosition(%control, %set, %param1, %param2)
{
echo("In Layout: Above");
%baseControl = %set.getBaseControl(%param1);
if (isObject(%baseControl))
{
%baseX = %baseControl.x;
%baseY = %baseControl.y;
}
else
{
echo("ERROR: TGUIBuilder -> TGUISet -> addControl -> GUILayout_Above -> Unable to position control relative to default control, because the default control is invalid. A control must have been added to the set before this one.");
return false;
}
if (%param2 !$= "")
{
%baseY = %baseY - %set.getPosition(%param2, "y") - %control.extentY;
}
else
{
%baseY = %baseY - %set.defaultVerticalSpacing - %control.extentY;
}
%control.x = %baseX;
%control.y = %baseY;
}
};// Load the plugin for the layout option specified
%code = "activatePackage(GUILayout_" @ %layout @ ");";
eval(%code);
echo(%code);
listPackages();
echo("Positioning control");
if (!%this.determineControlPosition(%control, %this, %param1, %param2))
{
echo("ERROR: TGUIBuilder -> TGUISet -> addControl -> Failed to properly determine control position using the layout specified. Ensure that you specified a valid layout option (layout options ARE case sensitive. 'above' is not the same as 'Above') and that the layout parameters are correct.");
%code = "deactivatePackage(GUILayout_" @ %layout @ ");";
eval(%code);
return false;
}
%code = "deactivatePackage(GUILayout_" @ %layout @ ");";
eval(%code);
#27
Thanks for posting your code here. I worked around the issue so I could continue working, but I'll give this a shot in the future. I was doing something similar that wasn't working, but I'll try replacing my
call with something like your code:
I hope it will make a difference, but regardless I think there is a bug in the package code.
Thanks again!
[HOW]EdM|EGTGE
PS - Sorry for the late repsponse. I've been super busy writing. I really appreciate your responding to my query.
Thx, Ed
08/14/2004 (7:57 am)
John,Thanks for posting your code here. I worked around the issue so I could continue working, but I'll give this a shot in the future. I was doing something similar that wasn't working, but I'll try replacing my
activate(%packageName);
call with something like your code:
%code = "deactivatePackage(GUILayout_" @ %layout @ ");"; eval(%code);
I hope it will make a difference, but regardless I think there is a bug in the package code.
Thanks again!
[HOW]EdM|EGTGE
PS - Sorry for the late repsponse. I've been super busy writing. I really appreciate your responding to my query.
Thx, Ed
#28
The above function is a memeber of TGUISet. It calls the determineControlPosition inside the package which it dynamicly activates depending on layout options. The "this" for TGUISet::addControl, in otherwords this function, is passed through determineControlPosition() because that package function uses members of TGUISet for determining various layout properties. That is this function here:
Originally this package function was not a member if TGUISet hence the reason for having to pass it through. Now that it is a member of it I shouldn't have to pass it through but it also shouldn't hurt, and it saves me from changing the code in every plugin.
Here is where the problem crops up. The wording of this is going to be confusing but i'll try to make it simple. The "this" which identifies the object of the TGUISet making this call is passed through the the package function, but when it gets to the package function it is suddenly a completely different object. When I echo the variable on both sides of the call it shows that it is two different objects!
addControl side:
determineControlPosition (Package function) side:
08/18/2004 (8:55 am)
Unfortunately this hasn't completely fixed the problem. It seems to have fixed some of it but also created a highly masked new problem.function TGUISet::addControl(%this, %control, %layout, %param1, %param2)
{
if (%control == 0)
{
echo("ERROR: TGUIBuilder -> TGUISet -> addControl -> Specified control is invalid.");
return false;
}
if (!$guiBuilder.isValidLayout(%layout))
{
echo("ERROR: TGUIBuilder -> TGUISet -> addControl -> Specified layout type is unknown. Layout types ARE case sensitive. For a list of known layout types call $guiBuilder.listValidLayouts()");
return false;
}
control.anchor = false;
// Load the plugin for the layout option specified
%code = "activatePackage(GUILayout_" @ %layout @ ");";
eval(%code);
echo(%code);
listPackages();
echo("Positioning control");
%set = %this;
// for some odd reason, the %set defined above when passed through the function
// below ends up as a different object when read by the function
echo(%set);
if (!%this.determineControlPosition(%control, %set, %param1, %param2))
{
echo("ERROR: TGUIBuilder -> TGUISet -> addControl -> Failed to properly determine control position using the layout specified. Ensure that you specified a valid layout option (layout options ARE case sensitive. 'above' is not the same as 'Above') and that the layout parameters are correct.");
%code = "deactivatePackage(GUILayout_" @ %layout @ ");";
eval(%code);
return false;
}The above function is a memeber of TGUISet. It calls the determineControlPosition inside the package which it dynamicly activates depending on layout options. The "this" for TGUISet::addControl, in otherwords this function, is passed through determineControlPosition() because that package function uses members of TGUISet for determining various layout properties. That is this function here:
if (!%this.determineControlPosition(%control, %set, %param1, %param2))
Originally this package function was not a member if TGUISet hence the reason for having to pass it through. Now that it is a member of it I shouldn't have to pass it through but it also shouldn't hurt, and it saves me from changing the code in every plugin.
Here is where the problem crops up. The wording of this is going to be confusing but i'll try to make it simple. The "this" which identifies the object of the TGUISet making this call is passed through the the package function, but when it gets to the package function it is suddenly a completely different object. When I echo the variable on both sides of the call it shows that it is two different objects!
addControl side:
Positioning control 1247
determineControlPosition (Package function) side:
In Layout: Absolute 1233
#29
08/18/2004 (8:57 am)
Oh an on a side note, "this" inside the package function which is a member function of TGUISet results in a null object. So somethign is defintly funky with the packages here.
#30
While it won't be as pretty, you might try calling it via:
TGUISet::determineControlPosition(%this, %control, %set, %param1, %param2);
If the %this stays the proper ID with that method then you would know if there is some odd conversion going on.
08/18/2004 (1:07 pm)
Thats a new one for me. It makes me wonder if TGUISet is the actuall classname, and it is being called on an instance of said class, and is then converting the ID to the class'. If you found that completly incoherant, well, I just got off work :).While it won't be as pretty, you might try calling it via:
TGUISet::determineControlPosition(%this, %control, %set, %param1, %param2);
If the %this stays the proper ID with that method then you would know if there is some odd conversion going on.
#31
08/18/2004 (1:20 pm)
TGUISet is a script object that is dynamically created for each GUI "set". Therefore there are, or can be, multiple object instances. That prevents me (I think) from making a call like you suggest above. HOWEVER, I think for my test code I only use one set so why don't I try that and just see what happens.
#32
Well that's what I get if I try what you suggested. I'm not sure what to make of it. TGUISet the object defintly exists.
08/18/2004 (1:23 pm)
show2/client/TGUIBuilder/TGUIBuilder.cs (366): Unable to find object: '' attempting to call function 'determineControlPosition'
Well that's what I get if I try what you suggested. I'm not sure what to make of it. TGUISet the object defintly exists.
#33
I started debugging and noticed that the object ID that the var became once inside the package function was the object ID of a control.
When I changed the package functions over to be members of an object, I forgt to change the definition so that %this was the first param. As a result, as you all well know, the params were offset, so %set was in fact %control.
DOH!
I feel like an idiot.
08/18/2004 (6:53 pm)
Well apparrently i'm an idiot. The problem is fixed now. Nothing to see here.I started debugging and noticed that the object ID that the var became once inside the package function was the object ID of a control.
function TGUISet::determineControlPosition(%control, %set, %param1, %param2)
When I changed the package functions over to be members of an object, I forgt to change the definition so that %this was the first param. As a result, as you all well know, the params were offset, so %set was in fact %control.
DOH!
I feel like an idiot.
#34
I am currently packaging common game.cs functions like onServerCreated, onServerDestroyed, onMissionLoaded, onMissionEnded, GameConnection::onClientEnterGame(%this), GameConnection::onClientLeaveGame(%this), and some non-member functions. I am doing this since every mission file with corresponding game.cs file because each mission is an entirely different mini game.
Like what mentioned above, only member functions are called correctly but not the non-member functions (no namespaces) when package switching.
Any suggestions on how can I make the it call non-member functions correctly? I'm trying to build the mini-game infrastructure to prevent switch...case on every non-member functions like onServerCreated.
01/08/2007 (2:47 am)
I need help on my problem.I am currently packaging common game.cs functions like onServerCreated, onServerDestroyed, onMissionLoaded, onMissionEnded, GameConnection::onClientEnterGame(%this), GameConnection::onClientLeaveGame(%this), and some non-member functions. I am doing this since every mission file with corresponding game.cs file because each mission is an entirely different mini game.
Like what mentioned above, only member functions are called correctly but not the non-member functions (no namespaces) when package switching.
Any suggestions on how can I make the it call non-member functions correctly? I'm trying to build the mini-game infrastructure to prevent switch...case on every non-member functions like onServerCreated.
#35
01/15/2007 (2:56 am)
Hmm well non-namespaced functions really is a problem. Oh well, I just cleaned up my code structure to evade that problem.
#36
Thanks.
09/28/2007 (8:53 pm)
I would be really interested in what you did to fix this problem. I want to be able to use packages as well that can be changed between missions to alter non-namespace functions, two to be specific, startgame and endgame.Thanks.
#37
09/30/2007 (12:36 am)
I was having issues with the wrong namespace methods being called on a datablock. This thread here: www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11888 solved my problem. Maybe it can help here.
Torque Owner John Vanderbeck
VanderGames
Bingo!
I made determineControlPosition a member of a class and suddenly the proper function was being called. Defintly exposed a bug in Torque packages here i'd say.
Thanks everyoen for all your help. Looks like this will work, but i'm going to have to do some minor restructuring to go with it.