Jump to content

Trying to Compile Engine Changes(TAIK) using Linux


Jason Campbell

Recommended Posts

I recently have been using Torque 3D 3.5 in WINE on Linux so I can utilize Bryce's incredible Tactical AI Kit. Nothing would make me happier then getting TAIK to work natively in Linux. Looking at the changes, it may be possible even in 3,10. I could continue in 3.5 but there are some issues with using WINE, crashes and what not, though performance is surprisingly good.


My questions is basically, how do I add new files to the Engine if I can't use the Project Solution from Visual Studio?


How do I add files,filters and existing items using CMAKE?


Any help or tips would be greatly appreciated.

Link to comment
Share on other sites

Thanks, that might work. Plus, I was wondering exactly how to add modules anyway.


The reason it might not work is that, there is a folder named recast inside of a folder named nav and his example in Visual studio has recast nested in nav, as "filters". I thought I had it set up in Code::Blocks but I can't do it again.


Anyway, just to clarify, I could add afx using CMAKE GUI or by editing CMakeCache.txt?


Thanks for responding.

Link to comment
Share on other sites

God, I'm so close to getting this working.


Originally Bryce said that any NavMesh and Recast will work fine as long as NavMesh is called Mesh1.


Well I finally got it to Build with 0 errors and everything seems to work except the NavMesh is not seen. The AI tries to walk the NavPath but fails. Here is the error

 

==>SpawnAI(0,0,2);
No NavMesh polygon near visit point (0, 0, 0) of NavPath 21855
brain.weapon = TAIKGunImage, brain.ammo = TAIKGunAmmo
AI player spawned. Id: 21852. Team: 0. Brain: 21856
21852
No NavMesh polygon near visit point (32.0894, 44.4581, 4.63566) of NavPath 21855
Set::getObject - index out of range.
scripts/server/ai/aiplayer/aiplayer.cs (862): Unable to find object: '' attempting to call function 'getPosition'
21852: On path 20701, moving to node at index 0
No NavMesh polygon near visit point (32.0894, 44.4581, 4.63566) of NavPath 21855
Set::getObject - index out of range.
scripts/server/ai/aiplayer/aiplayer.cs (862): Unable to find object: '' attempting to call function 'getPosition'
21852: On path 20701, moving to node at index 0

 

I saw this error in an old GG post of Daniel's and tried his suggestion of changing mTypeMask |= StaticShapeObjectType | MarkerObjectType; to mTypeMask |= MarkerObjectType; but that didn't fix it.


This is killing me. Any suggestion, please.




One other thing. I'm getting a crash every so often

 

Torque3D-3.10/Engine/source/core/stream/bitStream.cpp(339,0): {Fatal} - BitStream::writeInt: value out of range: -23/128 (7 bits)

 

I searched and it seems to be a network problem? I'm not checking my network when it occurs. Any thoughts on that would be appreciated.


Thank you

Link to comment
Share on other sites

Well, I can say -23/128 (7 bits) report tells us you're sending something along the network that expects a 7 bit range of 0-128, and it thinks youre trying to feed it a -23 (could be that, or could be wrapping. Half the reason for throwing that in for folks a while back was it used to be a silent network leak that would corrupt other stuff down the line. With that, should be able to turn up the exact cause with a stack trace.)

Link to comment
Share on other sites

  • 2 weeks later...

I can't believe but it appears I have everything working correctly. I didn't think I would get this far really. I seemed to have squashed the other "value out range" problems but have a new one and I'm going mad. I haven't slept well in days. Okay.


This is the new one

Engine/source/core/stream/bitStream.cpp(339,0): {Fatal} - BitStream::writeInt: value out of range: -1/64 (6 bits)

 

I'm pretty sure it stems from this in player.cpp

stream->writeSignedFloat(fTranquilized, 6);

 

It seems to be a variable that effects speed while the players are zoomed and it crashes almost every time when I'm getting melee'd by an AIPlayer.


I'm just going to post the snippets from everywhere I can find it. Maybe if someone can think of a work around to keep it a positive number or something. It seems to be consistently fatal with a -1 value.


Any help would be appreciated. Thank you.


player.h

488         F32 fTranquilized;
 
733         void Player::setTranquilized(const F32 & tranquilized);  
734         const F32 & Player::getTranquilized();

 

player.cpp

1673        fTranquilized=0.0f;
 
2801                 if(doStandardMove)
2802                {
2803                         F32 p = move->pitch * (mPose == SprintPose ? mDataBlock->sprintPitchScale : 1.0f);
2804		 if (fTranquilized>0.0f) p+=fTranquilized * mSin((F32)Sim::getCurrentTime()/200.0f); //TAIKWeapons++
2805                     if (p > M_PI_F) 
2806                        p -= M_2PI_F;
2807                     mHead.x = mClampF(mHead.x + p,mDataBlock->minLookAngle,
2808                                         mDataBlock->maxLookAngle);
 
2836                    F32 y = move->yaw * (mPose == SprintPose ? mDataBlock->sprintYawScale : 1.0f);
2837		 if (fTranquilized>0.0f) y+=fTranquilized * mCos((F32)Sim::getCurrentTime()/300.0f); //TAIKWeapons++
2838                      if (y > M_PI_F)
2839                       y -= M_2PI_F;
 
6833                  stream->writeSignedFloat(fTranquilized, 6); 
 
6929                   fTranquilized = stream->readSignedFloat(6);
 
 
(lines 7131 to 7149)
ConsoleMethod( Player, IsTranquilized, F32, 2, 2, "Return if tranquilizer is enabled.")  
{  
   Player* obj = static_cast(object);  
   return obj->getTranquilized();  
}  
 
ConsoleMethod( Player, SetTranquilized, void, 3, 3, "(F32) Sets tranquilizer.")  
{  
   Player* obj = static_cast(object);  
   obj->setTranquilized(dAtof(argv[2]));  
} 
 
const F32 & Player::getTranquilized() {  
    return fTranquilized;  
}  
 
void Player::setTranquilized(const F32 & tranquilized) {  
    fTranquilized = tranquilized;  
}

 


TorqueScript(TAIKZoom.cs)

function serverCmdCallZoomFunction( %client, %out )
{
   %zoomer = %client.getControlObject();
   //%curWeapon = %zoomer.getMountedImage($WeaponSlot).item.getName();
   //%curWeapon = %zoomer.getMountedImage($WeaponSlot);
   %zoomer.handleZoom(%out);
}
 
function Player::handleZoom(%this,%out)
{
 
  %iS = %this.getImageState(0);
  if (%this.isLeaning && !%out)
    return;
  if (%is $= "GLReady" || %is $= "GLActivate" || %is $= "GLPutAway" || %is $= "GLReload")
    return;
  if (%iS $= "ReloadClip")
    %out = true;
  if (%iS !$= "Ready" && %is !$= "NoAmmo" && %is !$= "DryFire" && %is !$= "Activate")
    %out = true;
 
  if (!%this.zoomOn && !%out)
  {
    %this.zoomOn = true;
    %this.setSpeedMult(0.5);
    %this.setTranquilized(0.0002);
    // Figure out what type of sights we should be using
    if (%this.getMountedImage(2))
    {
      if (%this.getMountedImage(2).getName() $= "M68Image" || %this.getMountedImage(2).getName() $= "SquareDotImage"
          || %this.getMountedImage(2).getName() $= "CMoreImage" || %this.getMountedImage(2).getName() $= "GlockDotImage"
          || %this.getMountedImage(2).getName() $= "EOTechImage" || %this.getMountedImage(2).getName() $= "AKDotImage"
          || %this.getMountedImage(2).getName() $= "F2000DotImage")
      {
        // Red dot
        %sightType = 2;
      }
      else if (%this.getMountedImage(2).getName() $= "AUGScopeImage")
      {
      	 //2x AUG Scope
      	%sightType = 5;
      }
      else if (%this.getMountedImage(2).getName() $= "M4HandleImage" || %this.getMountedImage(2).getName() $= "M16HandleImage" || %this.getMountedImage(2).getName() $= "F2000IronImage")
      {
      	// Iron sight
      	%sightType = 1;
      }
      else
      {
        // ACOG
        if (%this.getMountedImage(2).getName() $= "ACOG1Image" || %this.getMountedImage(2).getName() $= "AKACOGImage")
        	%sightType = 3;
        else
          %sightType = 4; // Default sniper scope
      }
    }
    else
    {
      if (%this.getMountedImage(0).permanentScope)
      {
        // Scope that cannot be dismounted
        %sightType = 3;
      }
      else
      {
        // Iron sights
        %sightType = 1;
      }
    }
  }
  else
  {
    %this.zoomOn = false;
    %sightType = 0;
    %this.setSpeedMult(1.0);
    %this.setTranquilized(0);
  }
  %cScope = %this.getMountedImage(0).scope;
  %wName = %this.getMountedImage(0).getName();
  if (%wName $= "M24Image" || %wName $= "M110Image" || %wName $= "M14Image")
    if (%sightType != 3)
      %cScope = "M24Scope";
  commandToClient(%this.client,'ZoomClientSide',%sightType,%this.getMountedImage(0).getName(),%cScope);
}
Link to comment
Share on other sites

Dude, you probably have enough on your plate. Heh.


I decided to try and eliminate all other errors in the console first and don't why I didn't notice this. Since it seemed to always occur during "fight3" I bypassed it for a bit and it became the next AI Melee TakeDown, in this case attack2. All sounds seem to work but this is clearly a problem.

 

SFXProfile((null))::onAdd: The preload failed!
SFXSound::_create() - Could not create device buffer!
SFXSystem::createSource() - Failed to create sound!
  Profile: (null)
  Filename: 
Loading SFX: art/sound/TAIKTakedowns/fight2 (1 channels, 44 kHz, 3.83 sec, 330 kb)

 

Could it be that simple as a Null in SFX? If so I don't get where to hunt this down.


This is the Takedown audio code but from the echos and also that it loads the right sound, it seems to work.

 

function playFightAudio(%person,%description,%filename,%pos)
{
   %person.fightSoundSource = sfxPlayOnce(%description,"art/sound/TAIKTakedowns/" @ %filename,getWord(%pos,0),getWord(%pos,1),getWord(%pos,2));
   echo("person" @ %person.fightSoundSource);
   echo(%filename);
   echo(%pos);
 
  // Make AIPlayers turn their heads if this happens close to them
  //  The idea is that if we're going to stab someone standing next to their friend...
  //    ...their friend should probably notice the scuffle.
  AlertAIPlayers(%person.getPosition(),8,0,"Annoyance",1,%person,0,0,%person.team);
}

 


edit: Found this and it looks complicated enough...


 

function attack3(%win,%lose)
{
  %prefix = "FT3_"; // Animation name is this + "loser" or "winner", e.g. FT1_Winner, or FT1_Loser
  %winOffsetFromLose = "0 1 0"; // Winner should perform this takedown 1m in front of loser
  %loseOffsetFromWin = ""; // Loser of this takedown should stay put
  %initPadTime = 100; // 10ms before playing animations, enough time to get everyone to stop what they're doing
  %lookCode = 1; // 1 = Winner looks toward loser, 2= loser looks toward winner
  %winFightTime = 2200 + %initPadTime; // Time in ms until the winner is done with the fight, and control is re-acquired.
  %loseFightTime = 3500 + %initPadTime; // How long until the loser is given their control binds back (though they're dead, they may want to respawn)
  %noReturnTime = 1340; // Time (ms) until victim is officially dead. %lose can escape the fight if %win dies before this time has elapsed.
  %disarmTime = 3300; // Time (ms) until victim drops their gun
 
  %p = %win.prepActor(%lose,%winOffsetFromLose,%loseOffsetFromWin,%lookCode);
  if (%p == -1)
    return;
  %lose.prepActor(%win,"","",0);
  %lose.fightKiller = %win;
  %win.fightVictim = %lose;
  %win.ensureLookingAtVictim(%lose,%winFightTime);
 
  schedule(%initPadTime,0,attack3_action,%win,%lose,%prefix);
  %lose.schedule(%noReturnTime,takedownDeath,%win);
 
  %win.weaponSched[0] = %win.schedule(500,mountImage,TAIKKnifeImage,0);
 
  %win.schedule(%winFightTime,leaveFight);
  %lose.schedule(%loseFightTime,leaveFight);
  %lose.schedule(%disarmTime,holsterWeapon);
  %win.holsterWeapon();
}
 
function attack3_action(%win,%lose,%prefix)
{
  if (%win.getState() $= "Dead" || %lose.getState() $= "Dead") return;
  %win.destroyThread(0);
  %lose.destroyThread(0);
  %win.setActionThread(%prefix @ "Winner");
  %lose.setActionThread(%prefix @ "Loser");
 
  playFightAudio(%win,AudioClosest3D,"fight3",%lose.getWorldBoxCenter()); 
}
Link to comment
Share on other sites

well... I can say quite a few script-exposed variables default to -1... If it's a case of the sucker getting referenced before it's set to a new value, that'd give you you that kind of output... Can't think of any 6-bit values used though with that...

Link to comment
Share on other sites

I can't figure out gdb debugger very well but I got a backtrace to show me shapebase.cpp or player.cpp is where the writeInt occurs.


For a while I thought it was this.

stream->writeInt(image.imageMountNode,6);


It mounts attachments to weapons but a made it zero right before the writeInt so it always returned zero and it didn't do a thing.


I just did a trace(1);


And perhaps it's this. These lines are the last bunch. Must be in player or aiplayer.

 

Entering AIPlayer::onCollision(23384, 23123)
   Leaving AIPlayer::onCollision() - return 
Leaving SpecOpsRifleman::onCollision() - return 
Entering SpecOpsRifleman::onCollision(699, 23123, 23384)
   Entering AIPlayer::onCollision(23123, 23384)
   Leaving AIPlayer::onCollision() - return 
Leaving SpecOpsRifleman::onCollision() - return 
Entering SpecOpsRifleman::onCollision(699, 23799, 21842)
   Entering AIPlayer::onCollision(23799, 21842)
   Leaving AIPlayer::onCollision() - return 
Leaving SpecOpsRifleman::onCollision() - return 
Entering SpecOpsRifleman::onCollision(699, 23799, 21514)
   Entering AIPlayer::onCollision(23799, 21514)
   Leaving AIPlayer::onCollision() - return 
Leaving SpecOpsRifleman::onCollision() - return 
Entering OpforRifleman::onCollision(700, 21514, 23799)
   Entering AIPlayer::onCollision(21514, 23799)
   Leaving AIPlayer::onCollision() - return 
Leaving OpforRifleman::onCollision() - return 
Entering OpforRifleman::onCollision(700, 21524, 21842)
   Entering AIPlayer::onCollision(21524, 21842)
   Leaving AIPlayer::onCollision() - return 
Leaving OpforRifleman::onCollision() - return
Link to comment
Share on other sites

Hey guys, the animation was screwed up for takedowns, Case sensitivity of Linux has made it tough to squash all the bugs. Anyway, I really thought that had done the trick but then the 7bit Fatal started again that I thought I had fixed.


So I disabled the Fatal breakpoint in bitstream.cpp and played the example mission again and again. My memory usage was high but steady. Same usage as before (900MB with 16 AI) just seems quite a bit higher then the Windows version, which is Torque 3,5(460MB). I checked to see if it was a Linux thing and the Example FPS level from 3,10 is around 640MB when I added a NavMesh and some stock AI.


Anyway, question is, what kind of trouble will I most likely run into by disabling the Fatal interrupt?


Thanks

Link to comment
Share on other sites

You won't be catching uninitialized variables, out of range values, and subtle bugs of that nature. Certain extensions of the engine go particularly fatal there in incredibly non-obvious ways, beyond just 'well, lets go ahead and use the wrong value anyway'..

Link to comment
Share on other sites

I've figured out the gdb debugger a little more and have been able to examine the backtrace frame by frame,, so I can find the exact line that caused the errors. Unfortunately, examining the local variables doesn't help much and every time I stop one, another pops up. Another thing, that -1/64 6 bit Fatal was not an Int, it was a Float name mRot, some sort of rotation calculation. After examining it, I realized that there was no real way to find out how it got to a -1 value. I used a real cheap method of catching it before it was written and checking if it was a negative number and if so, making it zero. I have no idea if that would make it worse? Also if it is a float, shouldn't it be -1.0? My c++ knowledge is limited.


Strangely the actual AI is getting better as I figure out more, it seems to be better then the original Windows 3.5 version I had compiled without errors, subtle things. Makes me think that I had errors in that version that I didn't even know about.


I've come so far, there is no way I'm giving up but it seems like a terrible game of wack-a-mole that never ends.


I have another question. In your experience can TorqueScript errors throw an error into the c++ code? Reason I'm asking is, I'm concentrating so much on the source code but may be making it worse. Some of the TS errors may be caused by conflicts in the source code, I'm guessing, but should I attempt to remove all errors from the console then work on the source code?


Thanks again.

Link to comment
Share on other sites

https://github.com/GarageGames/Torque3D/blob/c83efa59e0a11fc15c68afaf106807643191ac6f/Engine/source/core/stream/bitStream.cpp#L337-L347 first and last lines are why shoving a TS float value can trigger that. prolly does help verifiably isolate that down to a readFloat(&foo,6) in a packupdate or packdata then. fars TS errors goes, you'll recall that a .cs file will attempt to execute up to the point it hits a compilation flaw and stop there, so... pooooosssibly?


With more data, sounds like I'd eyeball

https://github.com/GarageGames/Torque3D/blob/7185d9664d7ee8c0469014acce9caad6d1380ea2/Engine/source/T3D/player.cpp#L6225-L6227

+

https://github.com/GarageGames/Torque3D/blob/7185d9664d7ee8c0469014acce9caad6d1380ea2/Engine/source/T3D/player.cpp#L6330-L6332

Link to comment
Share on other sites

Well, you are right about the lines making the problem. It was this line, and it was a 7bit not the 6bit I talked about:

https://github.com/GarageGames/Torque3D/blob/7185d9664d7ee8c0469014acce9caad6d1380ea2/Engine/source/T3D/player.cpp#L6225


I don't understand really how to fix it.


I wrote this stupid bit of code into it and it stopped the Fatal but honestly it can't be good.

if ((mRot.z / M_2PI_F) < 0)
      {
          mRot.z = 0;
      }
      if ((mRot.z / M_2PI_F) >= 0)
      {
      stream->writeFloat(mRot.z / M_2PI_F, 7);
    }

 

My newest error is being kicked off the server with a window telling me I don't have Full or access to some assets, I will write it down next time.


I was wondering could this cause a problem, since Float isn't defined?

https://github.com/GarageGames/Torque3D/blob/7185d9664d7ee8c0469014acce9caad6d1380ea2/Engine/source/T3D/player.cpp#L6080


Thanks again Az

Link to comment
Share on other sites

Ok. so. Cliffsnotes on write, writefloat, writePacketData, and packUpdate


1)write/read packetdata or pack/unpack update, (or, to be thorough pack/unpack Data are paired methods. meaning if it goes in in one form in one order in a write, it needs to come out in the exact same order, and in the exact same form in a read. Mismatching can lead to leakage, since it's literally decoding bits. (so if for instance you had write{bool a, float b} and read{float b, bool a}, you'd actually be getting the true/false tacked on to float b and it's last bit thrown over to bool a in the read. common cause of 'hey this data went corrupt' aka 'These Aren't The Datablocks You're Looking For'}


2) in order of frequency run:

A) packData/unpackData: done once on loading a mission. these are your datablock setters/getters.

B) writePacketData/readPacketData: sent to every client in scope (scope gets a bit complex for a quick primer, so we'll skip that)

C) packUpdate/unpackUpdate: sent to a given controlled client alone. So stuff like personal energy level. (forget offhand if that's set to update at a higher rate than the PacketData pair.


3)straight write() / read() calls use the full 32 bits in a float. (Basically uses a sizeof() lookup) while writefloat lets you specify the size you're using in a lossy manner. why it's generally a Bad Thing to go lower than 6ish, and can conversely add up pretty bad if you just run with 32s.


That help any?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...