Refining multiplayer: Fixed visualization of current number of players, not using player names. TODO: Multiple players from the same machine

master
EmaMaker 2020-04-25 14:20:31 +02:00
parent 01f38a09cb
commit fb708dfd9c
8 changed files with 111 additions and 55 deletions

View File

@ -38,7 +38,7 @@ public class GameManager {
mazeGen = new MazeGenerator(main, MazeSettings.MAZEX, MazeSettings.MAZEZ); mazeGen = new MazeGenerator(main, MazeSettings.MAZEX, MazeSettings.MAZEZ);
} }
ArrayList<MazePlayer> toDelete = new ArrayList<MazePlayer>(); // ArrayList<MazePlayer> toDelete = new ArrayList<MazePlayer>();
public void generateMaze(Set<MazePlayer> pl, int todraw[][]) { public void generateMaze(Set<MazePlayer> pl, int todraw[][]) {
main.setScreen(null); main.setScreen(null);
@ -48,25 +48,31 @@ public class GameManager {
// Only add new players and dispose the old ones // Only add new players and dispose the old ones
// Check if actually there are players to be deleted // Check if actually there are players to be deleted
if (pl != null) { if (pl != null) {
for (MazePlayer p : players)
if (!pl.contains(p))
toDelete.add(p);
// Check if new players have to be added // destroyPlayers();
for (MazePlayer p : pl) // players.addAll(p);
if (!players.contains(p)) for(MazePlayer p : players)
players.add(p); if(!p.isDisposed())
p.dispose();
// Fianlly delete players. A separated step is needed to remove the risk of a players.clear();
// ConcurrentModificationException players.addAll(pl);
for (MazePlayer p : toDelete) { // for (MazePlayer p : players)
p.dispose(); // if (!pl.contains(p))
players.remove(p); // toDelete.add(p);
} //
toDelete.clear(); // // Check if new players have to be added
// for (MazePlayer p : pl)
// if (!players.contains(p))
// players.add(p);
//
// // Fianlly delete players. A separated step is needed to remove the risk of a
// // ConcurrentModificationException
// for (MazePlayer p : toDelete) {
// p.dispose();
// players.remove(p);
// }
// toDelete.clear();
} }
// destroyPlayers();
// players.addAll(p);
for (int i = 0; i < MazeSettings.MAZEX; i++) { for (int i = 0; i < MazeSettings.MAZEX; i++) {
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
@ -102,7 +108,7 @@ public class GameManager {
main.world.modelBatch.begin(main.world.cam); main.world.modelBatch.begin(main.world.cam);
if (players != null) { if (players != null) {
for (MazePlayer p : players) { for (MazePlayer p : players) {
if (getShowGame()) if (getShowGame() && !p.isDisposed())
p.render(main.world.modelBatch, main.world.environment); p.render(main.world.modelBatch, main.world.environment);
anyoneWon = false; anyoneWon = false;
@ -120,7 +126,7 @@ public class GameManager {
System.out.println("Game Finished! " + type); System.out.println("Game Finished! " + type);
if (type == GameType.LOCAL) { if (type == GameType.LOCAL) {
main.setScreen(main.uiManager.playersScreen); main.setScreen(main.uiManager.playersScreen);
}else if(type == GameType.SERVER) { } else if (type == GameType.SERVER) {
main.uiManager.preGameScreen.setGameType(GameType.SERVER); main.uiManager.preGameScreen.setGameType(GameType.SERVER);
main.setScreen(main.uiManager.preGameScreen); main.setScreen(main.uiManager.preGameScreen);
} }
@ -211,6 +217,8 @@ public class GameManager {
public void dispose() { public void dispose() {
for (MazePlayer p : players) for (MazePlayer p : players)
p.dispose(); if (!p.isDisposed())
p.dispose();
players.clear();
} }
} }

View File

@ -136,9 +136,8 @@ public class GameClient {
} }
public void disconnected(Connection connection) { public void disconnected(Connection connection) {
for (MazePlayerRemote p : remotePlayers.values()) { toRemove.addAll(remotePlayers.keySet());
p.dispose(); toRemove.add(uuid);
}
} }
}); });
@ -168,8 +167,10 @@ public class GameClient {
} }
toAdd.clear(); toAdd.clear();
for (String s : toRemove) { for (String s : toRemove) {
remotePlayers.get(s).dispose(); if (remotePlayers.get(s) != null) {
remotePlayers.remove(s); remotePlayers.get(s).dispose();
remotePlayers.remove(s);
}else if(s.equals(uuid)) player.dispose();
} }
toRemove.clear(); toRemove.clear();
} catch (Exception e) { } catch (Exception e) {
@ -245,6 +246,20 @@ public class GameClient {
public void stop() { public void stop() {
if (clientRunning) { if (clientRunning) {
RemovePlayer request = new RemovePlayer();
request.uuid = uuid;
client.sendTCP(request);
for (MazePlayer p : remotePlayers.values())
if (!p.isDisposed())
p.dispose();
for (MazePlayer p : players)
if (!p.isDisposed())
p.dispose();
remotePlayers.clear();
players.clear();
client.stop(); client.stop();
clientRunning = false; clientRunning = false;
} }

View File

@ -80,6 +80,7 @@ public class GameServer {
response.uuid = connection.uuid; response.uuid = connection.uuid;
System.out.println("Server received connection request! Giving client UUID " + connection.uuid); System.out.println("Server received connection request! Giving client UUID " + connection.uuid);
c.sendTCP(response); c.sendTCP(response);
} else if (object instanceof LoginAO2) { } else if (object instanceof LoginAO2) {
// Ignore is there's no uuid or it's different from the login message one // Ignore is there's no uuid or it's different from the login message one
if (connection.uuid == null || !connection.uuid.equals(((LoginAO2) object).uuid)) if (connection.uuid == null || !connection.uuid.equals(((LoginAO2) object).uuid))
@ -90,7 +91,7 @@ public class GameServer {
// Otherwise add a new player and notify all clients about it // Otherwise add a new player and notify all clients about it
remotePlayers.put(((LoginAO2) object).uuid, remotePlayers.put(((LoginAO2) object).uuid,
new MazePlayerRemote(main, ((LoginAO2) object).uuid, false)); new MazePlayerRemote(main, ((LoginAO2) object).uuid, false));
AddNewPlayer response = new AddNewPlayer(); AddNewPlayer response = new AddNewPlayer();
response.uuid = ((LoginAO2) object).uuid; response.uuid = ((LoginAO2) object).uuid;
@ -112,7 +113,9 @@ public class GameServer {
if (connection.uuid == null || !connection.uuid.equals(((RemovePlayer) object).uuid)) if (connection.uuid == null || !connection.uuid.equals(((RemovePlayer) object).uuid))
return; return;
// Otherwise remove the player and notify all clients about it // Otherwise remove the player and notify all clients about it
remotePlayers.get(((RemovePlayer) object).uuid).dispose(); if (remotePlayers.get(((RemovePlayer) object).uuid) != null) {
remotePlayers.get(((RemovePlayer) object).uuid).dispose();
}
remotePlayers.remove(((RemovePlayer) object).uuid); remotePlayers.remove(((RemovePlayer) object).uuid);
System.out.println("Client with UUID " + connection.uuid + " is leaving the server :("); System.out.println("Client with UUID " + connection.uuid + " is leaving the server :(");
@ -139,9 +142,10 @@ public class GameServer {
public void disconnected(Connection c) { public void disconnected(Connection c) {
ConnectionPlayer connection = (ConnectionPlayer) c; ConnectionPlayer connection = (ConnectionPlayer) c;
if (connection.uuid != null) { if (connection.uuid != null) {
remotePlayers.get(connection.uuid).dispose(); if (remotePlayers.get(connection.uuid) != null) {
remotePlayers.get(connection.uuid).dispose();
}
remotePlayers.remove(connection.uuid); remotePlayers.remove(connection.uuid);
RemovePlayer remove = new RemovePlayer(); RemovePlayer remove = new RemovePlayer();
remove.uuid = connection.uuid; remove.uuid = connection.uuid;
server.sendToAllTCP(remove); server.sendToAllTCP(remove);
@ -191,7 +195,7 @@ public class GameServer {
this.gameManager = new GameManager(main, GameType.SERVER); this.gameManager = new GameManager(main, GameType.SERVER);
this.gameManager.generateMaze(new HashSet<MazePlayer>(remotePlayers.values())); this.gameManager.generateMaze(new HashSet<MazePlayer>(remotePlayers.values()));
endGameCalled = false; endGameCalled = false;
StartGame request = new StartGame(); StartGame request = new StartGame();
request.map = this.gameManager.mazeGen.runLenghtEncode(); request.map = this.gameManager.mazeGen.runLenghtEncode();
server.sendToAllTCP(request); server.sendToAllTCP(request);
@ -245,8 +249,11 @@ public class GameServer {
public void stop() { public void stop() {
for (MazePlayerRemote p : remotePlayers.values()) for (MazePlayerRemote p : remotePlayers.values())
p.dispose(); if (!p.isDisposed())
p.dispose();
remotePlayers.clear();
if (serverRunning) { if (serverRunning) {
main.client.stop();
server.stop(); server.stop();
serverRunning = false; serverRunning = false;
} }

View File

@ -243,8 +243,8 @@ public class MazeGenerator {
main.world.worldManager.setCell(i, 0, j, CellId.ID_GRASS); main.world.worldManager.setCell(i, 0, j, CellId.ID_GRASS);
// if (todraw[i][j] == 1) if (todraw[i][j] == 1)
// main.world.worldManager.setCell(i, 1, j, CellId.ID_LEAVES); main.world.worldManager.setCell(i, 1, j, CellId.ID_LEAVES);
if (todraw[i][j] == 2) { if (todraw[i][j] == 2) {
WINX = i; WINX = i;
WINZ = j; WINZ = j;

View File

@ -15,10 +15,11 @@ import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder; import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.math.Quaternion; import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Disposable;
import com.emamaker.amazeing.AMazeIng; import com.emamaker.amazeing.AMazeIng;
import com.emamaker.voxelengine.physics.GameObject; import com.emamaker.voxelengine.physics.GameObject;
public abstract class MazePlayer { public abstract class MazePlayer implements Disposable {
AMazeIng main; AMazeIng main;
@ -33,6 +34,7 @@ public abstract class MazePlayer {
public GameObject obj; public GameObject obj;
String name = ""; String name = "";
boolean disposing = false; boolean disposing = false;
boolean disposed = false;
boolean playing = false; boolean playing = false;
boolean show = true; boolean show = true;
@ -42,6 +44,7 @@ public abstract class MazePlayer {
MazePlayer(Game main_, boolean s) { MazePlayer(Game main_, boolean s) {
this(main_, String.valueOf((char) (65 + rand.nextInt(26))), s); this(main_, String.valueOf((char) (65 + rand.nextInt(26))), s);
disposing = false; disposing = false;
disposed = false;
playing = false; playing = false;
} }
@ -77,10 +80,11 @@ public abstract class MazePlayer {
} }
public void setTransform(float x, float y, float z, float i, float j, float k, float l) { public void setTransform(float x, float y, float z, float i, float j, float k, float l) {
if (!disposing ) { if (!disposing) {
pos.set(x, y, z); pos.set(x, y, z);
rot.set(i, j, k, l); rot.set(i, j, k, l);
if(show) instance.transform.set(x, y, z, i, j, k, l); if (show)
instance.transform.set(x, y, z, i, j, k, l);
} }
} }
@ -113,10 +117,22 @@ public abstract class MazePlayer {
public void update() { public void update() {
} }
@Override
public void dispose() { public void dispose() {
playing =false; playing = false;
if (!disposed) {
disposing = true;
if (show)
mazePlayerModel.dispose();
disposing = false;
}
disposed = true;
} }
public boolean isDisposed() {
return disposed;
}
public boolean isPlaying() { public boolean isPlaying() {
return playing; return playing;
} }

View File

@ -149,6 +149,7 @@ public class MazePlayerLocal extends MazePlayer {
public void update() { public void update() {
inputs(); inputs();
} }
@Override @Override
public Vector3 getPos() { public Vector3 getPos() {
if (!disposing) { if (!disposing) {
@ -178,13 +179,13 @@ public class MazePlayerLocal extends MazePlayer {
@Override @Override
public void dispose() { public void dispose() {
super.dispose();
disposing = true; disposing = true;
main.world.dynamicsWorld.removeAction(characterController); main.world.dynamicsWorld.removeAction(characterController);
main.world.dynamicsWorld.removeCollisionObject(ghostObject); main.world.dynamicsWorld.removeCollisionObject(ghostObject);
characterController.dispose(); characterController.dispose();
ghostObject.dispose(); ghostObject.dispose();
ghostShape.dispose(); ghostShape.dispose();
mazePlayerModel.dispose();
disposing = false; disposing = false;
} }

View File

@ -1,7 +1,5 @@
package com.emamaker.amazeing.ui.screens; package com.emamaker.amazeing.ui.screens;
import java.util.Arrays;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen; import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.GL20;
@ -27,6 +25,7 @@ public class PreGameScreen implements Screen {
Label[] labels; Label[] labels;
MazePlayer[] players, tmp; MazePlayer[] players, tmp;
int nPlayers, nPlayersOld;
// GameType we are runnig. assuming server for default. If client, the StartGame // GameType we are runnig. assuming server for default. If client, the StartGame
// button shouldn't appear // button shouldn't appear
@ -44,7 +43,9 @@ public class PreGameScreen implements Screen {
labels = new Label[MazeSettings.MAXPLAYERS]; labels = new Label[MazeSettings.MAXPLAYERS];
players = new MazePlayer[MazeSettings.MAXPLAYERS]; players = new MazePlayer[MazeSettings.MAXPLAYERS];
tmp = new MazePlayer[MazeSettings.MAXPLAYERS]; // tmp = new MazePlayer[MazeSettings.MAXPLAYERS];
nPlayers = 0;
nPlayersOld = 0;
stage = new Stage(new ScreenViewport()); stage = new Stage(new ScreenViewport());
Container<Table> tableContainer = new Container<Table>(); Container<Table> tableContainer = new Container<Table>();
@ -62,8 +63,9 @@ public class PreGameScreen implements Screen {
TextButton helpBtn = new TextButton("?", uiManager.skin); TextButton helpBtn = new TextButton("?", uiManager.skin);
TextButton playBtn = new TextButton("Start the match!", uiManager.skin); TextButton playBtn = new TextButton("Start the match!", uiManager.skin);
if(type == GameType.CLIENT) instLab.setText("Waiting for server to start the game..."); if (type == GameType.CLIENT)
instLab.setText("Waiting for server to start the game...");
// Labels to know if players joined // Labels to know if players joined
for (int i = 0; i < labels.length; i++) { for (int i = 0; i < labels.length; i++) {
labels[i] = new Label("-- empty slot --", uiManager.skin); labels[i] = new Label("-- empty slot --", uiManager.skin);
@ -74,7 +76,13 @@ public class PreGameScreen implements Screen {
@Override @Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
hide(); hide();
uiManager.main.setScreen(type == GameType.SERVER ? uiManager.srvLaunchScreen : uiManager.srvJoinScreen); if (type == GameType.SERVER) {
uiManager.main.server.stop();
uiManager.main.setScreen(uiManager.srvLaunchScreen);
} else if (type == GameType.CLIENT) {
uiManager.main.client.stop();
uiManager.main.setScreen(uiManager.srvJoinScreen);
}
return true; return true;
} }
}); });
@ -150,18 +158,20 @@ public class PreGameScreen implements Screen {
// Constantly update player labels, comparing with the remote players present on // Constantly update player labels, comparing with the remote players present on
// server // server
tmp = type == GameType.SERVER nPlayers = type == GameType.SERVER ? uiManager.main.server.remotePlayers.values().size()
? Arrays.copyOf(uiManager.main.server.remotePlayers.values().toArray(), : uiManager.main.client.players.size();
uiManager.main.server.remotePlayers.values().size(), MazePlayer[].class) // tmp = type == GameType.SERVER
: Arrays.copyOf(uiManager.main.client.players.toArray(), uiManager.main.client.players.size(), // ? Arrays.copyOf(uiManager.main.server.remotePlayers.values().toArray(),
MazePlayer[].class); // uiManager.main.server.remotePlayers.values().size(), MazePlayer[].class)
if (!(Arrays.equals(players, tmp))) { // : Arrays.copyOf(uiManager.main.client.players.toArray(), uiManager.main.client.players.size(),
// MazePlayer[].class);
if (nPlayers != nPlayersOld) {
// Update Labels // Update Labels
for (int i = 0; i < tmp.length; i++) { for (int i = 0; i < labels.length; i++) {
players[i] = tmp[i]; labels[i].setText(i < nPlayers ? "-- Player Ready! --" : "-- empty slot --" );
labels[i].setText(players[i].getName());
} }
} }
nPlayersOld = nPlayers;
} }
public void setGameType(GameType t) { public void setGameType(GameType t) {

View File

@ -13,7 +13,6 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextArea;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.emamaker.amazeing.manager.GameType;
import com.emamaker.amazeing.ui.UIManager; import com.emamaker.amazeing.ui.UIManager;
public class ServerLaunchScreen implements Screen { public class ServerLaunchScreen implements Screen {