fix networking issues

This commit is contained in:
austin 2022-05-09 14:54:15 -04:00
parent c641512886
commit ab5abb019f
8 changed files with 175 additions and 31 deletions

View File

@ -362,12 +362,6 @@ public class LoadingThread extends Thread {
} }
static void initClientTerrainManager(){ static void initClientTerrainManager(){
while(!Globals.clientConnection.getClientProtocol().hasReceivedWorld()){
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException ex) {
}
}
Globals.clientTerrainManager = new ClientTerrainManager(Globals.clientWorldData); Globals.clientTerrainManager = new ClientTerrainManager(Globals.clientWorldData);
} }
@ -393,6 +387,14 @@ public class LoadingThread extends Thread {
Globals.spawnPoint.set((float)startX,(float)Globals.commonWorldData.getElevationAtPoint(new Vector3d(startX,0,startZ)),(float)startZ); Globals.spawnPoint.set((float)startX,(float)Globals.commonWorldData.getElevationAtPoint(new Vector3d(startX,0,startZ)),(float)startZ);
} }
} else { } else {
//basically wait for the client to receive the world metadata
while(!Globals.clientConnection.getClientProtocol().hasReceivedWorld()){
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException ex) {
}
}
//then create common world data
Globals.commonWorldData = new CommonWorldData(Globals.clientWorldData, Globals.clientTerrainManager); Globals.commonWorldData = new CommonWorldData(Globals.clientWorldData, Globals.clientTerrainManager);
} }
} }
@ -434,16 +436,16 @@ public class LoadingThread extends Thread {
static void initDrawCellManager(){ static void initDrawCellManager(){
//if it hasn't already been initialized, create draw cell manager
if(Globals.drawCellManager == null){ if(Globals.drawCellManager == null){
Globals.drawCellManager = new DrawCellManager( Globals.drawCellManager = new DrawCellManager(
Globals.commonWorldData, Globals.commonWorldData,
Globals.clientTerrainManager, Globals.clientTerrainManager,
Globals.clientPlayerData.getWorldPositionX(), Globals.clientPlayerData.getWorldPositionX(),
Globals.clientPlayerData.getWorldPositionY() Globals.clientPlayerData.getWorldPositionY()
// Globals.terrainManager.getDynamicInterpolationRatio(),
// Globals.terrainManager.getRandomDampener()
); );
} else { }
if(Globals.RUN_CLIENT == true) {
//set our draw cell manager to actually generate drawable chunks //set our draw cell manager to actually generate drawable chunks
Globals.drawCellManager.setGenerateDrawables(true); Globals.drawCellManager.setGenerateDrawables(true);
} }

View File

@ -1,5 +1,6 @@
package electrosphere.menu; package electrosphere.menu;
import electrosphere.auth.AuthenticationManager;
import electrosphere.controls.ControlHandler.ControlsState; import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.LoadingThread; import electrosphere.engine.LoadingThread;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
@ -353,16 +354,38 @@ public class MenuGenerators {
portInput.setText(NetUtils.getPort() + ""); portInput.setText(NetUtils.getPort() + "");
rVal.addChild(portInput); rVal.addChild(portInput);
//label (address)
Label usernameLabel = new Label(100,screenTop + 350,1.0f);
usernameLabel.setText("Username");
rVal.addChild(usernameLabel);
//text entry (address)
TextInput usernameInput = new TextInput(100,screenTop + 425,1.0f);
usernameInput.setText("");
rVal.addChild(usernameInput);
//label (port)
Label passwordLabel = new Label(100,screenTop + 500,1.0f);
passwordLabel.setText("Password");
rVal.addChild(passwordLabel);
//text entry (port)
TextInput passwordInput = new TextInput(100,screenTop + 575,1.0f);
passwordInput.setText("");
rVal.addChild(passwordInput);
//button (connect) //button (connect)
Button connectButton = new Button(); Button connectButton = new Button();
Label connectLabel = new Label(100,screenTop + 350,1.0f); Label connectLabel = new Label(100,screenTop + 650,1.0f);
connectLabel.setText("Connect"); connectLabel.setText("Connect");
connectButton.addChild(connectLabel); connectButton.addChild(connectLabel);
rVal.addChild(connectButton); rVal.addChild(connectButton);
connectButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ connectButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
NetUtils.setAddress(addressInput.getText()); NetUtils.setAddress(addressInput.getText());
NetUtils.setPort(Integer.parseInt(portInput.getText())); NetUtils.setPort(Integer.parseInt(portInput.getText()));
LoadingThread clientThread = new LoadingThread(LoadingThread.LOAD_MAIN_GAME); Globals.clientUsername = usernameInput.getText();
Globals.clientPassword = AuthenticationManager.getHashedString(passwordInput.getText());
LoadingThread clientThread = new LoadingThread(LoadingThread.LOAD_CHARACTER_SERVER);
Globals.loadingThreadsList.add(clientThread); Globals.loadingThreadsList.add(clientThread);
Globals.RUN_CLIENT = true; Globals.RUN_CLIENT = true;
Globals.RUN_SERVER = false; Globals.RUN_SERVER = false;
@ -372,7 +395,7 @@ public class MenuGenerators {
//button (back) //button (back)
Button backButton = new Button(); Button backButton = new Button();
Label backLabel = new Label(100,screenTop + 425,1.0f); Label backLabel = new Label(100,screenTop + 725,1.0f);
backLabel.setText("Back"); backLabel.setText("Back");
backButton.addChild(backLabel); backButton.addChild(backLabel);
rVal.addChild(backButton); rVal.addChild(backButton);

View File

@ -10,6 +10,7 @@ import electrosphere.net.client.protocol.ClientProtocol;
import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.parser.net.message.PlayerMessage; import electrosphere.net.parser.net.message.PlayerMessage;
import electrosphere.net.parser.net.message.ServerMessage;
import electrosphere.net.parser.net.raw.NetworkParser; import electrosphere.net.parser.net.raw.NetworkParser;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -47,6 +48,11 @@ public class ClientNetworking implements Runnable{
ClientProtocol clientProtocol = new ClientProtocol(); ClientProtocol clientProtocol = new ClientProtocol();
static final int MAX_CONNECTION_ATTEMPTS = 10; static final int MAX_CONNECTION_ATTEMPTS = 10;
static final long SEND_PING_THRESHOLD = 3000;
static final long PING_DISCONNECT_THRESHOLD = 20000;
long lastPingTime = 0;
long lastPongTime = 0;
public ClientNetworking(String address, int port){ public ClientNetworking(String address, int port){
this.address = address; this.address = address;
@ -112,6 +118,30 @@ public class ClientNetworking implements Runnable{
parser.readMessagesIn(); parser.readMessagesIn();
//outgoing messages //outgoing messages
parser.pushMessagesOut(); parser.pushMessagesOut();
//ping logic
long currentTime = System.currentTimeMillis();
//basically if we haven't sent a ping in a while, send one
if(currentTime - lastPingTime > SEND_PING_THRESHOLD){
queueOutgoingMessage(ServerMessage.constructPingMessage());
lastPingTime = currentTime;
if(lastPongTime == 0){
lastPongTime = lastPingTime;
}
}
if(lastPingTime - lastPongTime > PING_DISCONNECT_THRESHOLD){
//disconnected from the server
LoggerInterface.loggerNetworking.WARNING("Disconnected from server");
//close socket
if(socket.isConnected()){
try {
socket.close();
} catch (IOException e) {
LoggerInterface.loggerNetworking.ERROR("Error closing socket", e);
}
}
//TODO: kick us back to the main menu
break;
}
} }
} }
@ -136,5 +166,9 @@ public class ClientNetworking implements Runnable{
public ClientProtocol getClientProtocol(){ public ClientProtocol getClientProtocol(){
return clientProtocol; return clientProtocol;
} }
public void markReceivedPongMessage(){
lastPongTime = System.currentTimeMillis();
}
} }

View File

@ -44,6 +44,10 @@ public class EntityProtocol {
EntityUtils.setEntityID(newlySpawnedEntity, message.getentityID()); EntityUtils.setEntityID(newlySpawnedEntity, message.getentityID());
break; break;
case DESTROY: case DESTROY:
//only obey if we're not also the server
if(!Globals.RUN_SERVER){
Globals.entityManager.deregisterEntity(Globals.entityManager.getEntityFromId(message.getentityID()));
}
break; break;
case MOVE: case MOVE:
//literally just adding this to scope so I can use `` Entity target; `` again //literally just adding this to scope so I can use `` Entity target; `` again
@ -84,6 +88,12 @@ public class EntityProtocol {
case ATTACKUPDATE: case ATTACKUPDATE:
CreatureUtils.attachEntityMessageToAttackTree(Globals.entityManager.getEntityFromId(message.getentityID()),message); CreatureUtils.attachEntityMessageToAttackTree(Globals.entityManager.getEntityFromId(message.getentityID()),message);
break; break;
case KILL:
break;
case SETPOSITION:
break;
case SETFACING:
break;
} }
} }

View File

@ -11,7 +11,8 @@ public class ServerProtocol {
Globals.clientConnection.queueOutgoingMessage(ServerMessage.constructPongMessage()); Globals.clientConnection.queueOutgoingMessage(ServerMessage.constructPongMessage());
break; break;
case PONG: case PONG:
//silently drop //let the networking loop know we received a pong message
Globals.clientConnection.markReceivedPongMessage();
break; break;
} }
} }

View File

@ -18,6 +18,7 @@ import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.parser.net.message.PlayerMessage; import electrosphere.net.parser.net.message.PlayerMessage;
import electrosphere.net.parser.net.message.ServerMessage; import electrosphere.net.parser.net.message.ServerMessage;
import electrosphere.net.parser.net.raw.NetworkParser; import electrosphere.net.parser.net.raw.NetworkParser;
import electrosphere.net.server.player.Player;
import electrosphere.net.server.protocol.ServerProtocol; import electrosphere.net.server.protocol.ServerProtocol;
import java.io.IOException; import java.io.IOException;
@ -35,6 +36,8 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
/** /**
@ -58,6 +61,15 @@ public class ServerConnectionHandler implements Runnable {
CreatureTemplate currentCreatureTemplate; CreatureTemplate currentCreatureTemplate;
ServerProtocol serverProtocol; ServerProtocol serverProtocol;
//thresholds for determining when to send pings and when a client has disconnected
static final long SEND_PING_THRESHOLD = 3000;
static final long PING_DISCONNECT_THRESHOLD = 20000;
//used to keep track of ping/pong messages with client
long lastPingTime = 0;
long lastPongTime = 0;
//flag to disconnect due to pipe break
boolean socketException = false;
public ServerConnectionHandler(Socket socket) { public ServerConnectionHandler(Socket socket) {
this.socket = socket; this.socket = socket;
@ -104,21 +116,59 @@ public class ServerConnectionHandler implements Runnable {
initialized = true; initialized = true;
while(Main.isRunning()){ while(Main.isRunning()){
//attempt poll incoming messages //parse messages both incoming and outgoing
networkParser.readMessagesIn();
//ponder incoming messages
while(networkParser.hasIncomingMessaage()){
NetworkMessage message = networkParser.popIncomingMessage();
serverProtocol.handleMessage(message);
}
//push outgoing message
networkParser.pushMessagesOut();
try { try {
//sleep parseMessages();
TimeUnit.MILLISECONDS.sleep(1); } catch (SocketException e) {
} catch (InterruptedException ex) { //if we get a SocketException broken pipe (basically the client dc'd without telling us)
ex.printStackTrace(); //set flag to disconnect client
//TODO: fix, this doesn't actually catch the socket exception which is exceedingly obnoxious
socketException = true;
LoggerInterface.loggerNetworking.DEBUG(e.getLocalizedMessage());
} }
//ping logic
long currentTime = System.currentTimeMillis();
//basically if we haven't sent a ping in a while, send one
if(currentTime - lastPingTime > SEND_PING_THRESHOLD){
addMessagetoOutgoingQueue(ServerMessage.constructPingMessage());
lastPingTime = currentTime;
if(lastPongTime == 0){
lastPongTime = lastPingTime;
}
}
//check if we meet disconnection criteria
//has it been too long since the last ping?
//have we had a socket exception?
if(lastPingTime - lastPongTime > PING_DISCONNECT_THRESHOLD || this.socketException == true){
//disconnected from the server
LoggerInterface.loggerNetworking.WARNING("Client disconnected");
//run disconnect routine
disconnect();
break;
}
}
}
/**
* Had to wrap the message parsing block in a function to throw a SocketException
* without my linter freaking out
* @throws SocketException
*/
void parseMessages() throws SocketException {
//attempt poll incoming messages
networkParser.readMessagesIn();
//ponder incoming messages
while(networkParser.hasIncomingMessaage()){
NetworkMessage message = networkParser.popIncomingMessage();
serverProtocol.handleMessage(message);
}
//push outgoing message
networkParser.pushMessagesOut();
try {
//sleep
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException ex) {
ex.printStackTrace();
} }
} }
@ -165,8 +215,6 @@ public class ServerConnectionHandler implements Runnable {
networkParser.addOutgoingMessage(message); networkParser.addOutgoingMessage(message);
} }
break; break;
case SPAWNCREATURE:
break;
default: default:
networkParser.addOutgoingMessage(message); networkParser.addOutgoingMessage(message);
break; break;
@ -186,4 +234,31 @@ public class ServerConnectionHandler implements Runnable {
return this.currentCreatureTemplate; return this.currentCreatureTemplate;
} }
public void markReceivedPongMessage(){
lastPongTime = System.currentTimeMillis();
}
/**
* Routine to run when the client disconnects
*/
void disconnect(){
//close socket
if(socket.isConnected()){
try {
socket.close();
} catch (IOException e) {
LoggerInterface.loggerNetworking.ERROR("Error closing socket", e);
}
}
//figure out what player we are
Player playerObject = Globals.playerManager.getPlayerFromId(getPlayerId());
//get player entity & position
Entity playerEntity = playerObject.getPlayerEntity();
Vector3d position = EntityUtils.getPosition(playerEntity);
//deregister entity
Globals.entityManager.deregisterEntity(playerObject.getPlayerEntity());
//tell all clients to destroy the entity
Globals.dataCellManager.getDataCellAtPoint(position).broadcastNetworkMessage(EntityMessage.constructDestroyMessage(playerEntity.getId()));
}
} }

View File

@ -18,7 +18,7 @@ public class AuthProtocol {
connectionHandler.addMessagetoOutgoingQueue(AuthMessage.constructAuthSuccessMessage()); connectionHandler.addMessagetoOutgoingQueue(AuthMessage.constructAuthSuccessMessage());
Player newPlayer = new Player(connectionHandler); Player newPlayer = new Player(connectionHandler);
Globals.playerManager.registerPlayer(newPlayer); Globals.playerManager.registerPlayer(newPlayer);
if(connectionHandler.getIPAddress().contains("127.0.0.1")){ if(connectionHandler.getIPAddress().contains("127.0.0.1") && Globals.RUN_CLIENT == true){
Globals.clientPlayer = newPlayer; Globals.clientPlayer = newPlayer;
} }
connectionHandler.addMessagetoOutgoingQueue(PlayerMessage.constructSet_IDMessage(connectionHandler.getPlayerId())); connectionHandler.addMessagetoOutgoingQueue(PlayerMessage.constructSet_IDMessage(connectionHandler.getPlayerId()));

View File

@ -29,7 +29,6 @@ import electrosphere.net.server.player.Player;
public class ServerProtocol { public class ServerProtocol {
ServerConnectionHandler connectionHandler; ServerConnectionHandler connectionHandler;
int playerCharacterID;
public ServerProtocol(ServerConnectionHandler connectionHandler){ public ServerProtocol(ServerConnectionHandler connectionHandler){
this.connectionHandler = connectionHandler; this.connectionHandler = connectionHandler;
@ -70,7 +69,7 @@ public class ServerProtocol {
connectionHandler.addMessagetoOutgoingQueue(ServerMessage.constructPongMessage()); connectionHandler.addMessagetoOutgoingQueue(ServerMessage.constructPongMessage());
break; break;
case PONG: case PONG:
//silently drop connectionHandler.markReceivedPongMessage();
break; break;
} }
} }