Game Development Community

Unwanted spawning AIPlayers

by Mark Jonker · in Torque 3D Professional · 10/10/2011 (6:31 am) · 8 replies

Hey all,

I am using T3D Pro 1.1 and I have some problems with unwanted spawning AIPlayers.

In my mission file there are 3 spawn points. 2 Spawn points are for bots and 1 spawn point is for the player itself. When the mission loads it spawns the 2 bots and the player, but it also spawns 2 more AIPlayers on the same location as the spawn point of the player. The unwanted AIPlayers have no name and have, according to T3D World editors object editor, as parentgroup "servergroup".

Since I don't have anything in my mission file that indicate that the AIPlayers should be spawned and use parentgroup "servergroup" I am wondering what else could cause these AIPlayers to spawn.

My mission file is as follow:

//--- OBJECT WRITE BEGIN ---
new SimGroup(MissionGroup) {
   canSave = "1";
   canSaveDynamicFields = "1";
      enabled = "1";

   new LevelInfo(theLevelInfo) {
      nearClip = "0.1";
      visibleDistance = "2000";
      decalBias = "0.0015";
      fogColor = "0.9 0.9 1 1";
      fogDensity = "0.001";
      fogDensityOffset = "10";
      fogAtmosphereHeight = "100";
      canvasClearColor = "220 230 240 255";
      ambientLightBlendPhase = "1";
      ambientLightBlendCurve = "0 0 -1 -1";
      advancedLightmapSupport = "0";
      soundAmbience = "AudioAmbienceDefault";
      soundDistanceModel = "Linear";
      canSave = "1";
      canSaveDynamicFields = "1";
         desc0 = "The main terrain ready to be populated with Torque objects.";
         LevelName = "Main Terrain";
   };
   new SimGroup(environment) {
      canSave = "1";
      canSaveDynamicFields = "1";

      new ScatterSky() {
         skyBrightness = "30";
         mieScattering = "0.0015";
         rayleighScattering = "0.0035";
         sunScale = "1 1 0.8 1";
         ambientScale = "0.5 0.5 0.4 1";
         fogScale = "1 1 1 1";
         exposure = "0.85";
         azimuth = "84";
         elevation = "54";
         moonAzimuth = "0";
         moonElevation = "45";
         castShadows = "1";
         brightness = "1";
         flareScale = "1";
         nightColor = "0.0196078 0.0117647 0.109804 1";
         nightFogColor = "0.0196078 0.0117647 0.109804 1";
         moonEnabled = "1";
         moonScale = "0.3";
         moonLightColor = "0.192157 0.192157 0.192157 1";
         useNightCubemap = "0";
         attenuationRatio = "0 1 1";
         shadowType = "PSSM";
         texSize = "1024";
         overDarkFactor = "3000 2000 1000 250";
         shadowDistance = "400";
         shadowSoftness = "0.25";
         numSplits = "4";
         logWeight = "0.96";
         fadeStartDistance = "325";
         lastSplitTerrainOnly = "0";
         representedInLightmap = "0";
         shadowDarkenColor = "0 0 0 -1";
         includeLightmappedGeometryInShadow = "0";
         position = "0 0 0";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         canSave = "1";
         canSaveDynamicFields = "1";
            moonTexture = "core/art/skies/night/moon_wglow";
            moonTint = "0.192157 0.192157 0.192157 1";
            sunBrightness = "50";
      };
      new TerrainBlock(theTerrain) {
         terrainFile = "art/terrains/Empty Terrain_0.ter";
         castShadows = "1";
         squareSize = "2";
         baseTexSize = "1024";
         lightMapSize = "256";
         screenError = "16";
         position = "-1024 -1024 0";
         rotation = "1 0 0 0";
         canSave = "1";
         canSaveDynamicFields = "1";
            scale = "1 1 1";
            tile = "0";
      };
      new WaterBlock(theWater) {
         gridElementSize = "10";
         gridSize = "10";
         density = "1";
         viscosity = "1";
         liquidType = "Water";
         baseColor = "45 108 171 255";
         fresnelBias = "0.3";
         fresnelPower = "6";
         specularPower = "48";
         specularColor = "1 1 1 1";
         emissive = "0";
         waveDir[0] = "0 1";
         waveDir[1] = "0.707 0.707";
         waveDir[2] = "0.5 0.86";
         waveSpeed[0] = "1";
         waveSpeed[1] = "1";
         waveSpeed[2] = "1";
         waveMagnitude[0] = "0.2";
         waveMagnitude[1] = "0.2";
         waveMagnitude[2] = "0.2";
         overallWaveMagnitude = "1";
         rippleTex = "core/art/water/noise02";
         rippleDir[0] = "0 1";
         rippleDir[1] = "0.707 0.707";
         rippleDir[2] = "0.5 0.86";
         rippleSpeed[0] = "-0.065";
         rippleSpeed[1] = "0.09";
         rippleSpeed[2] = "0.04";
         rippleTexScale[0] = "7.14 7.14";
         rippleTexScale[1] = "6.25 12.5";
         rippleTexScale[2] = "50 50";
         rippleMagnitude[0] = "1";
         rippleMagnitude[1] = "1";
         rippleMagnitude[2] = "0.3";
         overallRippleMagnitude = "1";
         foamTex = "core/art/water/foam";
         foamDir[0] = "1 0";
         foamDir[1] = "0 1";
         foamSpeed[0] = "0";
         foamSpeed[1] = "0";
         foamTexScale[0] = "1 1";
         foamTexScale[1] = "3 3";
         foamOpacity[0] = "0";
         foamOpacity[1] = "0";
         overallFoamOpacity = "1";
         foamMaxDepth = "2";
         foamAmbientLerp = "0.5";
         foamRippleInfluence = "0.05";
         cubemap = "DefaultSkyCubemap";
         fullReflect = "0";
         reflectivity = "0.5";
         reflectPriority = "1";
         reflectMaxRateMs = "15";
         reflectDetailAdjust = "1";
         reflectNormalUp = "1";
         useOcclusionQuery = "1";
         reflectTexSize = "256";
         waterFogDensity = "0.1";
         waterFogDensityOffset = "1";
         wetDepth = "1.5";
         wetDarkening = "0.2";
         depthGradientMax = "50";
         distortStartDist = "0.1";
         distortEndDist = "20";
         distortFullDepth = "3.5";
         clarity = "0.5";
         underwaterColor = "0 0 0 0";
         position = "0 0 39.6837";
         rotation = "1 0 0 0";
         scale = "1024 1024 50";
         canSave = "1";
         canSaveDynamicFields = "1";
            foamColorModulate = "0.5 0.5 0.5";
            foamScale = "1";
      };
   };
   new SimGroup(NPCDropPoints) {
      canSave = "1";
      canSaveDynamicFields = "1";
         enabled = "1";

      new SpawnSphere(npcSpawn001) {
         spawnClass = "AIPlayer";
         spawnDatablock = "GideonData";
         spawnScript = "if(!isObject(NPC001)) AIPlayer::spawnNPC(NPC001, npcSpawn001);";
         autoSpawn = "1";
         radius = "1";
         sphereWeight = "1";
         indoorWeight = "1";
         outdoorWeight = "1";
         dataBlock = "SpawnSphereMarker";
         position = "11 6 62";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         canSave = "1";
         canSaveDynamicFields = "1";
            enabled = "1";
      };
   };
   new SimGroup(MOBDropPoints) {
      canSave = "1";
      canSaveDynamicFields = "1";
         enabled = "1";

      new SpawnSphere(mobSpawn001) {
         spawnClass = "AIPlayer";
         spawnDatablock = "GideonData";
         spawnScript = "if(!isObject(MOB001)) AIPlayer::spawnMOB(MOB001, mobSpawn001);";
         autoSpawn = "1";
         radius = "1";
         sphereWeight = "1";
         indoorWeight = "1";
         outdoorWeight = "1";
         dataBlock = "SpawnSphereMarker";
         position = "13 2 62";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         canSave = "1";
         canSaveDynamicFields = "1";
            enabled = "1";
      };
   };
   new SimGroup(PlayerDropPoints2) {
      canSave = "1";
      canSaveDynamicFields = "1";
         enabled = "1";

      new SpawnSphere(playerSpawn2) {
         spawnClass = "AIPlayer";
         spawnDatablock = "GideonData";
         spawnScript = "%client.camera.setOrbitObject($SpawnObject, mDegToRad(30) @ \" 0 0\", 0, 7, 7);";
         autoSpawn = "0";
         radius = "1";
         sphereWeight = "1";
         indoorWeight = "1";
         outdoorWeight = "1";
         dataBlock = "SpawnSphereMarker";
         position = "0 0 67.7332";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         canSave = "1";
         canSaveDynamicFields = "1";
            enabled = "1";
      };
   };
};
//--- OBJECT WRITE END ---

The code for function AIPlayer::spawnNPC():
(The function AIPlayer::spawnMOB() is basically the same just different names)

function AIPlayer::spawnNPC(%name, %spawnPoint) {
   %player = PlayerData::createNPC(NPCMale);
   %player.setShapeName(%name);
   %player.setTransform(%spawnPoint.getTransform());
   echo(%name @ " has spawned at " @ %spawnPoint @ " (" @ %spawnPoint.getPosition() @ ")");
   
   return (%player);
}

The code for PlayerData::createNPC():

function PlayerData::createNPC(%block) {
   %obj = new AIPlayer() {
      datablock = %block;
      aiPlayer = true;
      ... (I have more settings here but none that are important for this problem)
   };
   
   return (%obj);
}

And the datablock for the NPCMale:

datablock PlayerData (NPCMale : GideonData) {
   category = "NPC Characters";  // Add to editor
   shapeFile = "art/shapes/actors/Gideon/gideon.dts";
   
   mass = 90;
   drag = 0.3;
   maxdrag = 0.4;
   density = 100;
   maxDamage = 100;
   maxEnergy = 100;
   repairRate = 0.33;
   energyPerDamagePoint = 5.0;
   
};

In the link below there is a screenshot of what I basically mean with the unwanted AIPlayers.

www.connectie.eu/images/ghost-objects.png

If anyone have an idea what the problem could be then please let me know.

#1
10/10/2011 (9:19 am)
One thing involved would be the Spawnpoint itself:
new SimGroup(PlayerDropPoints2) {  
      canSave = "1";  
      canSaveDynamicFields = "1";  
         enabled = "1";  
  
      new SpawnSphere(playerSpawn2) {  
         spawnClass = "AIPlayer";  
         spawnDatablock = "GideonData";


as in the core/.../spawn.cs file:
function GameConnection::spawnPlayer(%this, %spawnPoint, %noControl)
{
   if (isObject(%this.player))
   {
      // The client should not already have a player. Assigning
      // a new one could result in an uncontrolled player object.
      error("Attempting to create a player for a client that already has one!");
   }

   // Attempt to treat %spawnPoint as an object
   if (getWordCount(%spawnPoint) == 1 && isObject(%spawnPoint))
   {
      // Defaults
      %spawnClass      = $Game::DefaultPlayerClass;
      %spawnDataBlock  = $Game::DefaultPlayerDataBlock;

      // Overrides by the %spawnPoint
      if (isDefined("%spawnPoint.spawnClass"))
      {
         %spawnClass = %spawnPoint.spawnClass;
         %spawnDataBlock = %spawnPoint.spawnDatablock;
      }

      // This may seem redundant given the above but it allows
      // the SpawnSphere to override the datablock without
      // overriding the default player class
      if (isDefined("%spawnPoint.spawnDatablock"))
         %spawnDataBlock = %spawnPoint.spawnDatablock;

Its using the SpawnClass setting for the SpawnPoint..
All your Spawn Points are set for AiSpawns.
#2
10/11/2011 (1:53 am)
Thank you for the information but if I change the spawnClass for the player I still have the same problem.

The strange thing is that when I add an echo line to the spawnPlayer function it never shows up in the log. So I am wondering if it even gets to that function or that it somehow skips it but still spawns a player, if that is even possible.

function GameConnection::spawnPlayer(%this, %spawnPoint, %noControl)
{
   echo("======== GameConnection::spawnPlayer spawn.cs (199) ========");
   if (isObject(%this.player))
   {
      // The client should not already have a player. Assigning
      // a new one could result in an uncontrolled player object.
      error("Attempting to create a player for a client that already has one!");
   }

I even tried a few echo test in the "if statements" inside the function but none seem to show up in the log file.

I found another spawn function in gameCore.cs

function GameConnection::spawnPlayer(%this, %spawnPoint)
   {
      echo("======== GameConnection::spawnPlayer in gameCore.cs (353) ========");
      Game.spawnPlayer(%this, %spawnPoint);
   }

but that one also does not log the echo test.
#3
10/11/2011 (7:09 am)
Make sure you're working in the scripts folder instead of the core/scripts folder because the version of the script that is loaded last is the version the engine uses - and Core is loaded first.

Additionally,
new SpawnSphere(playerSpawn2) {  
         spawnClass = "AIPlayer";  
         spawnDatablock = "GideonData";  
         spawnScript = "%client.camera.setOrbitObject($SpawnObject, mDegToRad(30) @ " 0 0", 0, 7, 7);";  

 ....

should probably read

new SpawnSphere(playerSpawn2) {  
         spawnClass = "Player";  // NOT AIPlayer
         spawnDatablock = "GideonData";  
         spawnScript = "%client.camera.setOrbitObject($SpawnObject, mDegToRad(30) @ " 0 0", 0, 7, 7);";  

  ....

If you changed the player's class to AIPlayer, change it back to Player.
#4
10/11/2011 (7:52 am)
Ok so if there is a GameConnection::spawnPlayer() function in a file in the "core/scripts" folder and also in a file in the "scripts" folder then editing the one in "core/scripts" is useless?

Makes me wonder why the function is in the "core/scripts" folder to begin with.


I changed back the spawnClass to "Player" but that does not solve the problem it only gives me one more.

The function I use to move the player by mouse click does not work anymore when I use the Player as spawnClass.

function serverCmdMoveToPosition(%client, %pos, %start, %ray) {
        // Find end of search vector
        %ray = VectorScale(%ray, 2000);
        %end = VectorAdd(%start, %ray);

        // Only care about terrain objects
        %searchMasks = $TypeMasks::TerrainObjectType;

        // search!
        %scanTarg = ContainerRayCast(%start, %end, %searchMasks);

        if (%scanTarg)
                %client.player.setMoveDestination(getWords(%scanTarg, 1, 3));
}

That function only works when I set the spawnClass to AIPlayer. This because the Player does not have the setMoveDestination function if I am correct, so that is why I used the AIPlayer to begin with.
#5
10/11/2011 (8:17 am)
Ok, so, you're using the RTS Prototype control setup? In that case, you are correct - you cannot control your player. Let me think on this a minute.

The Core folder is for base functionality. In theory, it is the last fall-back if you don't have something in your main scripts folder. It is something that people have been confused over for a while and there has been talk of changing it - but for now, realize that if it exists in core/scripts and scripts/ then the scripts/ version is going to override the core.

Also, the scripts/gameCoreDM.cs file contains the DeathMatch package which is loaded by default, so technically this is the final spot unless you remove the deathmatch package. For most things you won't need to worry about this file, though.
#6
10/11/2011 (8:27 am)
Ok that I understand and I can work with.

I also figured out that it is the function GameCore::spawnPlayer() that is responsible for the spawning and not the function GameConnection::spawnPlayer().

But I still haven't found a solution for the spawns, changing the playerClass back to "Player" does not help in my case.

Would it help if I made a new playerClass that has mostly the same functions as the AIPlayer but with a different name of course?
#7
10/11/2011 (9:20 am)
I was starting to think along the lines of making a copy of the GideonData datablock, naming it GideonPlayerData and testing for that in your GameCore::spawnPlayer() function to decide which spawn point to use.
#8
10/11/2011 (11:11 am)
Quote:Ok, so, you're using the RTS Prototype control setup? In that case, you are correct - you cannot control your player. Let me think on this a minute.

Sorry did not see that earlier, but yes I am using the RTS Prototype with some modifications.


Making a copy of the GideonData datablock did not really help and I could not figure out how to use it to find the spawn point I needed to use.

I did find a solution, maybe not a good one but it works, by changing:

new SimGroup(NPCDropPoints) {  
      canSave = "1";  
      canSaveDynamicFields = "1";  
         enabled = "1";  
  
      new SpawnSphere(npcSpawn001) {  
         spawnClass = "AIPlayer";  
         spawnDatablock = "GideonData";  
         spawnScript = "if(!isObject(NPC001)) AIPlayer::spawnNPC(NPC001, npcSpawn001);";  
         autoSpawn = "1";
         ....

new SimGroup(MOBDropPoints) {  
      canSave = "1";  
      canSaveDynamicFields = "1";  
         enabled = "1";  
  
      new SpawnSphere(mobSpawn001) {  
         spawnClass = "AIPlayer";  
         spawnDatablock = "GideonData";  
         spawnScript = "if(!isObject(MOB001)) AIPlayer::spawnMOB(MOB001, mobSpawn001);";  
         autoSpawn = "1";
         ....

to:

new SimGroup(NPCDropPoints) {  
      canSave = "1";  
      canSaveDynamicFields = "1";  
         enabled = "1";  
  
      new SpawnSphere(npcSpawn001) {  
         spawnClass = "AIPlayer";  
         spawnDatablock = "GideonData";  
         spawnScript = "if(!isObject(NPC001)) AIPlayer::spawnNPC(NPC001, npcSpawn001);";  
         autoSpawn = "0";
         ....

new SimGroup(MOBDropPoints) {  
      canSave = "1";  
      canSaveDynamicFields = "1";  
         enabled = "1";  
  
      new SpawnSphere(mobSpawn001) {  
         spawnClass = "AIPlayer";  
         spawnDatablock = "GideonData";  
         spawnScript = "if(!isObject(MOB001)) AIPlayer::spawnMOB(MOB001, mobSpawn001);";  
         autoSpawn = "0";
         ....

I turned the autoSpawn off so they would not load while the mission file is loaded. After doing this I created two functions to load the AIPlayers right after loading the mission file.

Now when the player spawns it has two AIPlayers and one Player, the Player still has AIPlayer as spawnClass but I need this for moving around.