Game Development Community

Moving a variable outside the datablock?

by Dreamer · in Torque Game Engine · 05/01/2005 (11:03 am) · 11 replies

Hello, I have managed to move the MaxDamage value out of the PlayerData datablock and created 2 console methods and a new member variable, setMaxDamage, getMaxDamage and mMaxDamage. Then I removed all refferences in code to mDatablock->MaxDamage and replaced them with mMaxDamage.

Here is the most relevant snippits
void ShapeBase::setMaxDamage(int maxdamage){
	mMaxDamage = maxdamage;
	updateDamageLevel();
}

int ShapeBase::getMaxDamage(){
	return(mMaxDamage);
}

ConsoleMethod( ShapeBase, setMaxDamage, void, 3, 3, "(int Max Damage)")
{
   object->setMaxDamage(dAtoi(argv[2]));
}

ConsoleMethod(ShapeBase, getMaxDamage, S32,2,2,"(no params returns int)"){
   return object->getMaxDamage();
}

This new system seems to work really well, and I would like to create similar functionality for Energy and ShapeFile, I think with Energy the change will be really straightforward, however before I start, trying to do this with the ShapeFile, I would like to find out if there are any possible repurcussions in the engine. Like for instance, what considerations if any would I need to make, to keep the engine from crashing if I changed the shapefile? The purpose of changing the shapefile would of course be to allow the player to cast a spell and change his body shape, without needing to change datablocks.

Anyways, any caveats or advice would be greatly appreciated. Thanks!

#1
05/01/2005 (11:53 am)
I think the most pertinent question is why on earth you would want to do this. Granted, your new gametype needs to have dynamic setting of MaxDamage, MaxEnergy, and so on. Fine, create console methods like you've done above. But you do not need to remove these from the datablocks. The datablock will simply load it's value when the player is spawned, you are free to change it at will afterwards. Take some advice: don't take these things out of the datablock.

On to your real question: it won't be just as simple as changing the shapefile, you will need to do a bit of setting up. But look through shapebase::onNewDatablock and you should see what you need to do.

Ian
#2
05/01/2005 (12:57 pm)
@Ian: Actually, that is not true. If you change a datablock value, it will change for every object that uses that datablock.

Datablocks are shared on both the server and the client (after being downloaded), and therefore if you change objectXXX->mDatablock->someValue, it will change for everyone that references that datablock.
#3
05/01/2005 (1:11 pm)
No, don't agree. Sure, if you change a datablock value when the game isn't running it will affect all objects of that type, but then just leave those values default.

Changing a datablock's value during a game is not a good idea:
(a) It will not be persisted to the clients, so the datablocks will be out of sync.
(b) It won't affect objects which already exist, only newly created ones.

My point is that he shouldn't bother taking the values out of the datablock: they're doing absolutely no harm there, and taking things out that aren't doing any hard simply causes work later on, it's a proven fact of indie dev.

What he wants to do is change some values dynamically on an already spawned object. What datablocks do is initialise values. There is no intersection between these two things, and thus he shouldn't be messing around with the later while implementing the former.

At least, that's my take :)
Ian
#4
05/01/2005 (1:23 pm)
@Ian: Based on information from GG (I haven't traced this through myself to be honest), when you create a new object with a datablock name, it simply sets the object's mDataBlock pointer to the currently existing copy of the datablock object in memory.

If you modify a value in a datablock accessor method called within Object1, and then check that value from another object of the same datablock name, the change will have happened since both of the accessors will be referencing the same block of memory space: both of the objects will point to the same mDataBlock memory.

I originally thought datablocks were simply initializers as well, but they are only instantiated once, and then are shared.

If someone can show the code that proves this false, I'd certainly like to see it!
#5
05/01/2005 (1:34 pm)
Here is my proof...

Try adding this funciton in ShapeBase.cc
void ShapeBase::setMaxDamage(int damage){
   mDataBlock->maxDamage = damage;
   updateDamageLevel();
}

ConsoleMethod( ShapeBase, setMaxDamage, void, 3, 3, "(int MaxDamage)")
{
   object->setMaxDamage(dAtoi(argv[2]));
}

Create 2 players both using the PlayerBody datablock.

1138 is the first client
1139 is the second client.

1138.Player.setMaxDamage(100);
1139.Player.setMaxDamage(50);

echo("First player's MaxDamage is"@1138.Player.MaxDamage);
FirstPlayers MaxDamage is50

This would only happen is the value is being refferenced from the most recent change to the datablock. In short datablocks are convenient places to store static data which must be shared across multiple instances.

So if for instance I had 2 teams, Orcs and Elves, and I all the sudden wanted ALL the elves to get sick and lose 50 percent of thier max hitpoints. Just refference one elf.
%targetObject.Player.setMaxDamage(%targetObject.Player.MaxDamage /2);

And all the sudden all elves loose 1/2 of thier damage recieving capabilities.
#6
05/01/2005 (1:36 pm)
Right, gotcha. Looking at MaxEnergy etc the player class does call the datablock directly, so I'm wrong on that count. I guess what I think he should be doing is to change all references to mDatabock->maxEnergy to mMaxEnergy, fill mMaxEnergy from the dataBlock in onNewDataBlock, then access that directly.

Ian
#7
05/01/2005 (1:43 pm)
Well what I wound up doing is initializing mMaxDamage to 100 (for safety sake) at about the same place as mDamage is declared.

MPLEMENT_CO_NETOBJECT_V1(ShapeBase);

ShapeBase::ShapeBase()
{
   mTypeMask |= ShapeBaseObjectType;

   mDrag = 0;
   mBuoyancy = 0;
   mWaterCoverage = 0;
   mLiquidType = 0;
   mLiquidHeight = 0.0f;
   mControllingClient = 0;
   mControllingObject = 0;

   mGravityMod = 1.0;
   mAppliedForce.set(0, 0, 0);

   mTimeoutList = 0;
   mDataBlock = NULL;
   mShapeInstance = 0;
   mShadow = 0;
   mGenerateShadow = false;
   mEnergy = 0;
   mRechargeRate = 0;
   [b]mMaxDamage = 100;[/b]
   mDamage = 0;
   mRepairRate = 0;

What I need to know is if there are any possible repurcussions to this, like for instance, I would think that this new value needs to be handed off to the client somewhere via PackUpdate and UnPackUpdate, but I'm not seeing where to stick it.
Strangely though, this change seems to have propegated it's self automagically.
#8
05/03/2005 (1:48 pm)
Hey all,

I have looked everywhere for a good place to post this, and this seems to be it, so here we go. I want to add a dynamic variable to the Player class, called mJumpCharge (values being 0-1) that modifies the mDataBlock->jumpForce variable by taking a percentage of it. Originally, I added the following to player.h

ActionState mState;                ///< What is the player doing? @see ActionState
bool mFalling;                         ///< Falling in mid-air?
[b]F32  mJumpCharge;            ///< percent to be multiplied by jumpForce (0-1) - AB [/b]
S32  mJumpDelay;                 ///< Delay till next jump

Then in player.cc under Player::Player() I added

mFalling = false;
mContactTimer = 0;
[b]mJumpCharge = 0; [/b]
mJumpDelay = 0;

Next in player.cc under Player::updateMove(const Move* move) I changed this

F32 impulse =  mDataBlock->jumpForce / mMass;

To this:

//modified to account for charged jump
F32 impulse = (mJumpCharge * mDataBlock->jumpForce) / mMass;

Is there anything else I need to do to get this working right, so I can change the value of mJumpCharge in script?
I experimented with added read and write lines to packUpdate and unpackUpdate, but to no avail.
#9
05/03/2005 (2:37 pm)
Hey all,

I have looked everywhere for a good place to post this, and this seems to be it, so here we go. I want to add a dynamic variable to the Player class, called mJumpCharge (values being 0-1) that modifies the mDataBlock->jumpForce variable by taking a percentage of it. Originally, I added the following to player.h

ActionState mState;                ///< What is the player doing? @see ActionState
bool mFalling;                         ///< Falling in mid-air?
[b]F32  mJumpCharge;            ///< percent to be multiplied by jumpForce (0-1) - AB [/b]
S32  mJumpDelay;                 ///< Delay till next jump

Then in player.cc under Player::Player() I added

mFalling = false;
mContactTimer = 0;
[b]mJumpCharge = 0; [/b]
mJumpDelay = 0;

Next in player.cc under Player::updateMove(const Move* move) I changed this

F32 impulse =  mDataBlock->jumpForce / mMass;

To this:

//modified to account for charged jump
F32 impulse = (mJumpCharge * mDataBlock->jumpForce) / mMass;

Is there anything else I need to do to get this working right, so I can change the value of mJumpCharge in script?
I experimented with added read and write lines to packUpdate and unpackUpdate, but to no avail.
#10
05/06/2005 (7:38 pm)
Http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7453


Look at method 2

You can access the data in scripts easily. Modify it in the way you want.
#11
05/07/2005 (12:37 pm)
Thanks a lot.. That is exactly what i needed.