0

I need your help. Im working on online co-op rpg like game (Chronicon/Hero Siege as reference) and I am struggling to get my server-client architecture in one piece.

I decided to go for game states synchronization as it seems to be a good choice for that kind of game. The thing is I am not sure if I am doing it right.

I went thru all sorts of resource on web - Valve, https://gafferongames.com/ on web archives, many yt vidoes from game dev chats and more just so noone will spam links to any of these ;)

Getting to the point. Client clicked W arrow and sends a command to the server that "client with ID N pressed W button in gameState number M". Server starts calculating position based on that until another input command like "client with ID N released W in gameState M". That is fine.

if(object instanceof  MovementAction){
                    serverMovementController.addMovementAction((MovementAction) object);
                }

and after that simple calculations for x and y of player position on the server

Simulation runs 60times per second. Updates are sent 20times per second.

On Client connection to the server I implement simple synchronization which makes both Client and Server to be in the sync (Client and Server are in the same GameState in the same time) although I am not sure if thats good.

  SynchronizationSnapshot synchronizationSnapshot = new SynchronizationSnapshot();
                if(!gameStatesToSend.isEmpty()){
                    synchronizationSnapshot.setServerGameStateNumber(((GameState)gameStatesToSend.get(0)).getId());
                }else {
                    synchronizationSnapshot.setServerGameStateNumber(gameStateId);
                }
                synchronizationSnapshot.setTimeSent(Instant.now());
                server.sendToTCP(connection.getID(), synchronizationSnapshot);

Now the thing I have big problem to get to work is position correction. Clients are not waiting for server respond to start moving. When W is pressed Player starts moving and when the server update arrive its correcting the player position by using interpolation (well it suppose to), but unfortunetaly its not getting corrected smoothly, instead it still "teleports" the object. Local client works smoothly, the other players objects are glitchy. All updates are qued and processed one by one.


        synchronized (gameStatesToProcess){
            List<GameState> gameStatesToProcessToRemove = new ArrayList<>();
            Vector2 correctedPosition = null;
            //iterating thru gamestates that needs to be processed
            for (GameState gameStateToProcess : gameStatesToProcess){

                //find the gamestate with the same ID as the gamestate to process which came from server
                Optional<GameState> gameStateOptional = gameStates.stream().filter(actualGameState -> actualGameState.getId() == gameStateToProcess.getId()).findFirst();
                if (gameStateOptional.isPresent()){
                    GameState gameState = gameStateOptional.get();

                    //iterate thru entities: 
                    for (Entity entity : entities){

                        if(entity instanceof PlayerEntity){
                            PlayerEntity playerEntity = (PlayerEntity) entity;
                            PositionComponent positionComponent = positionComponentMapper.get(playerEntity);

                            //Get PlayerPosition based on unique connection id
                            Optional<PlayerPosition> playerPositionOptional = gameStateToProcess
                                    .getPlayerPositions().stream()
                                    .filter(playerPosition -> playerPosition.getConnectionId() == playerEntity.getConnectionId()).findFirst();
                            PlayerPosition playerPositionToProcess;

                            if (playerPositionOptional.isPresent()){
                                playerPositionToProcess = playerPositionOptional.get();
                                Optional<PlayerPosition> clientGameStatePlayerPositionOptional = gameState.getPlayerPositions()
                                        .stream()
                                        .filter(playerPosition -> playerPosition.getConnectionId() == playerPositionToProcess.getConnectionId()).findFirst();
                                if(clientGameStatePlayerPositionOptional.isPresent()){
                                    PlayerPosition clientGameStatePlayerPosition = clientGameStatePlayerPositionOptional.get();
                                    Vector2 positionDiffirence = playerPositionToProcess.getPosition().sub(clientGameStatePlayerPosition.getPosition());
                                    correctedPosition = positionComponent.getPosition().add(positionDiffirence);
                                    positionComponent.getPosition().lerp(correctedPosition, Interpolation.smooth2.apply(0.9f));

                                }
                            }
                            gameStatesToProcessToRemove.add(gameStateToProcess);
                            gameStates.remove(gameState);
                        }
                    }
                }else {
                    gameStatesToProcessToRemove.add(gameStateToProcess);
                }
            }
            gameStatesToProcess.removeAll(gameStatesToProcessToRemove);

enter image description here

So the final question is how should i implement position correction on client side so the interpolation actually works. In my case its not matter of alpha. It just simply is glitchy and I think i know the issue but still dont know how ti implement it diffirently. Should i go for the most recent update only or maybe something completely diffirent.

For any tips, adivices and potential solutions thanks in advance.

Jarek
  • 3
  • 1

0 Answers0