Material Mapping Projectile code problem
by Ronald J Nelson · in Torque Game Engine · 07/22/2006 (1:56 am) · 12 replies
I am currently working on a projectile code that identifies the object based upon an integer provided when the projectile's processtick performs it's raycast and the information is read from the propertyMap.cs based upon the name of the texture used on the object. This code will allow different decals and explosions for each projectile based upon this information. I am having a big problem that occurs when you fire the weapon at close range in that the information comes back as 0 only.
This is the code added to void Projectile::processTick:
Now when it gets to the Projectile::explode function it selects which decals and explosions to perform based on the value of the integer. To check if the values where being read I added the following at the beginning of the function to see if it was getting the correct values:
Keeping in mind that the data for the object I was firing at should have consistently returned the following in the console log:
Material type:(1)
Material flag:(1)
Material type:(0)
Material flag:(0)
It performs two of these in this case because the material flag value of 1 means the object is something this round can pass through. So the second set of values are the wall behind the object, in this case a pane of glass. This occurs correctly at a distance (about a simulated 6 feet) but this distance is further lengthened if the projectile's speed is increased by adjusting the muzzlevelocity value.
This is the code added to void Projectile::processTick:
//***Nelson's Material Mapping (Projectile Section) Update Start***
if( rInfo.object->getTypeMask() & TerrainObjectType )
{
TerrainBlock* tBlock = static_cast<TerrainBlock*>(rInfo.object);
S32 mapIndex = tBlock->mMPMIndex[0];
if (mapIndex != -1)
{
MaterialPropertyMap* pMatMap = static_cast<MaterialPropertyMap*>(Sim::findObject("MaterialPropertyMap"));
const MaterialPropertyMap::MapEntry* pEntry = pMatMap->getMapEntryFromIndex(mapIndex);
if(pEntry)
{
pMatType = pEntry->matType;
}
}
}
else
{
MaterialPropertyMap* pMatMap = static_cast<MaterialPropertyMap*>(Sim::findObject("MaterialPropertyMap"));
const MaterialPropertyMap::MapEntry* pMatEnt = pMatMap->getMapEntryFromIndex(rInfo.material);
if (pMatEnt)
{
pMatType = pMatEnt->matType;
pMatFlag = pMatEnt->matFlags;
}
if(pMatFlag == 1)
{
mPiercePosition = newPosition + mCurrVelocity * (F32(TickMs) / 1000.0f);
mPierceVelocity = mCurrVelocity;
}
}
onCollision(rInfo.point, rInfo.normal, rInfo.object);
explode(rInfo.point, rInfo.normal, objectType, mInitialPosition, mFinalVel );
//***Nelson's Material Mapping (Projectile Section) Update Stop***Now when it gets to the Projectile::explode function it selects which decals and explosions to perform based on the value of the integer. To check if the values where being read I added the following at the beginning of the function to see if it was getting the correct values:
Con::errorf(ConsoleLogEntry::General, "Material type:(%i)", pMatType ); Con::errorf(ConsoleLogEntry::General, "Material flag:(%i)", pMatFlag );
Keeping in mind that the data for the object I was firing at should have consistently returned the following in the console log:
Material type:(1)
Material flag:(1)
Material type:(0)
Material flag:(0)
It performs two of these in this case because the material flag value of 1 means the object is something this round can pass through. So the second set of values are the wall behind the object, in this case a pane of glass. This occurs correctly at a distance (about a simulated 6 feet) but this distance is further lengthened if the projectile's speed is increased by adjusting the muzzlevelocity value.
#2
Tried to catch you on IRC but it seems your wife already crucified you (:
I need to go, but perhaps this link could shed some light. I had this problem in TGE when fiddling around with decals, but I do not remember how I fixed it.
Also, make sure mDataBlock->armingDelay is set to 0.
07/22/2006 (3:28 am)
Hi Nelson,Tried to catch you on IRC but it seems your wife already crucified you (:
I need to go, but perhaps this link could shed some light. I had this problem in TGE when fiddling around with decals, but I do not remember how I fixed it.
Also, make sure mDataBlock->armingDelay is set to 0.
#3
For processTick in my code:
These values are actually getting the correct reading from the propertyMap.cs at all times even at close range which tells me the rayCasts and getting data from the propertyMap.cs for each texture type is working correctly no matter the range.
However, if I read the same values when it is at Projectile::explode they are now zeroes. It seems my earlier data was a bit off because I was not setting up good controlled experiments to isloate other factors. But this information is totally correct.
Now I even tried modifying the explode calls throughout the projectile code to pass the values directly hoping this would get rid of some sort of issue and it was no help.
Now, according to my console log there was not another processtick called between the correct reading and the explode call so the data should never have changed. The only thing I can even guess at here is since the values are initialized at "0" in Projectile::Projectile() that some how they are being reset somewhere in the process at close range which confuses me even further because that means for some reason when the weapon is fired at sufficient distance the values are not getting reinitialized.
Oh yeah and my arming delay is at 0.
07/23/2006 (1:34 am)
Thanks Stefan but through the use of console log entries through out my code I isolated the problem but I am not too sure on the cure. The problem at close range is as follows:For processTick in my code:
pMatType = pMatEnt->matType; pMatFlag = pMatEnt->matFlags;
These values are actually getting the correct reading from the propertyMap.cs at all times even at close range which tells me the rayCasts and getting data from the propertyMap.cs for each texture type is working correctly no matter the range.
However, if I read the same values when it is at Projectile::explode they are now zeroes. It seems my earlier data was a bit off because I was not setting up good controlled experiments to isloate other factors. But this information is totally correct.
Now I even tried modifying the explode calls throughout the projectile code to pass the values directly hoping this would get rid of some sort of issue and it was no help.
Now, according to my console log there was not another processtick called between the correct reading and the explode call so the data should never have changed. The only thing I can even guess at here is since the values are initialized at "0" in Projectile::Projectile() that some how they are being reset somewhere in the process at close range which confuses me even further because that means for some reason when the weapon is fired at sufficient distance the values are not getting reinitialized.
Oh yeah and my arming delay is at 0.
#4
Edit: And just to make sure, what values are you talking about that get set to 0 in the constructor?
07/23/2006 (3:00 am)
How are you grabbing the pMatEnt values? Trough rInfo?Edit: And just to make sure, what values are you talking about that get set to 0 in the constructor?
#5
07/23/2006 (3:29 pm)
Try change this S32 mapIndex = tBlock->mMPMIndex[0];to this
S32 mapIndex = tBlock->getTerrainMapIndex(rInfo.point);
#6
@Billy- I haven't really gotten into any issues with the Terrain code yet, what will this do for me?
07/23/2006 (3:49 pm)
@Stefan- Yes I am getting the values via rInfo, and the values that are set to 0 in the constructor are pMatType and pMatFlag. I have considered that maybe this is not the approach to go with and have them created at the point in processTick when they get their material properties. My concern with that method is that the flag property really needs to be at 0 if the projectile is not colliding with an object with the flag set to 1 otherwise it could lead to any object added without a propertyMap entry being registered as something toe create piercing projectiles for.@Billy- I haven't really gotten into any issues with the Terrain code yet, what will this do for me?
#7
This is the same fix you use to get materialmapping for footsteps to work.
I use matFlags and diff sounds for terrain hits and interior and use the above code.
So i hoped it could help you out:)
07/23/2006 (4:03 pm)
Are you really sure you get the right mapIndex ?This is the same fix you use to get materialmapping for footsteps to work.
I use matFlags and diff sounds for terrain hits and interior and use the above code.
So i hoped it could help you out:)
#8
The problem is that the data is getting set to 0 everytime I am at close range which after trying a new experiment I am convinced that somehow the raycast is screwwing things up now. I tried it out on an object and poited the weapon at the object in a way so the only object behind it was the sky, I got some wild data in the console log from that.
added this to start of Projectile::explode
------------------------------------------------------------
updated code from processTick
------------------------------------------------------------
from my console log
------------------------------------------------------------
07/23/2006 (4:31 pm)
@Billy - Yes. This has me totally confused since my values in processTick where the reading is taking place works perfectly, I put console log entries there and the data works perfectly every time. The problem is that the data is getting set to 0 everytime I am at close range which after trying a new experiment I am convinced that somehow the raycast is screwwing things up now. I tried it out on an object and poited the weapon at the object in a way so the only object behind it was the sky, I got some wild data in the console log from that.
added this to start of Projectile::explode
------------------------------------------------------------
Con::errorf(ConsoleLogEntry::General, "Material type:(%i)", pMatType ); Con::errorf(ConsoleLogEntry::General, "Material flag:(%i)", pMatFlag );
updated code from processTick
------------------------------------------------------------
if (getContainer()->castRay(oldPosition, newPosition, csmDynamicCollisionMask | csmStaticCollisionMask, &rInfo) == true)
{
Con::errorf(ConsoleLogEntry::General, "Projectile checkpoint 1" );
// make sure the client knows to bounce
if(isServerObject() && (rInfo.object->getType() & csmStaticCollisionMask) == 0)
setMaskBits(BounceMask);
// Next order of business: do we explode on this hit?
Con::errorf(ConsoleLogEntry::General, "PT Arming Delay:(%i)", mDataBlock->armingDelay );
if(mCurrTick > mDataBlock->armingDelay)
{
Con::errorf(ConsoleLogEntry::General, "Projectile checkpoint 2.1" );
mFinalVel = mCurrVelocity;
Point3F simDist = oldPosition - newPosition ;
Point3F realDist = oldPosition - rInfo.point;
F32 scalePart = mSqrt((realDist.x * realDist.x) + (realDist.y * realDist.y) + (realDist.z * realDist.z))
/ mSqrt((simDist.x * simDist.x) + (simDist.y * simDist.y) + (simDist.z * simDist.z));
//Final emission was got by client, lucky us
if(isClientObject())
{
emitParticles(mCurrPosition, rInfo.point, mCurrVelocity, TickMs * scalePart);
if(mInitialPosition != Point3F(0,0,0))
emitParticles(mInitialPosition, mCurrPosition, mCurrVelocity, TickMs * mCurrTick);
makeupParticles = false;
mInitialPosition.set(0, 0, 0);
mFinalVel.set(0, 0, 0);
}
MatrixF xform(true);
xform.setColumn(3, rInfo.point);
setTransform(xform);
mCurrPosition = rInfo.point;
mCurrVelocity = Point3F(0, 0, 0);
// Get the object type before the onCollision call, in case
// the object is destroyed.
U32 objectType = rInfo.object->getType();
// re-enable the collision response on the source object since
// we need to process the onCollision and explode calls
if(mSourceObject)
mSourceObject->enableCollision();
// Ok, here is how this works:
// onCollision is called to notify the server scripts that a collision has occured, then
// a call to explode is made to start the explosion process. The call to explode is made
// twice, once on the server and once on the client.
// The server process is responsible for two things:
// 1) setting the ExplosionMask network bit to guarantee that the client calls explode
// 2) initiate the explosion process on the server scripts
// The client process is responsible for only one thing:
// 1) drawing the appropriate explosion
// It is possible that during the processTick the server may have decided that a hit
// has occured while the client prediction has decided that a hit has not occured.
// In this particular scenario the client will have failed to call onCollision and
// explode during the processTick. However, the explode function will be called
// during the next packet update, due to the ExplosionMask network bit being set.
// onCollision will remain uncalled on the client however, therefore no client
// specific code should be placed inside the function!
//***Nelson's Material Mapping (Projectile Section) Update Start***
if( rInfo.object->getTypeMask() & TerrainObjectType )
{
TerrainBlock* tBlock = static_cast<TerrainBlock*>(rInfo.object);
S32 mapIndex = tBlock->mMPMIndex[0];
if (mapIndex != -1)
{
MaterialPropertyMap* pMatMap = static_cast<MaterialPropertyMap*>(Sim::findObject("MaterialPropertyMap"));
const MaterialPropertyMap::MapEntry* pEntry = pMatMap->getMapEntryFromIndex(mapIndex);
if(pEntry)
{
pMatType = pEntry->matType;
}
}
}
else
{
Con::errorf(ConsoleLogEntry::General, "Projectile checkpoint 2.2" );
MaterialPropertyMap* pMatMap = static_cast<MaterialPropertyMap*>(Sim::findObject("MaterialPropertyMap"));
const MaterialPropertyMap::MapEntry* pMatEnt = pMatMap->getMapEntryFromIndex(rInfo.material);
if (pMatEnt)
{
Con::errorf(ConsoleLogEntry::General, "Projectile checkpoint 2.3" );
pMatType = pMatEnt->matType;
pMatFlag = pMatEnt->matFlags;
Con::errorf(ConsoleLogEntry::General, "PT Material type:(%i)", pMatType );
Con::errorf(ConsoleLogEntry::General, "PT Material flag:(%i)", pMatFlag );
}
if(pMatFlag == 1)
{
Con::errorf(ConsoleLogEntry::General, "Projectile checkpoint 2.4" );
mPiercePosition = newPosition + mCurrVelocity * (F32(TickMs) / 1000.0f);
mPierceVelocity = mCurrVelocity;
}
}
onCollision(rInfo.point, rInfo.normal, rInfo.object);
explode(rInfo.point, rInfo.normal, objectType, mInitialPosition, mFinalVel );
//***Nelson's Material Mapping (Projectile Section) Update Stop***
}from my console log
------------------------------------------------------------
Projectile checkpoint 1 PT Arming Delay:(0) Projectile checkpoint 2.1 Projectile checkpoint 2.2 Projectile checkpoint 2.3 PT Material type:(1) PT Material flag:(1) Projectile checkpoint 2.4 Material type:(1) Material flag:(1) Projectile checkpoint 1 PT Arming Delay:(0) Projectile checkpoint 2.1 Projectile checkpoint 2.2 Projectile checkpoint 2.3 PT Material type:(1) PT Material flag:(1) Projectile checkpoint 2.4 Projectile checkpoint 1 PT Arming Delay:(0) Projectile checkpoint 2.1 Projectile checkpoint 2.2 Projectile checkpoint 2.3 PT Material type:(0) PT Material flag:(0) Material type:(243746944) Material flag:(-65281) Projectile checkpoint 1 PT Arming Delay:(0) Projectile checkpoint 2.1 Projectile checkpoint 2.2 Projectile checkpoint 2.3 PT Material type:(1) PT Material flag:(1) Projectile checkpoint 2.4 Material type:(1) Material flag:(1) Projectile checkpoint 1 PT Arming Delay:(0) Projectile checkpoint 2.1 Projectile checkpoint 2.2 Projectile checkpoint 2.3 PT Material type:(1) PT Material flag:(1) Projectile checkpoint 2.4 Projectile checkpoint 1 PT Arming Delay:(0) Projectile checkpoint 2.1 Projectile checkpoint 2.2 Projectile checkpoint 2.3 PT Material type:(0) PT Material flag:(0) Material type:(0) Material flag:(91229396) Projectile checkpoint 1 PT Arming Delay:(0) Projectile checkpoint 2.1 Projectile checkpoint 2.2 Projectile checkpoint 2.3 PT Material type:(1) PT Material flag:(1) Projectile checkpoint 2.4 Material type:(-1515344467) Material flag:(-1381655404) Projectile checkpoint 1 PT Arming Delay:(0) Projectile checkpoint 2.1 Projectile checkpoint 2.2 Projectile checkpoint 2.3 PT Material type:(0) PT Material flag:(0) Material type:(2071688051) Material flag:(1802204036)
#9
Maybe just before your material checking code, try adding something like
For projectiles, it's possible for them to get ghosted immediately as they explode, especially if you hit something at short range. In that case the raycast on the client may have produced results that were different than the results on the server. If this reallty the problem, you can fix it by adding appropriate code to packUpdate() and unpackUpdate() to ship over your material data.
07/23/2006 (5:06 pm)
Ron, it might be that the material data is different on the ghost(client) object than it is on the server (real) object. Did you add on code to properly ghost over the pMat* members in packupdate() and unpackupdate()? Maybe just before your material checking code, try adding something like
is (isGhost())
{
Con::errorf(ConsoleLogEntry::General, "I'm a ghost!");
}
else
{
Con::errorf(ConsoleLogEntry::General, "I'm not a ghost!");
}or whatever, and then checking if the ghost objects are the ones producing the broken values.For projectiles, it's possible for them to get ghosted immediately as they explode, especially if you hit something at short range. In that case the raycast on the client may have produced results that were different than the results on the server. If this reallty the problem, you can fix it by adding appropriate code to packUpdate() and unpackUpdate() to ship over your material data.
#10
07/23/2006 (6:06 pm)
That sounds exactly like what it is, I worked with the same problems getting particles to render right with projectiles. The raycasts will never happen on the client half the time, especially if it's a really fast projectile. That's why it sends the info to create the explosion from the server to the client based on the server's raycast and not the clients. You could probably add the code you need in the same place.
#11
07/24/2006 (12:42 am)
Indeed, it does seem like the same problem with decals where the server corrects the client simulation at close range and you lose the feature of a bullet decal.
#12
07/24/2006 (6:21 am)
Well gentlemen let me say thank you all very much!! I took Gary's advice and tried the test he listed, and it had shown that it was in fact a ghosting issue. I added the needed code to the packUpdate() and unPackUpdate() and it works perfectly now. Thanks again.
Torque Owner Ronald J Nelson
Code Hammer Games
Material type:(0)
Material flag:(0)
Material type:(0)
Material flag:(0)
Now this confuses me because it appears the material flag is wroking correctly because I only get one set of values if I fire the projectile at an object that the material flag is set to 0.
I should add that the peircing round is actually a second projectile fired from a position that would have been true at the time if the collision had never taken place. The check for this is performed in Torque Script during the weapon's onCollision function where it checks the value of pMaterialF which is pMatFlag passed on through Projectile::initPersistFields() with this statement:
addField("pMaterialF", TypeS32, Offset(pMatFlag, Projectile));Finally, I get all of this with the following code added to materialPropertyMap.cc in the MaterialPropertyMap::addMapping function:
//***Nelson's Material Mapping Update Start*** else if (dStrnicmp(param, "materialType:", dStrlen("materialType:")) == 0) { // Set the detail map const char* pColon = dStrchr(param, ':'); pColon++; while (*pColon == ' ' || *pColon == '\t') pColon++; const char* start = pColon; while(*pColon != ' ' && *pColon != '[[62819ed0c6f21]]') pColon++; const char* end = pColon; pColon++; char buffer[256]; dStrncpy(buffer, start, end - start); buffer[end - start] = '[[62819ed0c6f21]]'; pEntry->matType = dAtoi(buffer); } else if (dStrnicmp(param, "materialFlags:", dStrlen("materialFlags:")) == 0) { // Set the detail map const char* pColon = dStrchr(param, ':'); pColon++; while (*pColon == ' ' || *pColon == '\t') pColon++; const char* start = pColon; while (*pColon != ' ') pColon++; const char* end = pColon; pColon++; char buffer[256]; dStrncpy(buffer, start, end - start); buffer[end - start] = '[[62819ed0c6f21]]'; pEntry->matFlags = dAtoi(buffer); } //***Nelson's Material Mapping Update Stop***I am not sure if the issue is a raycast problem or an issue withing my own code that is causing the projectile to not read in sufficient time. I would sincerely appreciate some help with this, I would even be willing to release my code if I can get this issue resolved and finish up some other enhancements to it.