ACBob / VoxelThingYeah

Voxel Game Engine
1 stars 1 forks source link

Infinite World #9

Closed ACBob closed 3 years ago

ACBob commented 3 years ago

Each player up to their render distance (and up to the server's forced render distance) will load chunks around them from the server

Requires #6 ideally so we can see some cool shit and not an empty plane of grass

ACBob commented 3 years ago

proposal:

Each client has a 'chunkIndex' which is a 1D array up to RenderDistance³, every server update we increment that and send the chunk at that position.\ I prototyped smth like that but it was fucky and was generating chunks at, I shit you not, Chunk Position 9 Quintillion. Or, 144 quintillion world coords. Obviously something wrong with the weird disconnect from Vectors and WorldPos.

Not sure how expensive it is to send a new chunk for each player every frame, but we can worry about that later!

ACBob commented 3 years ago

I'd removed chunk pos entirely, now chunks just have a generic vector.

This works fine and I've got some kind of infinite world setup going, but it leads to some issues in that we start at -2,-2,-2 chunk pos relative to the player, so chunks don't load by the time you get to them - a solution would be to spiral out from the player's chunk pos, making sure that the chunks nearest to the player have the highest priority. This'll be a difficult change.

ACBob commented 3 years ago

I've figured out a potential way to load the chunks satisfactorily.\ Spiral!

psuedo-code (could be much better, loosely translated python turtle code)

for (CNetworkPlayer *cl : m_players)
{
   if (cl->m_iHorizLoad >= /* horz. dist */ || cl->m_iLoadOppurtunity > m_iTick)
     continue;

  if (cl->m_iHorizLoadIDX % 3== 0)
  {
     cl->m_vLoadDir = cl->m_vLoadDir.Rotate(2, 90);
     cl->m_iHorizLoad ++;
  }

  /* Load chunk at position, centred vertically before going up and then down */

  cl->m_vLoadPosition = m_vLoadPosition + cl_m_vLoadDir;
}
ACBob commented 3 years ago

I ended up with a loading algorithm along the lines of

    for ( CNetworkPlayer *c : m_players )
    {
        // Update chunk pos
        // Unfortunate name
        CVector cP = ( c->m_pEntity->m_vPosition / CVector( CHUNKSIZE_X, CHUNKSIZE_Y, CHUNKSIZE_Z ) ).Floor();
        if ( cP != c->m_vChunkPos )
        {
            c->m_iLoadedChunkIDX    = 0;
            c->m_iNextChunkLoadTick = m_iCurrentTick;
            c->m_iLoadedChunkLength = 0;
            c->m_iLoadedChunkTarget = 0;
        }
        c->m_vChunkPos = cP;

        if ( c->m_iNextChunkLoadTick < m_iCurrentTick )
            c->m_iNextChunkLoadTick = m_iCurrentTick + 1;
        else
            continue;

        if (c->m_iLoadedChunkIDX > (c->m_iChunkLoadSizeHorz))
            continue;

        if (c->m_iLoadedChunkLength >= c->m_iLoadedChunkTarget)     
        {
            if (c->m_iLoadedChunkIDX % 3 == 0)
            {                   
                c->m_iLoadedChunkTarget ++;
            }

            c->m_iChunkDir ++;
            if (c->m_iChunkDir >= UP)
                c->m_iChunkDir = NORTH;

            c->m_iLoadedChunkLength = 0;
        }

        c->m_vChunkLoadPos = c->m_vChunkLoadPos + DirectionVector[c->m_iChunkDir];

        CVector p = c->m_vChunkLoadPos + c->m_vChunkPos;
        protocol::SendServerChunkData( c->m_pPeer, &m_world, p );

        con_info("%i, %i, %i, %i, %.0f, %.0f, %.0f", 
            c->m_iLoadedChunkIDX,
            c->m_iChunkDir,
            c->m_iLoadedChunkLength,
            c->m_iLoadedChunkTarget,
            c->m_vChunkLoadPos.x, 
            c->m_vChunkLoadPos.y, 
            c->m_vChunkLoadPos.z
        );

        c->m_iLoadedChunkLength ++;
        c->m_iLoadedChunkIDX ++;
    }

But I couldn't get it to spiral out properly....

ACBob commented 3 years ago

Technically resolved, chunk loading just needs to be revised.