I am working on multiplayer game, which is created in a GameMaker studio. I have already created a server and a client in game maker, which is working perfectly fine, but game maker server can't be ran on any virtual machine, since it has to use DirectX.
So I've wanted to rewrite the server in Java, which would expand those options for me a lot. I've watched many of tutorials and I've only seen that people send "strings" as a messages, which I would like to replace with bytes. Because in the server I have created in GameMaker, I use message id, to identify where each message should refer to. Those are the lines in which I read it:
buffer_seek(buffer, buffer_seek_start, 0);
var mid = buffer_read(buffer, buffer_u8);
switch(mid) {
case 0:
But in Java there is only an inputstream as far as I have seen. How would I be able to split that message like it is in a code down bellow: (GameMaker's networking async event (of the server))
case network_type_data:
var buffer = ds_map_find_value(async_load, "buffer");
var socket = ds_map_find_value(async_load, "id");
buffer_seek(buffer, buffer_seek_start, 0);
var mid = buffer_read(buffer, buffer_u8);
switch(mid) {
case 0:
//let's updated the first information we can get whether the user is registering or loging in
//Reads what username was assigned to player
var username = buffer_read(buffer, buffer_string);
//Updates information of players
UpdatePlayerInfo("name", username, socket);
SendRoomList(1, socket);
break;
case 1: //player wants to create a server
//find the name of the player
show_debug_message("a player created a room");
if(Room_exists(socket) == false and PlayerInRoom(socket) == false) {
var Room = CreateRoom(socket, 2);
JoinRoom(socket, Room);
SendRoomList(1, socket);
}
break;
case 2: //player wants to join the server
var desired_room = buffer_read(buffer, buffer_u8);
if(PlayerInRoom(socket) == false) {
JoinRoom(socket, desired_room);
}
break;
}
}
Java's ByteBuffer is a good start to be able to get items other than String from a simple stream. Essentially, you grab a chunk of bytes from the TCP input stream into a ByteBuffer instance and you can call getInt(), getDouble(), and other similar methods to get primitive types out of it.
Here's some usages of it arranged similarly to your script in the question.
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class JavaIo {
// number of bytes in a user name
private static final int SIZE_OF_USER_NAME = 30;
// number of bytes in the internal buffer
private static final int BUFFER_SIZE = 1024;
public void workWithConnection() {
final int portNumber = 12345; // TODO: read this from config file or command line arguments instead
try (
ServerSocket server = new ServerSocket(portNumber);
Socket connection = server.accept();
SocketChannel channel = connection.getChannel();
) {
final ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
channel.read(buffer); // fill buffer from the input stream
// since your buffer in GameMaker is unsigned, let's prevent all that signed to unsigned nonsense by doing a
// bitmask
final int mid = buffer.get() & 0x000000FF;
switch(mid) {
case 0:
// grab some bytes from the buffer and change them into a String
final byte[] usernameBytes = new byte[SIZE_OF_USER_NAME];
buffer.get(usernameBytes);
final String username = new String( usernameBytes, Charset.forName(StandardCharsets.UTF_8.name()));
// ...
break;
case 1:
// grab 4 bytes from the buffer and change it into an integer
final int roomId = buffer.getInt();
// ...
break;
default:
// ...
}
} catch(IOException ioe) {
// TODO: handle exception
}
}
}
References:
Convert a byte array to integer in java and vice versa
http://www.ibm.com/developerworks/java/tutorials/j-nio/j-nio.html