Search Unity

Adjust gameobject's Y axis from an MMO server (3d)

Discussion in 'Scripting' started by Blarp, Oct 30, 2016.

  1. Blarp

    Blarp

    Joined:
    May 13, 2014
    Posts:
    269
    Background:
    My project is a 3d MMO in WebGL. The server-side code I'm using is reverse engineered from the actual game and has been around for 15+ years. Everyone uses the traditional release client, so I'm reverse engineering the client and building it to WebGL.

    Problem:
    The Y axis for NPC pathing is never correct from the server and I have to adjust it clientside.

    The Y axis that the server sends the traditional client, is a "close enough" type deal. The traditional client then adjusts the axis to fix an NPC above or below the world. I've been tinkering around with NavmeshAgents on my webgl client, but I'm not sure if that is the best solution for my problem.

    The way the server updates NPC positions, makes this trickier than your usual raycast implementations. Especially since too many raycasts will lower my FPS noticeably in WebGL. Which is why I've been struggling.

    Video of problem:
    NPCs pathing beneath the world.


    Code:
    I trimmed a lot out of the code so it is more readable.

    -Server sends client initial x,y,z spawn spot coordinates.
    -Server then sends client target positions with delta positions
    -When delta magnitude != 0 and an npc reaches it's target destination, it has to keep walking on the delta path while waiting for the next target position update.
    -When delta mag == 0 and an npc reaches it's target destination, it will idle at the target position

    Project is open source @ https://github.com/UnityEQ/UnityEQWebGL


    Code (csharp):
    1.  
    2. //Initial Spawn Position
    3. public float x;
    4. public float y;
    5. public float z;
    6.  
    7. //Target Position
    8. public float movetoX;// x coord
    9. public float movetoY;// y coord
    10. public float movetoZ;// z coord
    11.  
    12. //Delta Position
    13. public float deltaX;// x coord
    14. public float deltaY;// y coord
    15. public float deltaZ;// z coord
    16.  
    17. void Start()
    18. {
    19.     //place NPCs via ZoneSpawns packet positions
    20.     this.transform.position = new Vector3(x, y, z);
    21. }
    22.  
    23. void Update ()
    24. {
    25.  
    26.     //update deltas from clientupdate packet
    27.     if(updateDeltas == true)
    28.     {
    29.         deltaF = new Vector3 (deltaX,deltaY,deltaZ);
    30.         updateDeltas = false;
    31.     }
    32.    
    33.     if (deltaF.magnitude != 0)
    34.     {  
    35.         //idle gameobject recieving a target position
    36.         if(clientUpdate == true)
    37.         {
    38.             //initial movement
    39.             targetPosition = new Vector3 (movetoX,movetoY,movetoZ);
    40.         }
    41.         //if waiting on update from server for final target position, move along the delta positions
    42.         if(clientUpdate == false)
    43.         {
    44.             //continuing to move in between updates
    45.             targetPosition += new Vector3 (deltaX,0f,deltaZ);
    46.         }
    47.         //move now
    48.         this.transform.position = Vector3.MoveTowards(this.gameObject.transform.position, targetPosition, step * Time.deltaTime);
    49.     }
    50.     //idle npc after reaching a target destination.
    51.     else
    52.     {
    53.         if (deltaX == 0 && deltaY == 0 && deltaZ == 0 && movetoX != 0 && movetoY != 0 && movetoZ != 0)
    54.         {
    55.             this.transform.position = new Vector3(movetoX, movetoY, movetoZ);
    56.         }
    57.         else
    58.         {
    59.             //FOR  Y ADJUSTMENTS IF BENEATH WORLD WHEN NOT MOVING AND NO POSITION UPDATES FROM SERVER
    60.         }
    61. }
    62.  
    @jonas-echterhoff =)

    Random stuff I tried:
    Generating a navmesh for the zone and doing something like the code below, but it interfered with the //continuing to move in between updates line, or it would warp NPCs to (0,mynav.y,0).

    Also when I set the targetPosition.y with the navmeshHit.y it would gradually move over time because of movetowards instead of snap.

    Basically I'm trial and erroring at this point and could use some direction.

    Code (csharp):
    1.  
    2. NavMeshHit myNavHit;
    3. if(NavMesh.SamplePosition(this.transform.position, out myNavHit, 100 , NavMesh.AllAreas))
    4. {
    5.     this.transform.position = new Vector3(this.transform.position.x, myNavHit.position.y, this.transform.position.z);
    6. }
    7.  
     
    Last edited: Oct 30, 2016
  2. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    So is the under world problem only when the character spawns. Or does the server sometimes send deltas that move the character under the world?
    You could build a heightmap of your zone one time at loadup. Then ignore all Y positions the server sends (initial placement and deltaY). Then each time your NPCs spawn or move just use the correct x,z co-ordinate and look up the y position in heightmap. Since these zones are static you could write small program to pre-compute these heightmaps and load them up from file on zone load up
    Depending on how accurate you needed to be, you could make it so the heightmap was every unit, or every 2 units. Then just average the 4 corners of the square someone is in to save space in memory of the heightmap
     
  3. Blarp

    Blarp

    Joined:
    May 13, 2014
    Posts:
    269
    All the Ys are incorrect. The initial spawn, delta, and target. With deltas the Y is no problem because i'm doing += on the transform, which I can easily zero out the y as shown above in my code.

    wish i could do: vector3.xz = new vector2() and handle the Y completely separate. I'll mess around with heightmaps but I'll still have an issue with movetowards because I'll need a Y for the vector3.

    It would also be cool if i could do a transform.position movetowards with vector2(x,z) and handle Y completely seperate.
     
  4. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    The heighmap would handle all that. Everytime you move you would do something like this:
    Code (CSharp):
    1.  if(clientUpdate == true)
    2.         {
    3.             //initial movement
    4.             targetPosition = new Vector3 (movetoX,GetHeight(movetoX,movetoZ),movetoZ);
    5.         }
    and GetHeight would return the height of the nearest co-ordinate of moveToX and moveToZ You would ignore all Y positional data sent by the server and just replace the Y Co-ordinate iwth your GetHeight function.

    I am unfamiliar with EQ files on drawing the terrain. But I assume you can get height data for any paticular co-ordinate Level of Detail you need.
     
  5. Blarp

    Blarp

    Joined:
    May 13, 2014
    Posts:
    269
    I have extracted zones via .fbx.

    I took the script, Object2Terrain in order to create a heightmap of the zone's gameobject. Problem being, it doesn't create terrainData.

    So my problem with using GetHeight(s) is that I need to generate terrainData from an FBX.

     
  6. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Well how are you displaying the terrain in your client currently. Somehow you have to have X,Y,Z co-ordinates for the triangles to create a mesh for the terrain? Couldn't you just use those Y values to create your heightmap?
     
  7. Blarp

    Blarp

    Joined:
    May 13, 2014
    Posts:
    269
    its a mesh, which finding the height given an xz is tradionally found via raycast. i cant be raycasting every frame to adjust y axis in movement for 200+ NPCs.

    my two attempts so far resolving the issue with y adjustment is as follows:

    i baked a navmesh which also brings up my problem in the original post with implementing navmesh.agent without relying on raycasting and generating a terrain from a fbx doesnt result in terrainData which makes it to where i cant use getHeight

     
    Last edited: Nov 1, 2016
  8. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    I think your misunderstanding. You do all this raycasting ahead of time. Maybe write a separate program to create the heightmap and store it. The heightmap should be a pre-existing file you just load up the same time you load up the zone when the character zones in. Then all your calculations will just be looking up a into a 2D array given any x,z co-ordinate. Now this could get rather large so you could make the array have less LOD than the actual mesh, and just average 4 co-ordinates thtat the NPC is in.
     
  9. Blarp

    Blarp

    Joined:
    May 13, 2014
    Posts:
    269
    Still having this issue.

    Hoping I could use unity physics or even referencing the already existing mesh filter to solve the problem I have with Y axis. Or even a, grounded/bounds method.