ZeusServer 0.0.1
Initial Commit to github Multithreaded clientthread map generation with threadexecutorpool
This commit is contained in:
commit
4794af1895
12
ZeusServer.iml
Normal file
12
ZeusServer.iml
Normal file
@ -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>
|
3
src/main/java/META-INF/MANIFEST.MF
Normal file
3
src/main/java/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: ZeusServer.Server.Main
|
||||
|
51
src/main/java/ZeusServer/Helpers/Bytes.java
Normal file
51
src/main/java/ZeusServer/Helpers/Bytes.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
73
src/main/java/ZeusServer/Helpers/ChunkSerializer.java
Normal file
73
src/main/java/ZeusServer/Helpers/ChunkSerializer.java
Normal file
@ -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());
|
||||
}
|
||||
}
|
2140
src/main/java/ZeusServer/Helpers/OpenSimplexNoise.java
Executable file
2140
src/main/java/ZeusServer/Helpers/OpenSimplexNoise.java
Executable file
File diff suppressed because it is too large
Load Diff
9
src/main/java/ZeusServer/Helpers/PacketData.java
Normal file
9
src/main/java/ZeusServer/Helpers/PacketData.java
Normal file
@ -0,0 +1,9 @@
|
||||
package ZeusServer.Helpers;
|
||||
|
||||
import ZeusServer.Helpers.PacketType;
|
||||
|
||||
public class PacketData {
|
||||
public long time;
|
||||
public PacketType type;
|
||||
public byte[] data;
|
||||
}
|
7
src/main/java/ZeusServer/Helpers/PacketType.java
Normal file
7
src/main/java/ZeusServer/Helpers/PacketType.java
Normal file
@ -0,0 +1,7 @@
|
||||
package ZeusServer.Helpers;
|
||||
|
||||
public enum PacketType {
|
||||
DEBUG,
|
||||
REQUEST_CHUNK,
|
||||
BLOCK_CHUNK,
|
||||
}
|
95
src/main/java/ZeusServer/Helpers/RLE.java
Normal file
95
src/main/java/ZeusServer/Helpers/RLE.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
29
src/main/java/ZeusServer/Helpers/VecUtils.java
Normal file
29
src/main/java/ZeusServer/Helpers/VecUtils.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
150
src/main/java/ZeusServer/Networking/ClientThread.java
Normal file
150
src/main/java/ZeusServer/Networking/ClientThread.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
148
src/main/java/ZeusServer/Networking/Pacman.java
Normal file
148
src/main/java/ZeusServer/Networking/Pacman.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
24
src/main/java/ZeusServer/Server/GameServer.java
Normal file
24
src/main/java/ZeusServer/Server/GameServer.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
13
src/main/java/ZeusServer/Server/Main.java
Normal file
13
src/main/java/ZeusServer/Server/Main.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
90
src/main/java/ZeusServer/Server/MapGen.java
Normal file
90
src/main/java/ZeusServer/Server/MapGen.java
Normal file
@ -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…
x
Reference in New Issue
Block a user