Continous information between server and client now working correctly

master
EmaMaker 2020-04-17 13:28:25 +02:00
parent 15979d1d5a
commit ab89f9e348
6 changed files with 266 additions and 135 deletions

View File

@ -0,0 +1,63 @@
package com.emamaker.amazeing.manager;
import java.io.IOException;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Net.Protocol;
import com.badlogic.gdx.net.Socket;
import com.badlogic.gdx.net.SocketHints;
import com.emamaker.amazeing.AMazeIng;
public class GameClient {
volatile boolean clientRunning = false;
public Socket socket;
public String addr;
public int port;
Thread clientThread;
public AMazeIng main;
public GameClient(AMazeIng main_) {
main = main_;
}
public void start(String addr_, int port_) {
port = port_;
addr = addr_;
clientThread = new Thread(new Runnable() {
@Override
public void run() {
clientRunning = true;
while (clientRunning) {
/*
* https://www.gamefromscratch.com/post/2014/03/11/LibGDX-Tutorial-10-Basic-
* networking.aspx
*/
if (socket == null) {
SocketHints socketHints = new SocketHints();
socketHints.connectTimeout = 0;
socket = Gdx.net.newClientSocket(Protocol.TCP, addr, port, socketHints);
System.out.println("Connected to server!");
} else {
if (socket.isConnected()) {
// Send messages to the server:
try {
// write our entered message to the stream
socket.getOutputStream().write("AO\n".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
});
clientThread.start();
}
public void stop() {
clientRunning = false;
}
}

View File

@ -5,28 +5,32 @@ import java.util.Random;
import java.util.Set; import java.util.Set;
import com.badlogic.gdx.Game; import com.badlogic.gdx.Game;
import com.badlogic.gdx.math.Vector3;
import com.emamaker.amazeing.AMazeIng; import com.emamaker.amazeing.AMazeIng;
import com.emamaker.amazeing.maze.MazeGenerator; import com.emamaker.amazeing.maze.MazeGenerator;
import com.emamaker.amazeing.maze.settings.MazeSettings; import com.emamaker.amazeing.maze.settings.MazeSettings;
import com.emamaker.amazeing.player.MazePlayer; import com.emamaker.amazeing.player.MazePlayer;
import com.emamaker.voxelengine.block.CellId; import com.emamaker.voxelengine.block.CellId;
import com.emamaker.voxelengine.player.Player; import com.emamaker.voxelengine.player.Player;
import com.emamaker.voxelengine.utils.VoxelSettings;
public class GameManager { public class GameManager {
/*Local manager for local games and server host in multiplayer games*/
public MazeGenerator mazeGen; public MazeGenerator mazeGen;
public boolean gameStarted = false; public boolean gameStarted = false;
Random rand = new Random(); Random rand = new Random();
public GameServer server;
public GameClient client;
AMazeIng main; AMazeIng main;
ArrayList<MazePlayer> players = new ArrayList<MazePlayer>(); ArrayList<MazePlayer> players = new ArrayList<MazePlayer>();
public GameManager(Game main_) { public GameManager(Game main_) {
main = (AMazeIng) main_; main = (AMazeIng) main_;
gameStarted = false; gameStarted = false;
server = new GameServer(main);
client = new GameClient(main);
// Maze Generation // Maze Generation
mazeGen = new MazeGenerator(main, MazeSettings.MAZEX, MazeSettings.MAZEZ); mazeGen = new MazeGenerator(main, MazeSettings.MAZEX, MazeSettings.MAZEZ);
} }
@ -41,13 +45,15 @@ public class GameManager {
main.world.render(); main.world.render();
main.world.modelBatch.begin(main.world.cam); main.world.modelBatch.begin(main.world.cam);
for (MazePlayer p : players) { if(players != null) {
p.render(main.world.modelBatch, main.world.environment); for (MazePlayer p : players) {
anyoneWon = false; p.render(main.world.modelBatch, main.world.environment);
if (checkWin(p)) { anyoneWon = false;
anyoneWon = true; if (checkWin(p)) {
gameStarted = false; anyoneWon = true;
break; gameStarted = false;
break;
}
} }
} }
@ -63,21 +69,23 @@ 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
for (MazePlayer p : players) if(pl != null) {
if (!pl.contains(p)) for (MazePlayer p : players)
toDelete.add(p); if (!pl.contains(p))
toDelete.add(p);
//Check if new players have to be added //Check if new players have to be added
for (MazePlayer p : pl) for (MazePlayer p : pl)
if (!players.contains(p)) if (!players.contains(p))
players.add(p); players.add(p);
//Fianlly delete players. A separated step is needed to remove the risk of a ConcurrentModificationException //Fianlly delete players. A separated step is needed to remove the risk of a ConcurrentModificationException
for(MazePlayer p : toDelete) { for(MazePlayer p : toDelete) {
p.dispose(); p.dispose();
players.remove(p); players.remove(p);
}
toDelete.clear();
} }
toDelete.clear();
// destroyPlayers(); // destroyPlayers();
// players.addAll(p); // players.addAll(p);
@ -169,6 +177,8 @@ public class GameManager {
} }
public void dispose() { public void dispose() {
client.stop();
server.stop();
for (MazePlayer p : players) for (MazePlayer p : players)
p.dispose(); p.dispose();
} }

View File

@ -0,0 +1,98 @@
package com.emamaker.amazeing.manager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Net.Protocol;
import com.badlogic.gdx.net.ServerSocket;
import com.badlogic.gdx.net.ServerSocketHints;
import com.badlogic.gdx.net.Socket;
import com.badlogic.gdx.net.SocketHints;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.emamaker.amazeing.AMazeIng;
public class GameServer {
volatile boolean serverRunning = false;
String nextMessage = "oa";
public ServerSocket serverSocket = null;
public int port;
ArrayList<Socket> clientSockets = new ArrayList<Socket>();
Thread serverThread;
public AMazeIng main;
Socket s;
SocketHints socketHints = new SocketHints();
ServerSocketHints serverSocketHint = new ServerSocketHints();
public GameServer(AMazeIng main_) {
main = main_;
}
public void startServer(int port_) {
port = port_;
serverSocketHint.acceptTimeout = 100;
serverThread = new Thread(new Runnable() {
@Override
public void run() {
serverRunning = true;
while (serverRunning) {
if (serverSocket == null) {
serverSocket = Gdx.net.newServerSocket(Protocol.TCP, port, serverSocketHint);
System.out.println("Server started and listening for connections!");
}
try {
Socket socket = serverSocket.accept(null);
if (socket != null && !clientSockets.contains(socket)) {
clientSockets.add(socket);
System.out.println("Accepted new client: " + socket);
}
} catch (GdxRuntimeException se) {
// System.out.println("No new clients connected in the last 100 milliseconds");
}
for (Socket s : clientSockets) {
System.out.println(s);
// Receive messages from the server
try {
BufferedReader buffer = new BufferedReader(new InputStreamReader(s.getInputStream()));
// Read to the next newline (\n) and display that text on labelMessage
System.out.println("Server received message From: " + s + "!\n" + buffer.readLine());
} catch (IOException e) {
// e.printStackTrace();
}
}
}
}
});
serverThread.start();
}
public void startGame() {
// Once the server has started accepting connections from other players, the
// 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
// To spread the map we can just encode in a string the todraw[][] array in
// MazeGenerator, in future run-lenght encoding should be considered
main.gameManager.generateMaze(null);
nextMessage = "Map" + Arrays.deepToString(main.gameManager.mazeGen.todraw);
}
public void stop() {
if (serverSocket != null) {
serverSocket.dispose();
serverSocket = null;
}
serverRunning = false;
}
}

View File

@ -108,7 +108,7 @@ public class MazeGenerator {
currentCell.current = true; currentCell.current = true;
} }
} }
prepareShow(); prepareShow(todraw);
} }
//Setup end point in a random location. At a distance of EP_DIST from every player //Setup end point in a random location. At a distance of EP_DIST from every player
@ -128,7 +128,7 @@ public class MazeGenerator {
main.world.worldManager.setCell(WINX, 0, WINZ, CellId.ID_WOOD); main.world.worldManager.setCell(WINX, 0, WINZ, CellId.ID_WOOD);
} }
public void prepareShow() { public void prepareShow(int[][] todraw_) {
for (int i = 0; i < w; i++) { for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) { for (int j = 0; j < h; j++) {
todraw[i][j] = 1; todraw[i][j] = 1;
@ -143,20 +143,20 @@ public class MazeGenerator {
int y = 2 * j + 1; int y = 2 * j + 1;
// current cell // current cell
todraw[x][y] = 0; todraw_[x][y] = 0;
// up wall // up wall
if (!cellsGrid[i][j].walls[0]) if (!cellsGrid[i][j].walls[0])
todraw[x][y - 1] = 0; todraw_[x][y - 1] = 0;
// down wall // down wall
if (!cellsGrid[i][j].walls[2]) if (!cellsGrid[i][j].walls[2])
todraw[x][y + 1] = 0; todraw_[x][y + 1] = 0;
// left wall // left wall
if (!cellsGrid[i][j].walls[3]) if (!cellsGrid[i][j].walls[3])
todraw[x - 1][y] = 0; todraw_[x - 1][y] = 0;
// right all // right all
if (!cellsGrid[i][j].walls[1]) if (!cellsGrid[i][j].walls[1])
todraw[x + 1][y] = 0; todraw_[x + 1][y] = 0;
} }
} }
@ -164,7 +164,7 @@ public class MazeGenerator {
for (int j = 0; j < h; j++) { for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) { for (int i = 0; i < w; i++) {
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)
// main.world.worldManager.setCell(i, 0, j, CellId.ID_WOOD); // main.world.worldManager.setCell(i, 0, j, CellId.ID_WOOD);

View File

@ -1,13 +1,8 @@
package com.emamaker.amazeing.ui.screens; package com.emamaker.amazeing.ui.screens;
import java.io.IOException;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Net.Protocol;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.Screen; import com.badlogic.gdx.Screen;
import com.badlogic.gdx.net.Socket; import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.net.SocketHints;
import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.Stage;
@ -20,7 +15,7 @@ import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.emamaker.amazeing.ui.UIManager; import com.emamaker.amazeing.ui.UIManager;
public class ServerJoinScreen implements Screen{ public class ServerJoinScreen implements Screen {
Stage stage; Stage stage;
UIManager uiManager; UIManager uiManager;
@ -43,14 +38,15 @@ public class ServerJoinScreen implements Screen{
TextButton backBtn = new TextButton("Main menu", uiManager.skin); TextButton backBtn = new TextButton("Main menu", uiManager.skin);
TextButton connectBtn = new TextButton("Connect to the server!", uiManager.skin); TextButton connectBtn = new TextButton("Connect to the server!", uiManager.skin);
TextButton helpBtn = new TextButton("?", uiManager.skin); TextButton helpBtn = new TextButton("?", uiManager.skin);
final TextArea srvIp = new TextArea("Server IP Address", uiManager.skin); final TextArea srvIp = new TextArea("localhost", uiManager.skin);
final TextArea srvPort = new TextArea("Server Port", uiManager.skin); final TextArea srvPort = new TextArea("9999", uiManager.skin);
// Add actions to the buttons // Add actions to the buttons
backBtn.addListener(new InputListener() { backBtn.addListener(new InputListener() {
@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.gameManager.client.stop();
uiManager.main.setScreen(uiManager.titleScreen); uiManager.main.setScreen(uiManager.titleScreen);
return true; return true;
} }
@ -65,28 +61,20 @@ public class ServerJoinScreen implements Screen{
connectBtn.addListener(new InputListener() { connectBtn.addListener(new InputListener() {
@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) {
/*https://www.gamefromscratch.com/post/2014/03/11/LibGDX-Tutorial-10-Basic-networking.aspx*/ try {
SocketHints socketHints = new SocketHints(); uiManager.main.gameManager.client.start(srvIp.getText(), Integer.valueOf(srvPort.getText()));
// Socket will time our in 4 seconds }catch(Exception e) {
socketHints.connectTimeout = 4000; System.out.println("Please input a valid ip address and port");
//create the socket and connect to the server entered in the text box ( x.x.x.x format ) on port 9021 }
Socket socket = Gdx.net.newClientSocket(Protocol.TCP, srvIp.getText(), Integer.valueOf(srvPort.getText()), socketHints);
try { return true;
// write our entered message to the stream
socket.getOutputStream().write("AO\n".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
return true;
} }
}); });
Table firstRowTable = new Table(); Table firstRowTable = new Table();
firstRowTable.add(backBtn).fillX().expandX().space(cw*0.005f); firstRowTable.add(backBtn).fillX().expandX().space(cw * 0.005f);
firstRowTable.add(instLab).height(50).fillX().expandX().space(cw*0.25f); firstRowTable.add(instLab).height(50).fillX().expandX().space(cw * 0.25f);
firstRowTable.add(helpBtn).width(50).height(50).fillX().expandX().space(cw*0.005f); firstRowTable.add(helpBtn).width(50).height(50).fillX().expandX().space(cw * 0.005f);
firstRowTable.setOrigin(Align.center | Align.top); firstRowTable.setOrigin(Align.center | Align.top);
table.row().colspan(4); table.row().colspan(4);
@ -111,10 +99,10 @@ public class ServerJoinScreen implements Screen{
@Override @Override
public void render(float delta) { public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,0); Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(); stage.act();
stage.draw(); stage.draw();
} }
@Override @Override
@ -126,6 +114,7 @@ public class ServerJoinScreen implements Screen{
public void hide() { public void hide() {
uiManager.main.multiplexer.removeProcessor(stage); uiManager.main.multiplexer.removeProcessor(stage);
} }
@Override @Override
public void pause() { public void pause() {
} }

View File

@ -1,16 +1,8 @@
package com.emamaker.amazeing.ui.screens; package com.emamaker.amazeing.ui.screens;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Net.Protocol;
import com.badlogic.gdx.Screen; import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.net.ServerSocket;
import com.badlogic.gdx.net.ServerSocketHints;
import com.badlogic.gdx.net.Socket;
import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.Stage;
@ -23,7 +15,7 @@ import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.emamaker.amazeing.ui.UIManager; import com.emamaker.amazeing.ui.UIManager;
public class ServerLaunchScreen implements Screen{ public class ServerLaunchScreen implements Screen {
Stage stage; Stage stage;
UIManager uiManager; UIManager uiManager;
@ -43,16 +35,18 @@ public class ServerLaunchScreen implements Screen{
tableContainer.setPosition(0, 0); tableContainer.setPosition(0, 0);
Label instLab = new Label("Enter the port the server should start on", uiManager.skin); Label instLab = new Label("Enter the port the server should start on", uiManager.skin);
TextButton backBtn = new TextButton("Main menu", uiManager.skin); TextButton backBtn = new TextButton("Main menu and quit server", uiManager.skin);
TextButton connectBtn = new TextButton("Launch the server!", uiManager.skin); TextButton connectBtn = new TextButton("Launch the server!", uiManager.skin);
TextButton gameBtn = new TextButton("Launch the game!", uiManager.skin);
TextButton helpBtn = new TextButton("?", uiManager.skin); TextButton helpBtn = new TextButton("?", uiManager.skin);
final TextArea srvPort = new TextArea("Server Port", uiManager.skin); final TextArea srvPort = new TextArea("9999", uiManager.skin);
// Add actions to the buttons // Add actions to the buttons
backBtn.addListener(new InputListener() { backBtn.addListener(new InputListener() {
@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.gameManager.server.stop();
uiManager.main.setScreen(uiManager.titleScreen); uiManager.main.setScreen(uiManager.titleScreen);
return true; return true;
} }
@ -67,49 +61,22 @@ public class ServerLaunchScreen implements Screen{
connectBtn.addListener(new InputListener() { connectBtn.addListener(new InputListener() {
@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) {
/*https://www.gamefromscratch.com/post/2014/03/11/LibGDX-Tutorial-10-Basic-networking.aspx*/ uiManager.main.gameManager.server.startServer(Integer.valueOf(srvPort.getText()));
return true;
// Now we create a thread that will listen for incoming socket connections }
new Thread(new Runnable(){ });
gameBtn.addListener(new InputListener() {
@Override @Override
public void run() { public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
ServerSocketHints serverSocketHint = new ServerSocketHints(); uiManager.main.gameManager.server.startGame();
// 0 means no timeout. Probably not the greatest idea in production! return true;
serverSocketHint.acceptTimeout = 0;
// Create the socket server using TCP protocol and listening on 9021
// Only one app can listen to a port at a time, keep in mind many ports are reserved
// especially in the lower numbers ( like 21, 80, etc )
ServerSocket serverSocket = Gdx.net.newServerSocket(Protocol.TCP, Integer.valueOf(srvPort.getText()), serverSocketHint);
// Loop forever
while(true){
// Create a socket
Socket socket = serverSocket.accept(null);
// Read data from the socket into a BufferedReader
BufferedReader buffer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
try {
// Read to the next newline (\n) and display that text on labelMessage
System.out.println("Server received message!");
System.out.println(buffer.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start(); // And, start the thread running
return true;
} }
}); });
Table firstRowTable = new Table(); Table firstRowTable = new Table();
firstRowTable.add(backBtn).fillX().expandX().space(cw*0.005f); firstRowTable.add(backBtn).fillX().expandX().space(cw * 0.005f);
firstRowTable.add(instLab).height(50).fillX().expandX().space(cw*0.25f); firstRowTable.add(instLab).height(50).fillX().expandX().space(cw * 0.25f);
firstRowTable.add(helpBtn).width(50).height(50).fillX().expandX().space(cw*0.005f); firstRowTable.add(helpBtn).width(50).height(50).fillX().expandX().space(cw * 0.005f);
firstRowTable.setOrigin(Align.center | Align.top); firstRowTable.setOrigin(Align.center | Align.top);
table.row().colspan(4); table.row().colspan(4);
@ -121,6 +88,9 @@ public class ServerLaunchScreen implements Screen{
table.row().colspan(4); table.row().colspan(4);
table.add(connectBtn).fillX().expandX(); table.add(connectBtn).fillX().expandX();
table.row().colspan(4);
table.add(gameBtn).fillX().expandX();
tableContainer.setActor(table); tableContainer.setActor(table);
stage.addActor(tableContainer); stage.addActor(tableContainer);
} }
@ -132,10 +102,10 @@ public class ServerLaunchScreen implements Screen{
@Override @Override
public void render(float delta) { public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,0); Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(); stage.act();
stage.draw(); stage.draw();
} }
@Override @Override
@ -147,6 +117,7 @@ public class ServerLaunchScreen implements Screen{
public void hide() { public void hide() {
uiManager.main.multiplexer.removeProcessor(stage); uiManager.main.multiplexer.removeProcessor(stage);
} }
@Override @Override
public void pause() { public void pause() {
} }