package electrosphere.net.server; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.attach.AttachUtils; import electrosphere.logger.LoggerInterface; import electrosphere.main.Globals; import electrosphere.main.Main; import electrosphere.net.NetUtils; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.parser.net.message.PlayerMessage; import electrosphere.net.parser.net.message.StatusMessage; import electrosphere.net.parser.net.message.WorldMessage; import electrosphere.net.parser.net.raw.NetworkParser; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.net.Socket; import java.net.SocketException; import java.nio.ByteBuffer; import java.security.spec.RSAKeyGenParameterSpec; import java.util.Properties; import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.crypto.stream.CryptoInputStream; import org.apache.commons.crypto.stream.CryptoOutputStream; import org.joml.Vector3f; /** * * @author satellite */ public class ServerConnectionHandler implements Runnable { static int playerIdIncrementer = 0; Socket socket; // CryptoInputStream inputStream; // CryptoOutputStream outputStream; InputStream inputStream; OutputStream outputStream; boolean initialized; NetworkParser networkParser; int playerID; int playerCharacterID; ServerProtocol serverProtocol; public ServerConnectionHandler(Socket socket) { this.socket = socket; playerID = getPlayerID(); LoggerInterface.loggerNetworking.INFO("Player ID: " + playerID); } @Override public void run() { LoggerInterface.loggerNetworking.INFO("ServerConnectionHandler start"); initialized = false; try { socket.setSoTimeout(100); } catch (SocketException ex) { ex.printStackTrace(); } // final SecretKeySpec key = new SecretKeySpec(("1234567890123456").getBytes(),"AES"); // final Properties properties = new Properties(); // final RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(4096, BigInteger.probablePrime(4000, new Random())); // try { // inputStream = new CryptoInputStream("AES/ECB/PKCS5Padding",properties,socket.getInputStream(),key,spec); // } catch (IOException ex) { // ex.printStackTrace(); // System.exit(1); // } // try { // outputStream = new CryptoOutputStream("AES/ECB/PKCS5Padding",properties,socket.getOutputStream(),key,spec); // } catch (IOException ex) { // ex.printStackTrace(); // System.exit(1); // } try { inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); networkParser = new NetworkParser(inputStream,outputStream); serverProtocol = new ServerProtocol(this); } catch (IOException ex) { ex.printStackTrace(); System.exit(1); } //spawn player in world Entity newPlayerCharacter = CreatureUtils.spawnBasicCreature("Goblin"); playerCharacterID = newPlayerCharacter.getId(); CreatureUtils.positionCharacter(newPlayerCharacter, new Vector3f(Globals.spawnPoint.x,3,Globals.spawnPoint.z)); //spawn player sword Entity sword = ItemUtils.spawnBasicItem("Katana"); AttachUtils.attachEntityToEntityAtBone(newPlayerCharacter, sword, "Bone.031"); //set controller id CreatureUtils.setControllerPlayerId(newPlayerCharacter, playerID); if(Globals.RUN_SERVER && Main.playerId == -1){ Globals.playerCharacter = newPlayerCharacter; } //world metadata networkParser.addOutgoingMessage( WorldMessage.constructMetadataMessage( Globals.serverWorldData.getWorldSizeDiscrete(), Globals.serverWorldData.getDynamicInterpolationRatio(), Globals.serverWorldData.getRandomDampener(), (int)Globals.serverWorldData.getWorldBoundMin().x, (int)Globals.serverWorldData.getWorldBoundMin().z, (int)Globals.serverWorldData.getWorldBoundMax().x, (int)Globals.serverWorldData.getWorldBoundMax().z ) ); //set client initial discrete position networkParser.addOutgoingMessage( PlayerMessage.constructSetInitialDiscretePositionMessage( Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x), Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z) ) ); //send spawn point networkParser.addOutgoingMessage( WorldMessage.constructSpawnPositionMessage(Globals.spawnPoint.x, Globals.spawnPoint.z) ); //tell them what player stats they are networkParser.addOutgoingMessage(PlayerMessage.constructSet_IDMessage(playerID)); //figure out what chunk they're in //queue messages for that chunk if(Globals.RUN_SERVER && Main.playerId == -1){ } else { for(Entity currentEntity : Globals.entityManager.getMoveable()){ networkParser.addOutgoingMessage( EntityMessage.constructCreateMessage( currentEntity.getId(), 0, //0 for creatures CreatureUtils.getType(currentEntity), EntityUtils.getPosition(currentEntity).x, EntityUtils.getPosition(currentEntity).y, EntityUtils.getPosition(currentEntity).z ) ); if(CreatureUtils.isCreature(currentEntity)){ if(CreatureUtils.hasControllerPlayerId(currentEntity)){ LoggerInterface.loggerNetworking.INFO("Sending controller packets"); networkParser.addOutgoingMessage(NetUtils.createSetCreatureControllerIdEntityMessage(currentEntity)); } } } for(Entity currentEntity : Globals.entityManager.getItemEntities()){ networkParser.addOutgoingMessage( EntityMessage.constructCreateMessage( currentEntity.getId(), 1, //1 for items ItemUtils.getType(currentEntity), EntityUtils.getPosition(currentEntity).x, EntityUtils.getPosition(currentEntity).y, EntityUtils.getPosition(currentEntity).z ) ); if(AttachUtils.isAttached(currentEntity)){ networkParser.addOutgoingMessage( EntityMessage.constructattachEntityToEntityMessage( currentEntity.getId(), AttachUtils.getTargetBone(currentEntity), AttachUtils.getParent(currentEntity).getId() ) ); } } } //let client know it's ready networkParser.addOutgoingMessage(StatusMessage.constructReadyMessage(1)); initialized = true; while(Main.isRunning()){ //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(); } } } static int getPlayerID(){ playerIdIncrementer++; return playerIdIncrementer; } public void addMessagetoOutgoingQueue(NetworkMessage message){ switch(message.getType()){ case ENTITY_MESSAGE: switch(((EntityMessage)message).getMessageSubtype()){ case MOVEUPDATE: if(((EntityMessage)message).getentityID()==playerCharacterID){ //basically don't send the message if this is the player's character and it's a move update } else { networkParser.addOutgoingMessage(message); } break; case ATTACKUPDATE: if(((EntityMessage)message).getentityID()==playerCharacterID){ //basically don't send the message if this is the player's character and it's a move update } else { networkParser.addOutgoingMessage(message); } break; default: networkParser.addOutgoingMessage(message); break; } break; default: networkParser.addOutgoingMessage(message); break; } } }