Multiplayer: syncronize settings between server and clients
parent
607bf7b91e
commit
98d66880a8
|
@ -1,10 +1,11 @@
|
|||
package com.emamaker.amazeing.manager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import com.badlogic.gdx.Game;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Screen;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.math.Plane.PlaneSide;
|
||||
import com.badlogic.gdx.scenes.scene2d.Stage;
|
||||
import com.badlogic.gdx.utils.viewport.ScreenViewport;
|
||||
import com.emamaker.amazeing.AMazeIng;
|
||||
|
@ -17,10 +18,6 @@ import com.emamaker.amazeing.ui.screens.PreGameScreen;
|
|||
import com.emamaker.voxelengine.block.CellId;
|
||||
import com.emamaker.voxelengine.player.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
public class GameManager {
|
||||
|
||||
AMazeIng main;
|
||||
|
|
|
@ -21,6 +21,8 @@ import com.emamaker.amazeing.manager.network.NetworkCommon.RemovePlayer;
|
|||
import com.emamaker.amazeing.manager.network.NetworkCommon.StartGame;
|
||||
import com.emamaker.amazeing.manager.network.NetworkCommon.UpdateMap;
|
||||
import com.emamaker.amazeing.manager.network.NetworkCommon.UpdatePlayerTransform;
|
||||
import com.emamaker.amazeing.manager.network.NetworkCommon.UpdateSettings;
|
||||
import com.emamaker.amazeing.maze.settings.MazeSettings;
|
||||
import com.emamaker.amazeing.player.MazePlayer;
|
||||
import com.emamaker.amazeing.player.MazePlayerLocal;
|
||||
import com.emamaker.amazeing.player.MazePlayerRemote;
|
||||
|
@ -126,6 +128,17 @@ public class GameClient {
|
|||
gameManager.anyoneWon = true;
|
||||
showPreGame = true;
|
||||
}
|
||||
} else if (object instanceof UpdateSettings) {
|
||||
System.out.println("Update received for setting n." + ((UpdateSettings) object).index);
|
||||
if (!main.server.isRunning()) {
|
||||
MazeSettings.settings.get(((UpdateSettings) object).index)
|
||||
.parseOptionString(((UpdateSettings) object).value);
|
||||
}else {
|
||||
System.out.println("Ignoring settings update since we are running on a server");
|
||||
}
|
||||
|
||||
//We don't mind if we are client or server, just set the flag to update pregamescreen
|
||||
showPreGame = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.emamaker.amazeing.manager.network.NetworkCommon.LoginAO2;
|
|||
import com.emamaker.amazeing.manager.network.NetworkCommon.RemovePlayer;
|
||||
import com.emamaker.amazeing.manager.network.NetworkCommon.StartGame;
|
||||
import com.emamaker.amazeing.manager.network.NetworkCommon.UpdatePlayerTransform;
|
||||
import com.emamaker.amazeing.manager.network.NetworkCommon.UpdateSettings;
|
||||
import com.emamaker.amazeing.maze.settings.MazeSettings;
|
||||
import com.emamaker.amazeing.player.MazePlayer;
|
||||
import com.emamaker.amazeing.player.MazePlayerRemote;
|
||||
|
@ -76,16 +77,17 @@ public class GameServer {
|
|||
public void received(Connection c, Object object) {
|
||||
ConnectionPlayer connection = (ConnectionPlayer) c;
|
||||
|
||||
if(object instanceof JustConnected) {
|
||||
//Notify the newly connected client about all other clients already present here
|
||||
System.out.println("New client just connected, updating it with info about other clients!");
|
||||
if (object instanceof JustConnected) {
|
||||
// Notify the newly connected client about all other clients already present
|
||||
// here
|
||||
System.out.println("New client just connected, updating it with info about other clients!");
|
||||
AddNewPlayer response = new AddNewPlayer();
|
||||
for (String s : remotePlayers.keySet()) {
|
||||
response.uuid = s;
|
||||
c.sendTCP(response);
|
||||
System.out.println("Updated about: " + s);
|
||||
}
|
||||
}else if (object instanceof LoginAO) {
|
||||
}
|
||||
} else if (object instanceof LoginAO) {
|
||||
// Give player its UUID and wait for response. Once the LoginAO2 response is
|
||||
// received, move the
|
||||
// UUID to the list of players, create a new one and notify clients about it
|
||||
|
@ -103,12 +105,15 @@ public class GameServer {
|
|||
remotePlayers.put(((LoginAO2) object).uuid,
|
||||
new MazePlayerRemote(((LoginAO2) object).uuid, false));
|
||||
|
||||
System.out.println(
|
||||
"Client with UUID " + ((LoginAO2) object).uuid + " is connected and ready to play :)");
|
||||
|
||||
updateSettingForClient(c);
|
||||
|
||||
System.out.println("Client with UUID " + ((LoginAO2) object).uuid
|
||||
+ " is connected and ready to play :)");
|
||||
|
||||
AddNewPlayer response = new AddNewPlayer();
|
||||
response.uuid = ((LoginAO2) object).uuid;
|
||||
server.sendToAllTCP(response);
|
||||
|
||||
} else {
|
||||
// Send connection refused
|
||||
c.sendTCP(new ConnectionRefused());
|
||||
|
@ -122,8 +127,9 @@ public class GameServer {
|
|||
|
||||
System.out.println("Client with UUID " + connection.uuid + " is leaving the server :(");
|
||||
server.sendToAllTCP(object);
|
||||
}else {
|
||||
System.out.println("Server received delete message for player with UUID " + connection.uuid + " but player wasn't playing");
|
||||
} else {
|
||||
System.out.println("Server received delete message for player with UUID " + connection.uuid
|
||||
+ " but player wasn't playing");
|
||||
}
|
||||
} else if (object instanceof UpdatePlayerTransform) {
|
||||
UpdatePlayerTransform transform = (UpdatePlayerTransform) object;
|
||||
|
@ -189,29 +195,34 @@ public class GameServer {
|
|||
// host should decide when to start the gmae
|
||||
// A proper ui should be added, but for now we can just start the game without
|
||||
// showing any players and just show the map across all the clients
|
||||
public void startGame() {
|
||||
public boolean startGame() {
|
||||
if (serverRunning) {
|
||||
update();
|
||||
// Start game stuff
|
||||
this.gameManager = new GameManager(main, GameType.SERVER);
|
||||
this.gameManager.generateMaze(new HashSet<MazePlayer>(remotePlayers.values()));
|
||||
endGameCalled = false;
|
||||
|
||||
StartGame request = new StartGame();
|
||||
request.map = this.gameManager.mazeGen.runLenghtEncode();
|
||||
server.sendToAllTCP(request);
|
||||
if (!remotePlayers.isEmpty()) {
|
||||
// Start game stuff
|
||||
this.gameManager = new GameManager(main, GameType.SERVER);
|
||||
this.gameManager.generateMaze(new HashSet<MazePlayer>(remotePlayers.values()));
|
||||
endGameCalled = false;
|
||||
|
||||
if (gameManager.gameStarted)
|
||||
for (String p : remotePlayers.keySet())
|
||||
updatePlayer(p, remotePlayers.get(p), true);
|
||||
StartGame request = new StartGame();
|
||||
request.map = this.gameManager.mazeGen.runLenghtEncode();
|
||||
server.sendToAllTCP(request);
|
||||
|
||||
if (main.getScreen() != null) {
|
||||
main.getScreen().hide();
|
||||
main.setScreen(null);
|
||||
if (gameManager.gameStarted)
|
||||
for (String p : remotePlayers.keySet())
|
||||
updatePlayer(p, remotePlayers.get(p), true);
|
||||
|
||||
if (main.getScreen() != null) {
|
||||
main.getScreen().hide();
|
||||
main.setScreen(null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
System.out.println("Server not started yet, game cannot start");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updatePlayer(String uuid, MazePlayerRemote p, boolean force) {
|
||||
|
@ -263,6 +274,28 @@ public class GameServer {
|
|||
public boolean isRunning() {
|
||||
return serverRunning;
|
||||
}
|
||||
|
||||
UpdateSettings s = new UpdateSettings();
|
||||
|
||||
// Send updates about settings to the clients
|
||||
public void updateSettingForAll() {
|
||||
if(isRunning())
|
||||
for (int i = 0; i < MazeSettings.settings.size(); i++) {
|
||||
s.index = i;
|
||||
s.value = MazeSettings.settings.get(i).getOptionString();
|
||||
server.sendToAllTCP(s);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSettingForClient(Connection c) {
|
||||
if(isRunning())
|
||||
for (int i = 0; i < MazeSettings.settings.size(); i++) {
|
||||
s.index = i;
|
||||
s.value = MazeSettings.settings.get(i).getOptionString();
|
||||
c.sendTCP(s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ConnectionPlayer extends Connection {
|
||||
|
|
|
@ -7,7 +7,7 @@ public class NetworkCommon {
|
|||
|
||||
|
||||
// This registers objects that are going to be sent over the network.
|
||||
static public void register(EndPoint endPoint) {
|
||||
public static void register(EndPoint endPoint) {
|
||||
Kryo kryo = endPoint.getKryo();
|
||||
kryo.register(JustConnected.class);
|
||||
kryo.register(LoginAO.class);
|
||||
|
@ -21,51 +21,57 @@ public class NetworkCommon {
|
|||
kryo.register(StartGame.class);
|
||||
kryo.register(EndGame.class);
|
||||
kryo.register(UpdateMap.class);
|
||||
kryo.register(UpdateSettings.class);
|
||||
}
|
||||
|
||||
//Login stuff
|
||||
static public class JustConnected {
|
||||
public static class JustConnected {
|
||||
}
|
||||
static public class LoginAO {
|
||||
public static class LoginAO {
|
||||
}
|
||||
static public class LoginAO2 {
|
||||
public static class LoginAO2 {
|
||||
String uuid;
|
||||
}
|
||||
static public class ConnectionRefused {
|
||||
public static class ConnectionRefused {
|
||||
String uuid;
|
||||
}
|
||||
static public class LoginUUID {
|
||||
public static class LoginUUID {
|
||||
String uuid;
|
||||
}
|
||||
|
||||
//Player stuff
|
||||
static public class AddNewPlayer {
|
||||
public static class AddNewPlayer {
|
||||
String uuid;
|
||||
}
|
||||
static public class RemovePlayer {
|
||||
public static class RemovePlayer {
|
||||
String uuid;
|
||||
}
|
||||
static public class UpdatePlayerTransform {
|
||||
public static class UpdatePlayerTransform {
|
||||
String uuid;
|
||||
float tx, ty, tz, rx, ry, rz, rw;
|
||||
}
|
||||
static public class UpdatePlayerTransformServer {
|
||||
public static class UpdatePlayerTransformServer {
|
||||
String uuid;
|
||||
float tx, ty, tz, rx, ry, rz, rw;
|
||||
}
|
||||
|
||||
static public class StartGame{
|
||||
public static class StartGame{
|
||||
//Use this to notify clients of a newly started game
|
||||
//A Run-lenght-encoded representation of the map can be appended, this can be avoided but it's not recommended
|
||||
String map;
|
||||
}
|
||||
static public class EndGame{
|
||||
public static class EndGame{
|
||||
//Use this to notify clients when a game ends
|
||||
}
|
||||
static public class UpdateMap{
|
||||
public static class UpdateMap{
|
||||
//Use this to notify clients of a modification of the map
|
||||
//Run-lenght-encoded representation of the map
|
||||
String map;
|
||||
}
|
||||
|
||||
|
||||
public static class UpdateSettings {
|
||||
int index;
|
||||
String value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class MazeSetting {
|
|||
|
||||
//Build the Table which will be later used to add this to the screen
|
||||
table = new Table();
|
||||
nameLabel = new Label(this.name+"\t\t\t", uiManager.skin);
|
||||
nameLabel = new Label(this.name, uiManager.skin);
|
||||
currentOptLabel = new Label(this.options[currentOption], uiManager.skin);
|
||||
backBtn = new TextButton("<", uiManager.skin);
|
||||
forthBtn = new TextButton(">", uiManager.skin);
|
||||
|
@ -89,7 +89,9 @@ public class MazeSetting {
|
|||
}
|
||||
|
||||
public void update() {
|
||||
preUpdate();
|
||||
currentOption = (currentOption+options.length)%options.length;
|
||||
currentOptLabel.setText(options[currentOption]);
|
||||
parseOptionString(options[currentOption]);
|
||||
}
|
||||
|
||||
public void saveState() {
|
||||
|
@ -123,9 +125,9 @@ public class MazeSetting {
|
|||
table.add(resetBtn).fillX().expandX();
|
||||
}
|
||||
|
||||
public void preUpdate() {
|
||||
this.currentOption = (this.currentOption+this.options.length)%this.options.length;
|
||||
this.currentOptLabel.setText(this.options[currentOption]);
|
||||
public void parseOptionString(String opt) {}
|
||||
public String getOptionString() {
|
||||
return options[currentOption];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,11 +16,9 @@ public class MazeSettingDimension extends MazeSetting{
|
|||
public MazeSettingDimension(String name_, String[] options_, UIManager uiManager_) {
|
||||
super(name_, options_, uiManager_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
super.update();
|
||||
String opt = options[currentOption];
|
||||
public void parseOptionString(String opt) {
|
||||
super.parseOptionString(opt);
|
||||
String[] split = opt.split("x");
|
||||
MazeSettings.MAZEX = Integer.valueOf(split[0]);
|
||||
MazeSettings.MAZEZ = Integer.valueOf(split[1]);
|
||||
|
|
|
@ -14,9 +14,8 @@ public class MazeSettingMaxPlayers extends MazeSetting{
|
|||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
super.update();
|
||||
MazeSettings.MAXPLAYERS = Integer.valueOf(options[currentOption]);
|
||||
public void parseOptionString(String opt) {
|
||||
MazeSettings.MAXPLAYERS = Integer.valueOf(opt);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ public class MyScreen implements Screen {
|
|||
|
||||
update();
|
||||
|
||||
stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
|
||||
stage.act();
|
||||
stage.draw();
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ public class PlayerChooseScreen extends MyScreen {
|
|||
for (MazePlayer p : players)
|
||||
p.dispose();
|
||||
players.clear();
|
||||
|
||||
|
||||
for (int i = 0; i < buttons.length; i++)
|
||||
if (buttons[i].isChecked())
|
||||
players.add(new MazePlayerLocal(new Touchpad(0f, uiManager.skin), i));
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.emamaker.amazeing.ui.screens;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputListener;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Container;
|
||||
|
@ -9,13 +11,12 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table;
|
|||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
||||
import com.emamaker.amazeing.manager.GameType;
|
||||
import com.emamaker.amazeing.maze.settings.MazeSettings;
|
||||
import com.emamaker.amazeing.player.MazePlayer;
|
||||
import com.emamaker.amazeing.ui.UIManager;
|
||||
|
||||
public class PreGameScreen extends MyScreen {
|
||||
|
||||
Label[] labels;
|
||||
MazePlayer[] players;
|
||||
// MazePlayer[] players;
|
||||
int nPlayers, nPlayersOld;
|
||||
|
||||
// GameType we are runnig. assuming server for default. If client, the StartGame
|
||||
|
@ -29,7 +30,7 @@ public class PreGameScreen extends MyScreen {
|
|||
Label instLab, helpDlgText;
|
||||
TextButton backBtn, setBtn, helpBtn, playBtn, helpDlgOkBtn;
|
||||
Dialog helpDlg;
|
||||
|
||||
|
||||
public PreGameScreen(UIManager uiManager_) {
|
||||
super(uiManager_);
|
||||
chmult = 0.8f;
|
||||
|
@ -40,8 +41,6 @@ public class PreGameScreen extends MyScreen {
|
|||
super.createTable();
|
||||
thisScreen = this;
|
||||
|
||||
labels = new Label[MazeSettings.MAXPLAYERS];
|
||||
players = new MazePlayer[MazeSettings.MAXPLAYERS];
|
||||
nPlayers = 0;
|
||||
nPlayersOld = 0;
|
||||
|
||||
|
@ -61,8 +60,9 @@ public class PreGameScreen extends MyScreen {
|
|||
+ "If you're a server, wait for players and start the game pressing the \"Start the match!\" button.\n"
|
||||
+ "How to join (for both client and server):\n"
|
||||
+ "On a computer players can join or leave the game pressing WASD, Arrow buttons or\n"
|
||||
+ "a button on the controller\n" + "On mobile players can be toggled using the buttons below.", uiManager.skin);
|
||||
helpDlg.text(helpDlgText);
|
||||
+ "a button on the controller\n" + "On mobile players can be toggled using the buttons below.",
|
||||
uiManager.skin);
|
||||
helpDlg.text(helpDlgText);
|
||||
helpDlgOkBtn = new TextButton("OK", uiManager.skin);
|
||||
helpDlg.button(helpDlgOkBtn);
|
||||
helpDlgOkBtn.addListener(new InputListener() {
|
||||
|
@ -76,11 +76,6 @@ public class PreGameScreen extends MyScreen {
|
|||
if (type == GameType.CLIENT)
|
||||
instLab.setText("Waiting for server to start the game...");
|
||||
|
||||
// Labels to know if players joined
|
||||
for (int i = 0; i < labels.length; i++) {
|
||||
labels[i] = new Label("-- empty slot --", uiManager.skin);
|
||||
}
|
||||
|
||||
// Add actions to the buttons
|
||||
backBtn.addListener(new InputListener() {
|
||||
@Override
|
||||
|
@ -100,8 +95,8 @@ public class PreGameScreen extends MyScreen {
|
|||
playBtn.addListener(new InputListener() {
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
|
||||
hide();
|
||||
uiManager.main.server.startGame();
|
||||
if (uiManager.main.server.startGame())
|
||||
hide();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
@ -112,7 +107,6 @@ public class PreGameScreen extends MyScreen {
|
|||
hide();
|
||||
uiManager.setScreen.setPrevScreen(thisScreen);
|
||||
uiManager.main.setScreen(uiManager.setScreen);
|
||||
System.out.println("Bup");
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
@ -134,21 +128,31 @@ public class PreGameScreen extends MyScreen {
|
|||
@Override
|
||||
public void buildTable() {
|
||||
super.buildTable();
|
||||
firstRowTable.clear();
|
||||
|
||||
firstRowTable.clear();
|
||||
|
||||
float d = containerDiagonal();
|
||||
float labScale = d * .00090f;
|
||||
float buttonDim = d * 0.05f;
|
||||
|
||||
labels = new Label[MazeSettings.MAXPLAYERS];
|
||||
|
||||
// Labels to know if players joined
|
||||
for (int i = 0; i < labels.length; i++) {
|
||||
labels[i] = new Label("-- empty slot --", uiManager.skin);
|
||||
}
|
||||
|
||||
System.out.println(Arrays.toString(labels));
|
||||
|
||||
firstRowContainer.setSize(cw, ch * 0.2f);
|
||||
firstRowContainer.setPosition(tableContainer.getX(), ch * 0.1f);
|
||||
firstRowContainer.fill();
|
||||
|
||||
helpDlg.setSize(cw*0.65f, ch*0.4f);
|
||||
helpDlg.setPosition((sw-helpDlg.getWidth())/2, (sh-helpDlg.getHeight())/2);
|
||||
helpDlgText.setFontScale(labScale*0.9f);
|
||||
helpDlgOkBtn.getLabel().setFontScale(labScale*0.9f);
|
||||
|
||||
helpDlg.setSize(cw * 0.65f, ch * 0.4f);
|
||||
helpDlg.setPosition((sw - helpDlg.getWidth()) / 2, (sh - helpDlg.getHeight()) / 2);
|
||||
helpDlgText.setFontScale(labScale * 0.9f);
|
||||
helpDlgOkBtn.getLabel().setFontScale(labScale * 0.9f);
|
||||
|
||||
instLab.setFontScale(labScale);
|
||||
backBtn.getLabel().setFontScale(labScale);
|
||||
setBtn.getLabel().setFontScale(labScale);
|
||||
|
@ -162,6 +166,7 @@ public class PreGameScreen extends MyScreen {
|
|||
firstRowTable.add(helpBtn).fillX().expandX().space(cw * 0.005f).width(buttonDim).height(buttonDim);
|
||||
|
||||
table.row().colspan(MazeSettings.MAXPLAYERS == 2 ? 2 : 4);
|
||||
table.row().colspan(4);
|
||||
table.add(firstRowContainer);
|
||||
|
||||
for (int i = 0; i < labels.length; i++) {
|
||||
|
@ -184,13 +189,12 @@ public class PreGameScreen extends MyScreen {
|
|||
// server
|
||||
nPlayers = type == GameType.SERVER ? uiManager.main.server.remotePlayers.values().size()
|
||||
: uiManager.main.client.players.size();
|
||||
if (nPlayers != nPlayersOld) {
|
||||
if (labels.length > 0) {
|
||||
// Update Labels
|
||||
for (int i = 0; i < labels.length; i++) {
|
||||
labels[i].setText(i < nPlayers ? "-- Player Ready! --" : "-- empty slot --");
|
||||
}
|
||||
}
|
||||
nPlayersOld = nPlayers;
|
||||
}
|
||||
|
||||
public void setGameType(GameType t) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
|||
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
||||
import com.emamaker.amazeing.AMazeIng;
|
||||
import com.emamaker.amazeing.maze.settings.MazeSetting;
|
||||
import com.emamaker.amazeing.maze.settings.MazeSettings;
|
||||
import com.emamaker.amazeing.ui.UIManager;
|
||||
|
@ -137,8 +138,12 @@ public class SettingsScreen extends MyScreen {
|
|||
saveBtn.addListener(new InputListener() {
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
|
||||
//If we are running server, we must send update to clients
|
||||
AMazeIng.getMain().server.updateSettingForAll();
|
||||
|
||||
hide();
|
||||
uiManager.main.setScreen(prevScreen == null ? uiManager.titleScreen : prevScreen);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue