character database work
Some checks reported errors
studiorailgun/Renderer/pipeline/head Something is wrong with the build of this commit
Some checks reported errors
studiorailgun/Renderer/pipeline/head Something is wrong with the build of this commit
This commit is contained in:
parent
460989eeab
commit
080cdeca33
@ -6,5 +6,5 @@ CREATE INDEX charaWorldPositionsIDIndex ON charaWorldPositions (id);
|
||||
CREATE INDEX charaWorldPositionsPosIndex ON charaWorldPositions (posX, posY);
|
||||
|
||||
--data
|
||||
CREATE TABLE charaData (playerId INTEGER PRIMARY KEY, id INTEGER, dataVal VARCHAR);
|
||||
CREATE TABLE charaData (id INTEGER PRIMARY KEY AUTOINCREMENT, playerId INTEGER, dataVal VARCHAR);
|
||||
CREATE INDEX charaDataIDIndex ON charaData (id);
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
#maven.buildNumber.plugin properties file
|
||||
#Mon Nov 25 18:13:49 EST 2024
|
||||
buildNumber=405
|
||||
#Fri Nov 29 20:08:47 EST 2024
|
||||
buildNumber=406
|
||||
|
||||
@ -1184,6 +1184,8 @@ Actor panel additional functionality
|
||||
Better style for character creation menu
|
||||
Fix AABB calculation from assimp-loaded models
|
||||
Fix singleplayer launching at all
|
||||
Store characters in database
|
||||
Spawn characters from database
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
@ -20,6 +20,16 @@ public class AuthenticationManager {
|
||||
*/
|
||||
boolean isMock = false;
|
||||
|
||||
/**
|
||||
* An invalid login
|
||||
*/
|
||||
public static final int INVALID_LOGIN = -1;
|
||||
|
||||
/**
|
||||
* ID for a mock login
|
||||
*/
|
||||
public static final int MOCK_LOGIN = 0;
|
||||
|
||||
/**
|
||||
* Private constructor
|
||||
*/
|
||||
@ -38,9 +48,15 @@ public class AuthenticationManager {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
public boolean authenticate(String username, String password){
|
||||
/**
|
||||
* Authenticates the player
|
||||
* @param username The username of the player
|
||||
* @param password The password of the player
|
||||
* @return The id of the player if they logged in successfully, INVALID_LOGIN if the authentication failed
|
||||
*/
|
||||
public int authenticate(String username, String password){
|
||||
if(isMock){
|
||||
return true;
|
||||
return MOCK_LOGIN;
|
||||
}
|
||||
//first we hash the input password
|
||||
String hashedPassword = getHashedString(password);
|
||||
@ -54,19 +70,32 @@ public class AuthenticationManager {
|
||||
String pwdhash = row.getAsString("pwdhash");
|
||||
if(pwdhash.equals(hashedPassword)){
|
||||
LoggerInterface.loggerAuth.INFO("Authenticated user " + username);
|
||||
return true;
|
||||
return row.getAsInteger("id");
|
||||
}
|
||||
}
|
||||
//If we didn't find a single account, go ahead and create it
|
||||
if(!foundRow){
|
||||
LoggerInterface.loggerAuth.INFO("Created user " + username);
|
||||
Globals.dbController.executePreparedStatement("INSERT INTO accounts (username, pwdhash) VALUES(?, ?);",username,hashedPassword);
|
||||
//TODO: verify we created the account
|
||||
return true;
|
||||
|
||||
//verify the account was created
|
||||
result = Globals.dbController.executePreparedQuery("SELECT id, username, pwdhash FROM accounts WHERE username=?;",username);
|
||||
if(result.hasResult()){
|
||||
foundRow = false;
|
||||
//if we get a valid response from the database, check that it actually matches hashes
|
||||
for(DatabaseResultRow row : result){
|
||||
foundRow = true;
|
||||
String pwdhash = row.getAsString("pwdhash");
|
||||
if(pwdhash.equals(hashedPassword)){
|
||||
LoggerInterface.loggerAuth.INFO("Authenticated user " + username);
|
||||
return row.getAsInteger("id");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LoggerInterface.loggerAuth.INFO("Failed to authenticate user " + username);
|
||||
return false;
|
||||
return INVALID_LOGIN;
|
||||
}
|
||||
|
||||
static final int saltLength = 16;
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
package electrosphere.client.entity.character;
|
||||
|
||||
import electrosphere.entity.types.creature.CreatureTemplate;
|
||||
|
||||
/**
|
||||
* Describes a character
|
||||
*/
|
||||
public class CharacterDescription {
|
||||
|
||||
/**
|
||||
* The id of the character
|
||||
*/
|
||||
String id;
|
||||
|
||||
/**
|
||||
* The character's template data
|
||||
*/
|
||||
CreatureTemplate template;
|
||||
|
||||
/**
|
||||
* Gets the id of the character
|
||||
* @return The id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id of the character
|
||||
* @param id The id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the creature template for the character
|
||||
* @return The creature template
|
||||
*/
|
||||
public CreatureTemplate getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the creature template for the character
|
||||
* @param template The creature template
|
||||
*/
|
||||
public void setTemplate(CreatureTemplate template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package electrosphere.client.entity.character;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DTO for sending available characters to the client
|
||||
*/
|
||||
public class ClientCharacterListDTO {
|
||||
|
||||
/**
|
||||
* The list of characters stored in the DTO
|
||||
*/
|
||||
List<CharacterDescription> characters;
|
||||
|
||||
/**
|
||||
* Gets the list of characters
|
||||
* @return The list of characters
|
||||
*/
|
||||
public List<CharacterDescription> getCharacters() {
|
||||
return characters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of characters
|
||||
* @param characters The list of characters
|
||||
*/
|
||||
public void setCharacters(List<CharacterDescription> characters) {
|
||||
this.characters = characters;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package electrosphere.client.entity.character;
|
||||
|
||||
/**
|
||||
* Tracks the characers available to the client
|
||||
*/
|
||||
public class ClientCharacterManager {
|
||||
|
||||
/**
|
||||
* The list of characters available
|
||||
*/
|
||||
ClientCharacterListDTO characterList;
|
||||
|
||||
/**
|
||||
* Gets the character list
|
||||
* @return The character list
|
||||
*/
|
||||
public ClientCharacterListDTO getCharacterList() {
|
||||
return characterList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character list
|
||||
* @param characterList The character list
|
||||
*/
|
||||
public void setCharacterList(ClientCharacterListDTO characterList) {
|
||||
this.characterList = characterList;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,14 +1,20 @@
|
||||
package electrosphere.client.ui.menu.mainmenu;
|
||||
|
||||
import electrosphere.client.entity.character.CharacterDescription;
|
||||
import electrosphere.client.ui.components.CharacterCustomizer;
|
||||
import electrosphere.client.ui.menu.WindowUtils;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.engine.loadingthreads.LoadingThread;
|
||||
import electrosphere.engine.loadingthreads.LoadingThread.LoadingThreadType;
|
||||
import electrosphere.entity.types.creature.CreatureTemplate;
|
||||
import electrosphere.net.parser.net.message.CharacterMessage;
|
||||
import electrosphere.net.parser.net.message.TerrainMessage;
|
||||
import electrosphere.renderer.ui.elements.Button;
|
||||
import electrosphere.renderer.ui.elements.Div;
|
||||
import electrosphere.renderer.ui.elements.FormElement;
|
||||
import electrosphere.renderer.ui.elements.StringCarousel;
|
||||
import electrosphere.renderer.ui.elementtypes.Element;
|
||||
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaAlignment;
|
||||
import electrosphere.renderer.ui.events.ValueChangeEvent;
|
||||
import electrosphere.util.Utilities;
|
||||
|
||||
@ -29,11 +35,35 @@ public class MenuCharacterCreation {
|
||||
public static Element createCharacterSelectionWindow(){
|
||||
FormElement rVal = new FormElement();
|
||||
|
||||
//the list of characters
|
||||
Div selectContainer = Div.createCol();
|
||||
if(Globals.clientCharacterManager.getCharacterList() != null){
|
||||
for(CharacterDescription description : Globals.clientCharacterManager.getCharacterList().getCharacters()){
|
||||
String buttonTitle = "Character " + description.getId();
|
||||
Div charNameContainer = Div.createRow(Button.createButton(buttonTitle, () -> {
|
||||
Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage(description.getId()));
|
||||
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestMetadataMessage());
|
||||
Globals.threadManager.start(new LoadingThread(LoadingThreadType.CLIENT_WORLD));
|
||||
}));
|
||||
selectContainer.addChild(charNameContainer);
|
||||
}
|
||||
}
|
||||
|
||||
//button (create)
|
||||
rVal.addChild(Button.createButton("Create Character", () -> {
|
||||
Div createContainer = Div.createDiv();
|
||||
createContainer.addChild(Button.createButton("Create Character", () -> {
|
||||
WindowUtils.replaceMainMenuContents(MenuCharacterCreation.createRaceSelectionMenu());
|
||||
}));
|
||||
|
||||
|
||||
//main layout
|
||||
Div mainLayout = Div.createCol(
|
||||
selectContainer,
|
||||
createContainer
|
||||
);
|
||||
mainLayout.setAlignItems(YogaAlignment.Center);
|
||||
rVal.addChild(mainLayout);
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ import electrosphere.client.block.ClientBlockManager;
|
||||
import electrosphere.client.block.cells.BlockTextureAtlas;
|
||||
import electrosphere.client.block.cells.ClientBlockCellManager;
|
||||
import electrosphere.client.chemistry.ClientChemistryCollisionCallback;
|
||||
import electrosphere.client.entity.character.ClientCharacterManager;
|
||||
import electrosphere.client.entity.particle.ParticleService;
|
||||
import electrosphere.client.fluid.cells.FluidCellManager;
|
||||
import electrosphere.client.fluid.manager.ClientFluidManager;
|
||||
@ -352,6 +353,7 @@ public class Globals {
|
||||
|
||||
//client world data
|
||||
public static ClientWorldData clientWorldData;
|
||||
public static ClientCharacterManager clientCharacterManager = new ClientCharacterManager();
|
||||
|
||||
//client gridded manager
|
||||
public static ClientTerrainManager clientTerrainManager;
|
||||
@ -703,6 +705,7 @@ public class Globals {
|
||||
if(Globals.realmManager != null){
|
||||
Globals.realmManager.reset();
|
||||
}
|
||||
Globals.dbController.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -102,6 +102,7 @@ public class ClientLoading {
|
||||
Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT);
|
||||
//initialize the "real" objects simulation
|
||||
initClientSimulation();
|
||||
LoadingUtils.setSimulationsToReady();
|
||||
//initialize the gridded managers (client)
|
||||
initDrawCellManager(true);
|
||||
initFoliageManager();
|
||||
|
||||
@ -24,6 +24,7 @@ import electrosphere.net.parser.net.message.CharacterMessage;
|
||||
import electrosphere.net.server.Server;
|
||||
import electrosphere.net.server.ServerConnectionHandler;
|
||||
import electrosphere.net.server.player.Player;
|
||||
import electrosphere.net.server.protocol.CharacterProtocol;
|
||||
import electrosphere.server.datacell.Realm;
|
||||
import electrosphere.server.simulation.MicroSimulation;
|
||||
|
||||
@ -167,7 +168,7 @@ public class LoadingUtils {
|
||||
template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector"));
|
||||
//set player character template
|
||||
serverPlayerConnection.setCreatureTemplate(template);
|
||||
Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage());
|
||||
Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage(CharacterProtocol.SPAWN_EXISTING_TEMPLATE + ""));
|
||||
|
||||
//set player world-space coordinates
|
||||
Player playerObject = Globals.playerManager.getFirstPlayer();
|
||||
|
||||
@ -219,7 +219,7 @@ public class ClientNetworking implements Runnable {
|
||||
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());
|
||||
this.queueOutgoingMessage(ServerMessage.constructPingMessage());
|
||||
lastPingTime = currentTime;
|
||||
if(lastPongTime == 0){
|
||||
lastPongTime = lastPingTime;
|
||||
|
||||
@ -3,6 +3,7 @@ package electrosphere.net.client.protocol;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.net.parser.net.message.AuthMessage;
|
||||
import electrosphere.net.parser.net.message.CharacterMessage;
|
||||
import electrosphere.net.parser.net.message.LoreMessage;
|
||||
import electrosphere.net.template.ClientProtocolTemplate;
|
||||
|
||||
@ -24,6 +25,8 @@ public class AuthProtocol implements ClientProtocolTemplate<AuthMessage> {
|
||||
Globals.clientPassword = "";
|
||||
//request playable races
|
||||
Globals.clientConnection.queueOutgoingMessage(LoreMessage.constructRequestRacesMessage());
|
||||
//request characters available to this player
|
||||
Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestCharacterListMessage());
|
||||
//log that we succeeded
|
||||
LoggerInterface.loggerAuth.INFO("Successfully logged in");
|
||||
break;
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
package electrosphere.net.client.protocol;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import electrosphere.client.entity.character.ClientCharacterListDTO;
|
||||
import electrosphere.client.ui.menu.WindowUtils;
|
||||
import electrosphere.client.ui.menu.mainmenu.MenuCharacterCreation;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.engine.loadingthreads.LoadingThread;
|
||||
import electrosphere.engine.loadingthreads.LoadingThread.LoadingThreadType;
|
||||
import electrosphere.engine.signal.Signal.SignalType;
|
||||
import electrosphere.net.parser.net.message.CharacterMessage;
|
||||
import electrosphere.net.parser.net.message.TerrainMessage;
|
||||
import electrosphere.net.template.ClientProtocolTemplate;
|
||||
@ -20,17 +26,22 @@ public class CharacterProtocol implements ClientProtocolTemplate<CharacterMessag
|
||||
@Override
|
||||
public void handleSyncMessage(CharacterMessage message) {
|
||||
switch(message.getMessageSubtype()){
|
||||
case RESPONSECREATECHARACTERSUCCESS:
|
||||
//trigger request to spawn character
|
||||
Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage());
|
||||
case RESPONSECREATECHARACTERSUCCESS: {
|
||||
//trigger request to spawn character if the character list is undefined (ie if special loading case)
|
||||
Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage(electrosphere.net.server.protocol.CharacterProtocol.SPAWN_EXISTING_TEMPLATE + ""));
|
||||
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestMetadataMessage());
|
||||
LoadingThread clientThread = new LoadingThread(LoadingThreadType.CLIENT_WORLD);
|
||||
Globals.threadManager.start(clientThread);
|
||||
break;
|
||||
} break;
|
||||
case RESPONSECHARACTERLIST: {
|
||||
Globals.clientCharacterManager.setCharacterList(new Gson().fromJson(message.getdata(), ClientCharacterListDTO.class));
|
||||
Globals.signalSystem.post(SignalType.UI_MODIFICATION,() -> {
|
||||
WindowUtils.replaceMainMenuContents(MenuCharacterCreation.createCharacterSelectionWindow());
|
||||
});
|
||||
} break;
|
||||
case REQUESTCHARACTERLIST:
|
||||
case REQUESTCREATECHARACTER:
|
||||
case REQUESTSPAWNCHARACTER:
|
||||
case RESPONSECHARACTERLIST:
|
||||
case RESPONSECREATECHARACTERFAILURE:
|
||||
case RESPONSESPAWNCHARACTER:
|
||||
case EDITORSWAP:
|
||||
|
||||
@ -23,7 +23,7 @@ public class PlayerProtocol implements ClientProtocolTemplate<PlayerMessage> {
|
||||
Globals.profiler.beginCpuSample("PlayerProtocol.handlePlayerMessage");
|
||||
switch(message.getMessageSubtype()){
|
||||
case SET_ID:
|
||||
Globals.clientPlayer = new Player(message.getplayerID());
|
||||
Globals.clientPlayer = new Player(message.getplayerID(), Player.CLIENT_DB_ID);
|
||||
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Player ID is " + Globals.clientPlayer.getId());
|
||||
break;
|
||||
case SETINITIALDISCRETEPOSITION:
|
||||
|
||||
@ -93,11 +93,7 @@ public class CharacterMessage extends NetworkMessage {
|
||||
return false;
|
||||
}
|
||||
case TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER:
|
||||
if(byteBuffer.getRemaining() >= TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER_SIZE){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return CharacterMessage.canParseRequestSpawnCharacterMessage(byteBuffer);
|
||||
case TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSESPAWNCHARACTER:
|
||||
return CharacterMessage.canParseResponseSpawnCharacterMessage(byteBuffer);
|
||||
case TypeBytes.CHARACTER_MESSAGE_TYPE_EDITORSWAP:
|
||||
@ -248,20 +244,44 @@ public class CharacterMessage extends NetworkMessage {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a message of type RequestSpawnCharacter can be parsed from the byte stream
|
||||
*/
|
||||
public static boolean canParseRequestSpawnCharacterMessage(CircularByteBuffer byteBuffer){
|
||||
int currentStreamLength = byteBuffer.getRemaining();
|
||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||
int dataSize = 0;
|
||||
if(currentStreamLength < 6){
|
||||
return false;
|
||||
} else {
|
||||
temporaryByteQueue.add(byteBuffer.peek(2 + 0));
|
||||
temporaryByteQueue.add(byteBuffer.peek(2 + 1));
|
||||
temporaryByteQueue.add(byteBuffer.peek(2 + 2));
|
||||
temporaryByteQueue.add(byteBuffer.peek(2 + 3));
|
||||
dataSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
|
||||
}
|
||||
if(currentStreamLength < 6 + dataSize){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a message of type RequestSpawnCharacter
|
||||
*/
|
||||
public static CharacterMessage parseRequestSpawnCharacterMessage(CircularByteBuffer byteBuffer){
|
||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTSPAWNCHARACTER);
|
||||
stripPacketHeader(byteBuffer);
|
||||
rVal.setdata(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a message of type RequestSpawnCharacter
|
||||
*/
|
||||
public static CharacterMessage constructRequestSpawnCharacterMessage(){
|
||||
public static CharacterMessage constructRequestSpawnCharacterMessage(String data){
|
||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTSPAWNCHARACTER);
|
||||
rVal.setdata(data);
|
||||
rVal.serialize();
|
||||
return rVal;
|
||||
}
|
||||
@ -383,11 +403,19 @@ public class CharacterMessage extends NetworkMessage {
|
||||
rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE;
|
||||
break;
|
||||
case REQUESTSPAWNCHARACTER:
|
||||
rawBytes = new byte[2];
|
||||
rawBytes = new byte[2+4+data.length()];
|
||||
//message header
|
||||
rawBytes[0] = TypeBytes.MESSAGE_TYPE_CHARACTER;
|
||||
//entity messaage header
|
||||
rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER;
|
||||
intValues = ByteStreamUtils.serializeIntToBytes(data.length());
|
||||
for(int i = 0; i < 4; i++){
|
||||
rawBytes[2+i] = intValues[i];
|
||||
}
|
||||
stringBytes = data.getBytes();
|
||||
for(int i = 0; i < data.length(); i++){
|
||||
rawBytes[6+i] = stringBytes[i];
|
||||
}
|
||||
break;
|
||||
case RESPONSESPAWNCHARACTER:
|
||||
rawBytes = new byte[2+4+data.length()];
|
||||
|
||||
@ -137,7 +137,6 @@ public class TypeBytes {
|
||||
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST_SIZE = 2;
|
||||
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERSUCCESS_SIZE = 2;
|
||||
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE_SIZE = 2;
|
||||
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER_SIZE = 2;
|
||||
public static final byte CHARACTER_MESSAGE_TYPE_EDITORSWAP_SIZE = 2;
|
||||
|
||||
/*
|
||||
|
||||
@ -21,6 +21,11 @@ public class Player {
|
||||
*/
|
||||
public static final int DEFAULT_SIMULATION_RADIUS = 3;
|
||||
|
||||
/**
|
||||
* DBID the client assigns to the player object
|
||||
*/
|
||||
public static final int CLIENT_DB_ID = 0;
|
||||
|
||||
/**
|
||||
* Id incrementer lock
|
||||
*/
|
||||
@ -41,6 +46,11 @@ public class Player {
|
||||
*/
|
||||
int id;
|
||||
|
||||
/**
|
||||
* The database's id of the player
|
||||
*/
|
||||
int dbId;
|
||||
|
||||
/**
|
||||
* The world position of this player
|
||||
*/
|
||||
@ -64,10 +74,12 @@ public class Player {
|
||||
/**
|
||||
* Constructor
|
||||
* @param connectionHandler The corresponding connection
|
||||
* @param dbId The database's id of the player
|
||||
*/
|
||||
public Player(ServerConnectionHandler connectionHandler){
|
||||
public Player(ServerConnectionHandler connectionHandler, int dbId){
|
||||
this.connectionHandler = connectionHandler;
|
||||
id = connectionHandler.getPlayerId();
|
||||
this.dbId = dbId;
|
||||
this.simulationRadius = Globals.userSettings.getGameplayPhysicsCellRadius();
|
||||
}
|
||||
|
||||
@ -75,8 +87,9 @@ public class Player {
|
||||
* Used when initing a local connection
|
||||
* @param id The id of the local connection
|
||||
*/
|
||||
public Player(int id){
|
||||
public Player(int id, int dbId){
|
||||
this.id = id;
|
||||
this.dbId = dbId;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,6 +195,14 @@ public class Player {
|
||||
this.hasSentPlayerEntity = hasSentPlayerEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database's id for the player
|
||||
* @return The database's id for the player
|
||||
*/
|
||||
public int getDBID(){
|
||||
return this.dbId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package electrosphere.net.server.protocol;
|
||||
|
||||
import electrosphere.auth.AuthenticationManager;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.net.parser.net.message.AuthMessage;
|
||||
import electrosphere.net.parser.net.message.PlayerMessage;
|
||||
@ -17,11 +18,11 @@ public class AuthProtocol implements ServerProtocolTemplate<AuthMessage> {
|
||||
switch(message.getMessageSubtype()){
|
||||
case AUTHDETAILS:
|
||||
//auth check
|
||||
boolean successfulLogin = Globals.authenticationManager.authenticate(message.getuser(), message.getpass());
|
||||
if(successfulLogin){
|
||||
int loginId = Globals.authenticationManager.authenticate(message.getuser(), message.getpass());
|
||||
if(loginId != AuthenticationManager.INVALID_LOGIN){
|
||||
//TODO: actually set connection/protocol to authenticated
|
||||
connectionHandler.addMessagetoOutgoingQueue(AuthMessage.constructAuthSuccessMessage());
|
||||
Player newPlayer = new Player(connectionHandler);
|
||||
Player newPlayer = new Player(connectionHandler, loginId);
|
||||
Globals.playerManager.registerPlayer(newPlayer);
|
||||
//there is a race condition here where if a local non-server client connects first then it breaks
|
||||
if(connectionHandler.getIPAddress().contains("127.0.0.1") && Globals.RUN_CLIENT == true && Globals.clientPlayer == null){
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
package electrosphere.net.server.protocol;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import electrosphere.client.entity.character.CharacterDescription;
|
||||
import electrosphere.client.entity.character.ClientCharacterListDTO;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.engine.loadingthreads.LoadingUtils;
|
||||
import electrosphere.entity.Entity;
|
||||
@ -21,6 +26,8 @@ import electrosphere.net.server.player.Player;
|
||||
import electrosphere.net.template.ServerProtocolTemplate;
|
||||
import electrosphere.server.character.PlayerCharacterCreation;
|
||||
import electrosphere.server.datacell.Realm;
|
||||
import electrosphere.server.db.DatabaseResult;
|
||||
import electrosphere.server.db.DatabaseResultRow;
|
||||
import electrosphere.util.Utilities;
|
||||
|
||||
/**
|
||||
@ -28,20 +35,50 @@ import electrosphere.util.Utilities;
|
||||
*/
|
||||
public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessage> {
|
||||
|
||||
/**
|
||||
* Should spawn the existing template
|
||||
*/
|
||||
public static final int SPAWN_EXISTING_TEMPLATE = -1;
|
||||
|
||||
@Override
|
||||
public CharacterMessage handleAsyncMessage(ServerConnectionHandler connectionHandler, CharacterMessage message) {
|
||||
switch(message.getMessageSubtype()){
|
||||
case REQUESTCHARACTERLIST: {
|
||||
Gson gson = new Gson();
|
||||
List<CharacterDescription> characters = new LinkedList<CharacterDescription>();
|
||||
DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT id, dataVal FROM charaData WHERE playerId=?;",connectionHandler.getPlayer().getDBID());
|
||||
if(result.hasResult()){
|
||||
//if we get a valid response from the database, check that it actually matches hashes
|
||||
for(DatabaseResultRow row : result){
|
||||
CharacterDescription description = new CharacterDescription();
|
||||
CreatureTemplate template = gson.fromJson(row.getAsString("dataVal"),CreatureTemplate.class);
|
||||
description.setTemplate(template);
|
||||
description.setId(row.getAsInteger("id") + "");
|
||||
characters.add(description);
|
||||
}
|
||||
}
|
||||
ClientCharacterListDTO dto = new ClientCharacterListDTO();
|
||||
dto.setCharacters(characters);
|
||||
connectionHandler.addMessagetoOutgoingQueue(CharacterMessage.constructResponseCharacterListMessage(gson.toJson(dto)));
|
||||
return null;
|
||||
}
|
||||
default: {
|
||||
} break;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSyncMessage(ServerConnectionHandler connectionHandler, CharacterMessage message) {
|
||||
switch(message.getMessageSubtype()){
|
||||
case REQUESTCHARACTERLIST:
|
||||
//TODO
|
||||
break;
|
||||
case REQUESTCREATECHARACTER: {
|
||||
CreatureTemplate template = Utilities.deserialize(message.getdata(), CreatureTemplate.class);
|
||||
if(template != null){
|
||||
Globals.dbController.executePreparedStatement(
|
||||
"INSERT INTO charaData (playerId,dataVal) VALUES (?,?);",
|
||||
connectionHandler.getPlayer().getDBID(),
|
||||
new Gson().toJson(template)
|
||||
);
|
||||
connectionHandler.setCreatureTemplate(Utilities.deserialize(message.getdata(), CreatureTemplate.class));
|
||||
connectionHandler.addMessagetoOutgoingQueue(CharacterMessage.constructResponseCreateCharacterSuccessMessage());
|
||||
} else {
|
||||
@ -49,11 +86,15 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
|
||||
}
|
||||
} break;
|
||||
case REQUESTSPAWNCHARACTER: {
|
||||
CharacterProtocol.spawnEntityForClient(connectionHandler);
|
||||
int charaId = Integer.parseInt(message.getdata());
|
||||
CharacterProtocol.spawnEntityForClient(connectionHandler, charaId);
|
||||
} break;
|
||||
case EDITORSWAP: {
|
||||
CharacterProtocol.swapPlayerCharacter(connectionHandler);
|
||||
} break;
|
||||
case REQUESTCHARACTERLIST:
|
||||
//handled async
|
||||
break;
|
||||
case RESPONSECHARACTERLIST:
|
||||
case RESPONSECREATECHARACTERSUCCESS:
|
||||
case RESPONSECREATECHARACTERFAILURE:
|
||||
@ -68,7 +109,18 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
|
||||
* @param connectionHandler The connection handler for the player
|
||||
* @return THe player's entity
|
||||
*/
|
||||
static Entity spawnEntityForClient(ServerConnectionHandler connectionHandler){
|
||||
static Entity spawnEntityForClient(ServerConnectionHandler connectionHandler, int id){
|
||||
if(id != CharacterProtocol.SPAWN_EXISTING_TEMPLATE){
|
||||
DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT id, dataVal FROM charaData WHERE playerId=? AND id=?;",connectionHandler.getPlayer().getDBID(), id);
|
||||
if(result.hasResult()){
|
||||
Gson gson = new Gson();
|
||||
//if we get a valid response from the database, check that it actually matches hashes
|
||||
for(DatabaseResultRow row : result){
|
||||
CreatureTemplate template = gson.fromJson(row.getAsString("dataVal"),CreatureTemplate.class);
|
||||
connectionHandler.setCreatureTemplate(template);
|
||||
}
|
||||
}
|
||||
}
|
||||
Entity rVal = PlayerCharacterCreation.spawnPlayerCharacter(connectionHandler);
|
||||
Realm realm = Globals.playerManager.getPlayerRealm(connectionHandler.getPlayer());
|
||||
Vector3d spawnPoint = realm.getSpawnPoint();
|
||||
@ -147,7 +199,7 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
|
||||
|
||||
//spawn the new one
|
||||
player.setHasSentPlayerEntity(false);
|
||||
Entity newEntity = CharacterProtocol.spawnEntityForClient(connectionHandler);
|
||||
Entity newEntity = CharacterProtocol.spawnEntityForClient(connectionHandler, CharacterProtocol.SPAWN_EXISTING_TEMPLATE);
|
||||
ServerEntityUtils.repositionEntity(newEntity, position);
|
||||
return newEntity;
|
||||
}
|
||||
|
||||
@ -10,19 +10,53 @@ import java.sql.SQLException;
|
||||
*/
|
||||
public class DatabaseResult implements Iterable<DatabaseResultRow> {
|
||||
|
||||
boolean isQuery = false;
|
||||
boolean isStatement = false;
|
||||
boolean succeeded = false;
|
||||
boolean hasResultSet = false;
|
||||
String code;
|
||||
ResultSet rs;
|
||||
/**
|
||||
* The deserializer for the data
|
||||
*/
|
||||
private static Gson deserializer;
|
||||
|
||||
/**
|
||||
* Init deserializer
|
||||
*/
|
||||
static {
|
||||
deserializer = new Gson();
|
||||
}
|
||||
|
||||
/**
|
||||
* True if this was a query
|
||||
*/
|
||||
boolean isQuery = false;
|
||||
|
||||
/**
|
||||
* True if this was a statement
|
||||
*/
|
||||
boolean isStatement = false;
|
||||
|
||||
/**
|
||||
* True if the request succeeded, false otherwise
|
||||
*/
|
||||
boolean succeeded = false;
|
||||
|
||||
/**
|
||||
* True if the result has data, false otherwise
|
||||
*/
|
||||
boolean hasResultSet = false;
|
||||
|
||||
/**
|
||||
* The code for the query
|
||||
*/
|
||||
String code;
|
||||
|
||||
/**
|
||||
* The raw result data
|
||||
*/
|
||||
ResultSet rs;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a query
|
||||
* @param code The code for the query
|
||||
* @return The results of the query
|
||||
*/
|
||||
protected static DatabaseResult createQuery(String code){
|
||||
DatabaseResult rVal = new DatabaseResult();
|
||||
rVal.isQuery = true;
|
||||
@ -30,6 +64,11 @@ public class DatabaseResult implements Iterable<DatabaseResultRow> {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a statement
|
||||
* @param code The code for the statement
|
||||
* @return The results of the statement
|
||||
*/
|
||||
protected static DatabaseResult createStatement(String code){
|
||||
DatabaseResult rVal = new DatabaseResult();
|
||||
rVal.isStatement = true;
|
||||
@ -72,10 +111,6 @@ public class DatabaseResult implements Iterable<DatabaseResultRow> {
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
|
||||
public void logRawResult(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatabaseResultIterator iterator() {
|
||||
|
||||
@ -10,10 +10,24 @@ import java.util.List;
|
||||
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
|
||||
/**
|
||||
* Iterates through a database result
|
||||
*/
|
||||
public class DatabaseResultIterator implements Iterator<DatabaseResultRow> {
|
||||
|
||||
/**
|
||||
* The result set
|
||||
*/
|
||||
ResultSet rs;
|
||||
|
||||
/**
|
||||
* The metadata of the result set
|
||||
*/
|
||||
ResultSetMetaData metadata;
|
||||
|
||||
/**
|
||||
* The type list of each column
|
||||
*/
|
||||
List<Integer> typeList;
|
||||
|
||||
/**
|
||||
@ -34,6 +48,11 @@ public class DatabaseResultIterator implements Iterator<DatabaseResultRow> {
|
||||
//if it did, we'd call this to be explicitly clear where we want to start
|
||||
//instead the assumption is it always starts ON the first element
|
||||
// this.rs.first();
|
||||
|
||||
//starts before the first, so must iterate once into the result set in order to not double-sample the first row
|
||||
if(this.rs.isBeforeFirst()){
|
||||
this.rs.next();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LoggerInterface.loggerEngine.ERROR("SQL Exception", e);
|
||||
}
|
||||
|
||||
@ -43,7 +43,9 @@
|
||||
{
|
||||
"messageName" : "RequestSpawnCharacter",
|
||||
"description" : "Requests that the server spawn the client in as a given character",
|
||||
"data" : []
|
||||
"data" : [
|
||||
"data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"messageName" : "ResponseSpawnCharacter",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user