ZeusServer 0.0.1
Initial Commit to github Multithreaded clientthread map generation with threadexecutorpoolmaster
commit
4794af1895
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="Helpers" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
|
@ -0,0 +1,3 @@
|
||||||
|
Manifest-Version: 1.0
|
||||||
|
Main-Class: ZeusServer.Server.Main
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package ZeusServer.Helpers;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class Bytes {
|
||||||
|
|
||||||
|
// Long
|
||||||
|
|
||||||
|
public static byte[] longToBytes(long x) {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
|
||||||
|
buffer.putLong(x);
|
||||||
|
return buffer.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long bytesToLong(byte[] bytes) {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
|
||||||
|
buffer.put(bytes);
|
||||||
|
buffer.flip();
|
||||||
|
return buffer.getLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Integer
|
||||||
|
|
||||||
|
public static byte[] intToBytes(int x) {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
|
||||||
|
buffer.putInt(x);
|
||||||
|
return buffer.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int bytesToInt(byte[] bytes) {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
|
||||||
|
buffer.put(bytes);
|
||||||
|
buffer.flip();
|
||||||
|
return buffer.getInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short
|
||||||
|
|
||||||
|
public static byte[] shortToBytes(short x) {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(Short.BYTES);
|
||||||
|
buffer.putShort(x);
|
||||||
|
return buffer.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static short bytesToShort(byte[] bytes) {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(Short.BYTES);
|
||||||
|
buffer.put(bytes);
|
||||||
|
buffer.flip();
|
||||||
|
return buffer.getShort();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package ZeusServer.Helpers;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
|
import static ZeusServer.Helpers.Bytes.*;
|
||||||
|
|
||||||
|
public class ChunkSerializer {
|
||||||
|
|
||||||
|
public static byte[] encodeChunk(short[] chunk, ArrayList<short[]> sides) {
|
||||||
|
ArrayList<Byte> list = new ArrayList<>();
|
||||||
|
byte[] rleArray = RLE.encode(chunk);
|
||||||
|
byte[] size = intToBytes(rleArray.length);
|
||||||
|
list.add(size[0]);
|
||||||
|
list.add(size[1]);
|
||||||
|
list.add(size[2]);
|
||||||
|
list.add(size[3]);
|
||||||
|
|
||||||
|
ByteArrayInputStream rleStream = new ByteArrayInputStream(rleArray);
|
||||||
|
while (rleStream.available() > 0) list.add((byte)rleStream.read());
|
||||||
|
|
||||||
|
for (short[] shorts : sides) {
|
||||||
|
addAdjacent(list, shorts);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] array = new byte[list.size()];
|
||||||
|
for (var i = 0; i < list.size(); i++) {
|
||||||
|
array[i] = list.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayOutputStream bos;
|
||||||
|
try {
|
||||||
|
bos = new ByteArrayOutputStream(array.length);
|
||||||
|
GZIPOutputStream gzip = new GZIPOutputStream(bos);
|
||||||
|
gzip.write(array);
|
||||||
|
gzip.close();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] compressed = bos.toByteArray();
|
||||||
|
|
||||||
|
try {
|
||||||
|
bos.close();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addAdjacent(ArrayList<Byte> list, short[] adj) {
|
||||||
|
byte[] rleArray = RLE.encode(adj);
|
||||||
|
byte[] size = intToBytes(rleArray.length);
|
||||||
|
list.add(size[0]);
|
||||||
|
list.add(size[1]);
|
||||||
|
list.add(size[2]);
|
||||||
|
list.add(size[3]);
|
||||||
|
|
||||||
|
ByteArrayInputStream rleStream = new ByteArrayInputStream(rleArray);
|
||||||
|
while (rleStream.available() > 0) list.add((byte)rleStream.read());
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,9 @@
|
||||||
|
package ZeusServer.Helpers;
|
||||||
|
|
||||||
|
import ZeusServer.Helpers.PacketType;
|
||||||
|
|
||||||
|
public class PacketData {
|
||||||
|
public long time;
|
||||||
|
public PacketType type;
|
||||||
|
public byte[] data;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ZeusServer.Helpers;
|
||||||
|
|
||||||
|
public enum PacketType {
|
||||||
|
DEBUG,
|
||||||
|
REQUEST_CHUNK,
|
||||||
|
BLOCK_CHUNK,
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package ZeusServer.Helpers;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class RLE {
|
||||||
|
public static byte[] encode(boolean[] booleans) {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
boolean type = booleans[0];
|
||||||
|
short count = 0;
|
||||||
|
for (boolean bool : booleans) {
|
||||||
|
if (bool != type) {
|
||||||
|
bos.write(new byte[]{(byte) (count & 0xff), (byte) ((count >> 8) & 0xff)});
|
||||||
|
bos.write(new byte[]{(byte) (type ? 1 : 0)});
|
||||||
|
type = bool;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
bos.write(new byte[]{(byte) (count & 0xff), (byte) ((count >> 8) & 0xff)});
|
||||||
|
bos.write(new byte[]{(byte) (type ? 1 : 0)});
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] encode(short[] shorts) {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
short type = shorts[0];
|
||||||
|
short count = 0;
|
||||||
|
for (short val: shorts) {
|
||||||
|
if (val != type) {
|
||||||
|
bos.write(new byte[]{(byte) (count & 0xff), (byte) ((count >> 8) & 0xff)});
|
||||||
|
bos.write(new byte[]{(byte) (type & 0xff), (byte) ((type >> 8) & 0xff)});
|
||||||
|
type = val;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
bos.write(new byte[]{(byte) (count & 0xff), (byte) ((count >> 8) & 0xff)});
|
||||||
|
bos.write(new byte[]{(byte) (type & 0xff), (byte) ((type >> 8) & 0xff)});
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static short[] decodeShorts(byte[] bytes) {
|
||||||
|
ArrayList<Short> shorts = new ArrayList<>();
|
||||||
|
|
||||||
|
for (var i = 0; i < bytes.length; i+=4) {
|
||||||
|
short len = (short)(((bytes[i+1] & 0xFF) << 8) | (bytes[i] & 0xFF));
|
||||||
|
short val = (short)(((bytes[i+3] & 0xFF) << 8) | (bytes[i+2] & 0xFF));
|
||||||
|
for (var j = 0; j < len; j++) {
|
||||||
|
shorts.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short[] arr = new short[shorts.size()];
|
||||||
|
|
||||||
|
for (var i = 0; i < shorts.size(); i++) {
|
||||||
|
arr[i] = shorts.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean[] decodeBools(byte[] bytes) {
|
||||||
|
ArrayList<Boolean> booleans = new ArrayList<>();
|
||||||
|
|
||||||
|
for (var i = 0; i < bytes.length; i+=3) {
|
||||||
|
short len = (short)(((bytes[i+1] & 0xFF) << 8) | (bytes[i] & 0xFF));
|
||||||
|
boolean val = (bytes[i+2] & 0xFF)==1;
|
||||||
|
for (var j = 0; j < len; j++) {
|
||||||
|
booleans.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean[] arr = new boolean[booleans.size()];
|
||||||
|
|
||||||
|
for (var i = 0; i < booleans.size(); i++) {
|
||||||
|
arr[i] = booleans.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package ZeusServer.Helpers;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
public class VecUtils {
|
||||||
|
public static Vector3i stringToVector(String in) {
|
||||||
|
String[] coords = in.split(",");
|
||||||
|
if (coords.length != 3) return null;
|
||||||
|
Vector3i pos = new Vector3i();
|
||||||
|
try {
|
||||||
|
pos.x = Integer.valueOf(coords[0]);
|
||||||
|
pos.y = Integer.valueOf(coords[1]);
|
||||||
|
pos.z = Integer.valueOf(coords[2]);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String vectorToString(Vector3i in) {
|
||||||
|
return vectorToString(in.x, in.y, in.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String vectorToString(int x, int y, int z) {
|
||||||
|
return x + "," + y + "," + z;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
package ZeusServer.Networking;
|
||||||
|
|
||||||
|
import ZeusServer.Helpers.*;
|
||||||
|
import ZeusServer.Server.MapGen;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.sql.SQLOutput;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static ZeusServer.Server.MapGen.CHUNK_SIZE;
|
||||||
|
|
||||||
|
public class ClientThread extends Thread implements Runnable {
|
||||||
|
private Socket socket;
|
||||||
|
private Pacman pacman;
|
||||||
|
private boolean alive;
|
||||||
|
private MapGen mapGen;
|
||||||
|
|
||||||
|
private ThreadPoolExecutor mapGenPool;
|
||||||
|
private ArrayList<Future> mapGenFutures;
|
||||||
|
|
||||||
|
public ClientThread(Socket socket) {
|
||||||
|
this.socket = socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
this.pacman = new Pacman(socket);
|
||||||
|
mapGen = new MapGen();
|
||||||
|
pacman.start();
|
||||||
|
alive = true;
|
||||||
|
|
||||||
|
mapGenPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(32);
|
||||||
|
mapGenPool.setMaximumPoolSize(64);
|
||||||
|
mapGenPool.setKeepAliveTime(32, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
mapGenFutures = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update() {
|
||||||
|
pacman.getPackets((PacketData in) -> {
|
||||||
|
switch (in.type) {
|
||||||
|
case DEBUG:
|
||||||
|
System.out.println(new String(in.data, StandardCharsets.ISO_8859_1));
|
||||||
|
break;
|
||||||
|
case REQUEST_CHUNK:
|
||||||
|
deferredRenderChunk(in);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.out.println("Recieved packet of type " + in.type + "and we can't to deal with it!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// pacman.sendPacket(PacketType.DEBUG, "Server to client: Hi! Time is " + System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deferredRenderChunk(PacketData in) {
|
||||||
|
mapGenFutures.add(mapGenPool.submit(() -> {
|
||||||
|
Vector3i position = VecUtils.stringToVector(new String(in.data, StandardCharsets.ISO_8859_1));
|
||||||
|
if (position == null) return;
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
s.append(VecUtils.vectorToString(position));
|
||||||
|
s.append("|");
|
||||||
|
|
||||||
|
System.out.println("Generating chunk at position " + position);
|
||||||
|
|
||||||
|
var bytes = ChunkSerializer.encodeChunk(generateChunk(position), generateSides(position));
|
||||||
|
if (bytes == null) return;
|
||||||
|
|
||||||
|
s.append(new String(bytes, StandardCharsets.ISO_8859_1));
|
||||||
|
|
||||||
|
pacman.sendPacket(PacketType.BLOCK_CHUNK, s.toString());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<short[]> generateSides(Vector3i pos) {
|
||||||
|
ArrayList<short[]> sides = new ArrayList<>();
|
||||||
|
|
||||||
|
var array = new short[256];
|
||||||
|
for (var i = 0; i < 256; i++) {
|
||||||
|
array[i] = mapGen.getBlock(pos.x*CHUNK_SIZE + 16, pos.y*CHUNK_SIZE + i/16, pos.z*CHUNK_SIZE + i%16);
|
||||||
|
}
|
||||||
|
sides.add(array);
|
||||||
|
|
||||||
|
array = new short[256];
|
||||||
|
for (var i = 0; i < 256; i++) {
|
||||||
|
array[i] = mapGen.getBlock(pos.x*CHUNK_SIZE - 1, pos.y*CHUNK_SIZE + i/16, pos.z*CHUNK_SIZE + i%16);
|
||||||
|
}
|
||||||
|
sides.add(array);
|
||||||
|
|
||||||
|
array = new short[256];
|
||||||
|
for (var i = 0; i < 256; i++) {
|
||||||
|
array[i] = mapGen.getBlock(pos.x*CHUNK_SIZE + i/16, pos.y*CHUNK_SIZE + 16, pos.z*CHUNK_SIZE + i%16);
|
||||||
|
}
|
||||||
|
sides.add(array);
|
||||||
|
|
||||||
|
array = new short[256];
|
||||||
|
for (var i = 0; i < 256; i++) {
|
||||||
|
array[i] = mapGen.getBlock(pos.x*CHUNK_SIZE + i/16, pos.y*CHUNK_SIZE - 1, pos.z*CHUNK_SIZE + i%16);
|
||||||
|
}
|
||||||
|
sides.add(array);
|
||||||
|
|
||||||
|
array = new short[256];
|
||||||
|
for (var i = 0; i < 256; i++) {
|
||||||
|
array[i] = mapGen.getBlock(pos.x*CHUNK_SIZE + i%16, pos.y*CHUNK_SIZE + i/16, pos.z*CHUNK_SIZE + 16);
|
||||||
|
}
|
||||||
|
sides.add(array);
|
||||||
|
|
||||||
|
array = new short[256];
|
||||||
|
for (var i = 0; i < 256; i++) {
|
||||||
|
array[i] = mapGen.getBlock(pos.x*CHUNK_SIZE + i%16, pos.y*CHUNK_SIZE + i/16, pos.z*CHUNK_SIZE - 1);
|
||||||
|
}
|
||||||
|
sides.add(array);
|
||||||
|
|
||||||
|
return sides;
|
||||||
|
}
|
||||||
|
|
||||||
|
private short[] generateChunk(Vector3i pos) {
|
||||||
|
var chunk = new short[4096];
|
||||||
|
|
||||||
|
for (var i = 0; i < CHUNK_SIZE; i++) {
|
||||||
|
for (var j = 0; j < CHUNK_SIZE; j++) {
|
||||||
|
for (var k = 0; k < CHUNK_SIZE; k++) {
|
||||||
|
short fill = mapGen.getBlock(i + pos.x*CHUNK_SIZE, j + pos.y*CHUNK_SIZE, k + pos.z*CHUNK_SIZE);
|
||||||
|
chunk[i + CHUNK_SIZE * (j + CHUNK_SIZE * k)] = fill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
init();
|
||||||
|
|
||||||
|
while (alive) {
|
||||||
|
update();
|
||||||
|
try {
|
||||||
|
Thread.sleep(16);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
package ZeusServer.Networking;
|
||||||
|
|
||||||
|
import ZeusServer.Helpers.Bytes;
|
||||||
|
import ZeusServer.Helpers.PacketData;
|
||||||
|
import ZeusServer.Helpers.PacketType;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class Pacman extends Thread implements Runnable {
|
||||||
|
private final int MAX_OUT_SIZE = 4096;
|
||||||
|
private final int OUT_INTERVAL = 32;
|
||||||
|
|
||||||
|
private Socket socket;
|
||||||
|
private boolean closed = false;
|
||||||
|
|
||||||
|
private DataInputStream in;
|
||||||
|
private DataOutputStream out;
|
||||||
|
|
||||||
|
private ArrayList<byte[]> pendingOutPackets;
|
||||||
|
private BlockingQueue<byte[]> pendingInPackets;
|
||||||
|
|
||||||
|
private ArrayList<PacketData> clientPackets;
|
||||||
|
|
||||||
|
Pacman(Socket socket) {
|
||||||
|
this.socket = socket;
|
||||||
|
|
||||||
|
pendingOutPackets = new ArrayList<>();
|
||||||
|
pendingInPackets = new LinkedBlockingQueue<>();
|
||||||
|
clientPackets = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
in = new DataInputStream(socket.getInputStream());
|
||||||
|
out = new DataOutputStream(socket.getOutputStream());
|
||||||
|
|
||||||
|
//Background Packet Resolver
|
||||||
|
Thread thread = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
while (!closed) {
|
||||||
|
int length = in.readInt();
|
||||||
|
byte[] data = new byte[length];
|
||||||
|
in.readFully(data, 0, length);
|
||||||
|
pendingInPackets.put(data);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
}, "BackgroundPacketResolver");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
thread.start();
|
||||||
|
|
||||||
|
loop();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loop() throws Exception {
|
||||||
|
while (!closed) {
|
||||||
|
update();
|
||||||
|
Thread.sleep(OUT_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update() throws Exception {
|
||||||
|
synchronized (this) {
|
||||||
|
//noinspection StatementWithEmptyBody
|
||||||
|
while (decodePacket()) {}
|
||||||
|
}
|
||||||
|
sendPendingOutPackets();
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void getPackets(Consumer<PacketData> consumer) {
|
||||||
|
for (PacketData packet : clientPackets) {
|
||||||
|
consumer.accept(packet);
|
||||||
|
}
|
||||||
|
clientPackets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean decodePacket() throws InterruptedException {
|
||||||
|
byte[] packet = (closed || pendingInPackets.isEmpty()) ? null : pendingInPackets.poll(1L, TimeUnit.MILLISECONDS);
|
||||||
|
if (packet == null) return false;
|
||||||
|
|
||||||
|
PacketData p = new PacketData();
|
||||||
|
|
||||||
|
p.type = PacketType.values()[Bytes.bytesToInt(Arrays.copyOfRange(packet, 0, 4))];
|
||||||
|
p.time = Bytes.bytesToLong(Arrays.copyOfRange(packet, 4, 12));
|
||||||
|
p.data = Arrays.copyOfRange(packet, 12, packet.length);
|
||||||
|
|
||||||
|
clientPackets.add(p);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendPendingOutPackets() throws IOException {
|
||||||
|
int size = 0;
|
||||||
|
byte[] packet;
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
while (pendingOutPackets.size() > 0) {
|
||||||
|
packet = pendingOutPackets.get(0);
|
||||||
|
size += packet.length;
|
||||||
|
|
||||||
|
out.writeInt(packet.length);
|
||||||
|
out.write(packet);
|
||||||
|
|
||||||
|
pendingOutPackets.remove(0);
|
||||||
|
|
||||||
|
if (size >= MAX_OUT_SIZE) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendPacket(PacketType p, String data) {
|
||||||
|
sendPacket(p, data.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendPacket(PacketType p, byte[] data) {
|
||||||
|
byte[] out = new byte[data.length + 12];
|
||||||
|
System.arraycopy(Bytes.intToBytes(p.ordinal()), 0, out, 0, 4);
|
||||||
|
System.arraycopy(Bytes.longToBytes(0), 0, out, 4, 8);
|
||||||
|
System.arraycopy(data, 0, out, 12, data.length);
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
pendingOutPackets.add(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kill() {
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package ZeusServer.Server;
|
||||||
|
|
||||||
|
import ZeusServer.Networking.ClientThread;
|
||||||
|
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
class GameServer {
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
GameServer(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() throws Exception {
|
||||||
|
ServerSocket socket = new ServerSocket(this.port);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Socket clientSocket = socket.accept();
|
||||||
|
ClientThread t = new ClientThread(clientSocket);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package ZeusServer.Server;
|
||||||
|
|
||||||
|
import ZeusServer.Server.GameServer;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
if (args.length <= 0) throw new Exception("No Port Specified! Port should be the first argument.");
|
||||||
|
|
||||||
|
int port = Integer.parseInt(args[0]);
|
||||||
|
GameServer server = new GameServer(port);
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package ZeusServer.Server;
|
||||||
|
|
||||||
|
import ZeusServer.Helpers.OpenSimplexNoise;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import static java.lang.Math.floorMod;
|
||||||
|
|
||||||
|
public class MapGen {
|
||||||
|
public static final int CHUNK_SIZE = 16;
|
||||||
|
|
||||||
|
OpenSimplexNoise terrainNoise;
|
||||||
|
OpenSimplexNoise treeNoise;
|
||||||
|
private long seed;
|
||||||
|
|
||||||
|
public MapGen() {
|
||||||
|
// seed = Math.round(Math.random()*1000000);
|
||||||
|
seed = 0;
|
||||||
|
terrainNoise = new OpenSimplexNoise(seed);
|
||||||
|
treeNoise = new OpenSimplexNoise(seed/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getBlock(int x, int y, int z) {
|
||||||
|
int xx = (int)Math.floor((float)x/8);
|
||||||
|
int zz = (int)Math.floor((float)z/8);
|
||||||
|
|
||||||
|
float v = ((float)x/8) - xx;
|
||||||
|
float u = ((float)z/8) - zz;
|
||||||
|
|
||||||
|
float point00 = getNoisePoint(xx*8, zz*8);
|
||||||
|
float point10 = getNoisePoint((xx+1)*8, zz*8);
|
||||||
|
float point01 = getNoisePoint(xx*8, (zz+1)*8);
|
||||||
|
float point11 = getNoisePoint((xx+1)*8, (zz+1)*8);
|
||||||
|
|
||||||
|
float x1 = lerp(point00, point01, u);
|
||||||
|
float x2 = lerp(point10, point11, u);
|
||||||
|
|
||||||
|
float average = lerp(x1, x2, v);
|
||||||
|
|
||||||
|
if (y + 1 - average < -2) return 3;
|
||||||
|
if (y + 1 - average < 0) return 2;
|
||||||
|
if (y - average < 0) return 1;
|
||||||
|
|
||||||
|
if (y - average < 5)
|
||||||
|
if (Math.pow(treeNoise.eval(x, z), 2) > 0.6) return 11;
|
||||||
|
|
||||||
|
if (y - average < 5 && y - average > 3) {
|
||||||
|
for (var i = -2; i < 3; i++) {
|
||||||
|
for (var j = -2; j < 3; j++) {
|
||||||
|
if (i != 0 || j != 0) {
|
||||||
|
if (Math.pow(treeNoise.eval(x + i, z + j), 2) > 0.6) return 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y - average < 7 && y - average > 5) {
|
||||||
|
for (var i = -1; i < 2; i++) {
|
||||||
|
for (var j = -1; j < 2; j++) {
|
||||||
|
if (Math.pow(treeNoise.eval(x + i, z + j), 2) > 0.6) return 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y - 1 - average < 0) {
|
||||||
|
if (Math.random() > 0.2) {
|
||||||
|
return (short)(4 + Math.round(Math.random() * 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getBlock(Vector3i pos) {
|
||||||
|
return getBlock(pos.x, pos.y, pos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int multiplyPerlin(int x, int z, int horz, int vert) {
|
||||||
|
return (int)(terrainNoise.eval((float)x / horz, (float)z / horz) * vert);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float lerp(float s, float e, float t) {
|
||||||
|
return s + (e - s) * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getNoisePoint(int x, int y) {
|
||||||
|
double value = multiplyPerlin(x, y, 600, 100) * 0.6;
|
||||||
|
value += multiplyPerlin(x, y, 100, 50) * 0.6;
|
||||||
|
value += multiplyPerlin(x, y, 50, 25) * 0.6;
|
||||||
|
return (float)value;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue