mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-27 19:47:44 +01:00
Fixes & added data serializer
This commit is contained in:
parent
b517c1091e
commit
879f9e7c42
@ -18,5 +18,6 @@ dependencies {
|
|||||||
implementation 'com.github.luben:zstd-jni:1.4.3-1'
|
implementation 'com.github.luben:zstd-jni:1.4.3-1'
|
||||||
implementation 'com.esotericsoftware:reflectasm:1.11.9'
|
implementation 'com.esotericsoftware:reflectasm:1.11.9'
|
||||||
implementation 'com.github.LynnOwens:starlite:9971b899f7'
|
implementation 'com.github.LynnOwens:starlite:9971b899f7'
|
||||||
implementation 'com.github.jhg023:SimpleNet:1.5.0'
|
//implementation 'com.github.jhg023:SimpleNet:1.5.0'
|
||||||
|
implementation 'com.github.jhg023:SimpleNet:97dbc4951e'
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,9 @@ public class Main {
|
|||||||
|
|
||||||
// Thread number
|
// Thread number
|
||||||
public static final int THREAD_COUNT_PACKET_WRITER = 2;
|
public static final int THREAD_COUNT_PACKET_WRITER = 2;
|
||||||
public static final int THREAD_COUNT_CHUNK_IO = 2;
|
public static final int THREAD_COUNT_IO = 2;
|
||||||
public static final int THREAD_COUNT_CHUNK_BATCH = 2;
|
public static final int THREAD_COUNT_CHUNK_BATCH = 2;
|
||||||
|
public static final int THREAD_COUNT_BLOCK_BATCH = 2;
|
||||||
public static final int THREAD_COUNT_ENTITIES = 2;
|
public static final int THREAD_COUNT_ENTITIES = 2;
|
||||||
public static final int THREAD_COUNT_PLAYERS_ENTITIES = 2;
|
public static final int THREAD_COUNT_PLAYERS_ENTITIES = 2;
|
||||||
|
|
||||||
|
@ -1,13 +1,24 @@
|
|||||||
package fr.themode.minestom.data;
|
package fr.themode.minestom.data;
|
||||||
|
|
||||||
|
import fr.themode.minestom.Main;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class Data {
|
public class Data {
|
||||||
|
|
||||||
private ConcurrentHashMap<String, Object> data = new ConcurrentHashMap();
|
private DataManager dataManager = Main.getDataManager();
|
||||||
private ConcurrentHashMap<String, DataType> dataType = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public <T> void set(String key, T value, DataType<T> type) {
|
private ConcurrentHashMap<String, Object> data = new ConcurrentHashMap();
|
||||||
|
private ConcurrentHashMap<String, Class> dataType = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public <T> void set(String key, T value, Class<T> type) {
|
||||||
|
if (dataManager.getDataType(type) == null) {
|
||||||
|
throw new UnsupportedOperationException("Type " + type.getName() + " hasn't been registered in DataManager#registerType");
|
||||||
|
}
|
||||||
this.data.put(key, value);
|
this.data.put(key, value);
|
||||||
this.dataType.put(key, type);
|
this.dataType.put(key, type);
|
||||||
}
|
}
|
||||||
@ -20,6 +31,32 @@ public class Data {
|
|||||||
return (T) data.getOrDefault(key, defaultValue);
|
return (T) data.getOrDefault(key, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO serialization
|
public byte[] getSerializedData() throws IOException {
|
||||||
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream dos = new DataOutputStream(output);
|
||||||
|
|
||||||
|
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Class type = dataType.get(key);
|
||||||
|
Object value = entry.getValue();
|
||||||
|
DataType dataType = Main.getDataManager().getDataType(type);
|
||||||
|
|
||||||
|
byte[] encodedType = type.getName().getBytes(); // Data type
|
||||||
|
dos.writeShort(encodedType.length);
|
||||||
|
dos.write(encodedType);
|
||||||
|
|
||||||
|
byte[] encodedName = key.getBytes(); // Data name
|
||||||
|
dos.writeShort(encodedName.length);
|
||||||
|
dos.write(encodedName);
|
||||||
|
|
||||||
|
byte[] encodedValue = dataType.encode(value); // Data
|
||||||
|
dos.writeInt(encodedValue.length);
|
||||||
|
dos.write(encodedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
dos.writeShort(0xff); // End of data object
|
||||||
|
|
||||||
|
return output.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,113 @@
|
|||||||
package fr.themode.minestom.data;
|
package fr.themode.minestom.data;
|
||||||
|
|
||||||
|
import fr.themode.minestom.Main;
|
||||||
|
import fr.themode.minestom.io.IOManager;
|
||||||
|
import fr.themode.minestom.utils.CompressionUtils;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public interface DataContainer {
|
public interface DataContainer {
|
||||||
|
|
||||||
Data getData();
|
Data getData();
|
||||||
|
|
||||||
void setData(Data data);
|
void setData(Data data);
|
||||||
|
|
||||||
|
default void saveData(File file, Runnable callback) {
|
||||||
|
IOManager.submit(() -> {
|
||||||
|
Data data = getData();
|
||||||
|
if (data == null) {
|
||||||
|
// TODO error trying to save null data
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
|
byte[] serializedData = data.getSerializedData();
|
||||||
|
fos.write(CompressionUtils.getCompressedData(serializedData));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (callback != null)
|
||||||
|
callback.run();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
default void saveData(File file) {
|
||||||
|
saveData(file, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void loadData(File file, Consumer<Data> callback) {
|
||||||
|
IOManager.submit(() -> {
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
setData(new Data());
|
||||||
|
if (callback != null)
|
||||||
|
callback.accept(getData());
|
||||||
|
System.out.println("FILE DATA NOT FOUND, NEW DATA OBJECT CREATED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] array;
|
||||||
|
try {
|
||||||
|
array = Files.readAllBytes(file.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace(); // Unknown error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(CompressionUtils.getDecompressedData(array)));
|
||||||
|
|
||||||
|
Data data = new Data();
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
short typeLength = stream.readShort();
|
||||||
|
|
||||||
|
if (typeLength == 0xff) {
|
||||||
|
// End of data
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] typeCache = new byte[typeLength];
|
||||||
|
for (int i = 0; i < typeLength; i++) {
|
||||||
|
typeCache[i] = stream.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
short nameLength = stream.readShort();
|
||||||
|
byte[] nameCache = new byte[nameLength];
|
||||||
|
for (int i = 0; i < nameLength; i++) {
|
||||||
|
nameCache[i] = stream.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
int valueLength = stream.readInt();
|
||||||
|
byte[] valueCache = new byte[valueLength];
|
||||||
|
for (int i = 0; i < valueLength; i++) {
|
||||||
|
valueCache[i] = stream.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
Class type = Class.forName(new String(typeCache));
|
||||||
|
String name = new String(nameCache);
|
||||||
|
Object value = Main.getDataManager().getDataType(type).decode(valueCache);
|
||||||
|
|
||||||
|
data.set(name, value, type);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
setData(data);
|
||||||
|
if (callback != null)
|
||||||
|
callback.accept(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
default void loadData(File file) {
|
||||||
|
loadData(file, null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
29
src/main/java/fr/themode/minestom/data/DataManager.java
Normal file
29
src/main/java/fr/themode/minestom/data/DataManager.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package fr.themode.minestom.data;
|
||||||
|
|
||||||
|
import fr.themode.minestom.data.type.IntegerData;
|
||||||
|
import fr.themode.minestom.utils.PrimitiveConversion;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DataManager {
|
||||||
|
|
||||||
|
private Map<Class, DataType> dataTypeMap = new HashMap<>();
|
||||||
|
|
||||||
|
{
|
||||||
|
registerType(Integer.class, new IntegerData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void registerType(Class<T> clazz, DataType<T> dataType) {
|
||||||
|
clazz = PrimitiveConversion.getObjectClass(clazz);
|
||||||
|
if (dataTypeMap.containsKey(clazz))
|
||||||
|
throw new UnsupportedOperationException("Type " + clazz.getName() + " has already been registed");
|
||||||
|
|
||||||
|
this.dataTypeMap.put(clazz, dataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> DataType<T> getDataType(Class<T> clazz) {
|
||||||
|
return dataTypeMap.get(PrimitiveConversion.getObjectClass(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,18 +5,18 @@ import fr.themode.minestom.event.PlayerLoginEvent;
|
|||||||
import fr.themode.minestom.instance.Chunk;
|
import fr.themode.minestom.instance.Chunk;
|
||||||
import fr.themode.minestom.instance.Instance;
|
import fr.themode.minestom.instance.Instance;
|
||||||
import fr.themode.minestom.instance.InstanceManager;
|
import fr.themode.minestom.instance.InstanceManager;
|
||||||
|
import fr.themode.minestom.utils.thread.MinestomThread;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
public class EntityManager {
|
public class EntityManager {
|
||||||
|
|
||||||
private static InstanceManager instanceManager = Main.getInstanceManager();
|
private static InstanceManager instanceManager = Main.getInstanceManager();
|
||||||
|
|
||||||
private ExecutorService entitiesPool = Executors.newFixedThreadPool(Main.THREAD_COUNT_ENTITIES);
|
private ExecutorService entitiesPool = new MinestomThread(Main.THREAD_COUNT_ENTITIES, "Ms-EntitiesPool");
|
||||||
private ExecutorService playersPool = Executors.newFixedThreadPool(Main.THREAD_COUNT_PLAYERS_ENTITIES);
|
private ExecutorService playersPool = new MinestomThread(Main.THREAD_COUNT_PLAYERS_ENTITIES, "Ms-PlayersPool");
|
||||||
|
|
||||||
private ConcurrentLinkedQueue<Player> waitingPlayers = new ConcurrentLinkedQueue<>();
|
private ConcurrentLinkedQueue<Player> waitingPlayers = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
@ -25,7 +25,6 @@ public class EntityManager {
|
|||||||
for (Instance instance : instanceManager.getInstances()) {
|
for (Instance instance : instanceManager.getInstances()) {
|
||||||
testTick2(instance);
|
testTick2(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitingPlayersTick() {
|
private void waitingPlayersTick() {
|
||||||
@ -38,7 +37,6 @@ public class EntityManager {
|
|||||||
Instance spawningInstance = loginEvent.getSpawningInstance() == null ? instanceManager.createInstanceContainer() : loginEvent.getSpawningInstance();
|
Instance spawningInstance = loginEvent.getSpawningInstance() == null ? instanceManager.createInstanceContainer() : loginEvent.getSpawningInstance();
|
||||||
|
|
||||||
playerCache.setInstance(spawningInstance);
|
playerCache.setInstance(spawningInstance);
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import fr.themode.minestom.net.packet.server.play.SpawnObjectPacket;
|
|||||||
import fr.themode.minestom.net.player.PlayerConnection;
|
import fr.themode.minestom.net.player.PlayerConnection;
|
||||||
import fr.themode.minestom.utils.EntityUtils;
|
import fr.themode.minestom.utils.EntityUtils;
|
||||||
|
|
||||||
// TODO viewers synchronization each X ticks?
|
|
||||||
public abstract class ObjectEntity extends Entity {
|
public abstract class ObjectEntity extends Entity {
|
||||||
|
|
||||||
public ObjectEntity(int entityType) {
|
public ObjectEntity(int entityType) {
|
||||||
|
@ -4,7 +4,6 @@ import fr.themode.minestom.Main;
|
|||||||
import fr.themode.minestom.bossbar.BossBar;
|
import fr.themode.minestom.bossbar.BossBar;
|
||||||
import fr.themode.minestom.chat.Chat;
|
import fr.themode.minestom.chat.Chat;
|
||||||
import fr.themode.minestom.collision.BoundingBox;
|
import fr.themode.minestom.collision.BoundingBox;
|
||||||
import fr.themode.minestom.data.Data;
|
|
||||||
import fr.themode.minestom.entity.property.Attribute;
|
import fr.themode.minestom.entity.property.Attribute;
|
||||||
import fr.themode.minestom.event.*;
|
import fr.themode.minestom.event.*;
|
||||||
import fr.themode.minestom.instance.Chunk;
|
import fr.themode.minestom.instance.Chunk;
|
||||||
@ -23,6 +22,7 @@ import fr.themode.minestom.utils.*;
|
|||||||
import fr.themode.minestom.world.Dimension;
|
import fr.themode.minestom.world.Dimension;
|
||||||
import fr.themode.minestom.world.LevelType;
|
import fr.themode.minestom.world.LevelType;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -124,12 +124,21 @@ public class Player extends LivingEntity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setEventCallback(PlayerBlockPlaceEvent.class, event -> {
|
final String dataFileName = "C:\\Users\\themo\\OneDrive\\Bureau\\Minestom data\\" + getUsername() + ".dat";
|
||||||
/*sendMessage("Placed block! " + event.getHand());
|
|
||||||
int value = getData().getOrDefault("test", 0);
|
setEventCallback(PlayerDisconnectEvent.class, event -> {
|
||||||
getData().set("test", value + 1, DataType.INTEGER);
|
saveData(new File(dataFileName), () -> {
|
||||||
|
System.out.println("SAVE DONE");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setEventCallback(PlayerBlockPlaceEvent.class, event -> {
|
||||||
|
if (getData() != null) {
|
||||||
|
int value = getData().getOrDefault("test", 0);
|
||||||
|
getData().set("test", value + 1, Integer.class);
|
||||||
|
System.out.println("OLD DATA VALUE: " + value);
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println("OLD DATA VALUE: " + value);*/
|
|
||||||
if (event.getHand() != Hand.MAIN)
|
if (event.getHand() != Hand.MAIN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -151,18 +160,20 @@ public class Player extends LivingEntity {
|
|||||||
|
|
||||||
setEventCallback(PlayerLoginEvent.class, event -> {
|
setEventCallback(PlayerLoginEvent.class, event -> {
|
||||||
event.setSpawningInstance(instanceContainer);
|
event.setSpawningInstance(instanceContainer);
|
||||||
setData(new Data());
|
loadData(new File(dataFileName));
|
||||||
});
|
});
|
||||||
|
|
||||||
setEventCallback(PlayerSpawnEvent.class, event -> {
|
setEventCallback(PlayerSpawnEvent.class, event -> {
|
||||||
System.out.println("SPAWN");
|
setGameMode(GameMode.CREATIVE);
|
||||||
setGameMode(GameMode.SURVIVAL);
|
|
||||||
teleport(new Position(0, 66, 0));
|
teleport(new Position(0, 66, 0));
|
||||||
|
|
||||||
/*ChickenCreature chickenCreature = new ChickenCreature();
|
/*Random random = new Random();
|
||||||
chickenCreature.refreshPosition(2, 65, 2);
|
for (int i = 0; i < 50; i++) {
|
||||||
|
ChickenCreature chickenCreature = new ChickenCreature();
|
||||||
|
chickenCreature.refreshPosition(random.nextInt(100), 65, random.nextInt(100));
|
||||||
chickenCreature.setInstance(getInstance());
|
chickenCreature.setInstance(getInstance());
|
||||||
chickenCreature.addPassenger(this);*/
|
}*/
|
||||||
|
//chickenCreature.addPassenger(this);
|
||||||
|
|
||||||
/*for (int ix = 0; ix < 4; ix++)
|
/*for (int ix = 0; ix < 4; ix++)
|
||||||
for (int iz = 0; iz < 4; iz++) {
|
for (int iz = 0; iz < 4; iz++) {
|
||||||
@ -173,7 +184,7 @@ public class Player extends LivingEntity {
|
|||||||
//itemEntity.remove();
|
//itemEntity.remove();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
getInventory().addItemStack(new ItemStack(541, (byte) 1));
|
getInventory().addItemStack(new ItemStack(1, (byte) 75));
|
||||||
//getInventory().addItemStack(new ItemStack(1, (byte) 100));
|
//getInventory().addItemStack(new ItemStack(1, (byte) 100));
|
||||||
|
|
||||||
TeamsPacket teamsPacket = new TeamsPacket();
|
TeamsPacket teamsPacket = new TeamsPacket();
|
||||||
@ -198,8 +209,10 @@ public class Player extends LivingEntity {
|
|||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
|
|
||||||
|
// Flush all pending packets
|
||||||
playerConnection.flush();
|
playerConnection.flush();
|
||||||
|
|
||||||
|
// Process sent packets
|
||||||
ClientPlayPacket packet;
|
ClientPlayPacket packet;
|
||||||
while ((packet = packets.poll()) != null) {
|
while ((packet = packets.poll()) != null) {
|
||||||
packet.process(this);
|
packet.process(this);
|
||||||
@ -250,6 +263,7 @@ public class Player extends LivingEntity {
|
|||||||
|
|
||||||
|
|
||||||
// Multiplayer sync
|
// Multiplayer sync
|
||||||
|
if (!getViewers().isEmpty()) {
|
||||||
Position position = getPosition();
|
Position position = getPosition();
|
||||||
boolean positionChanged = position.getX() != lastX || position.getZ() != lastZ || position.getY() != lastY;
|
boolean positionChanged = position.getX() != lastX || position.getZ() != lastZ || position.getY() != lastY;
|
||||||
boolean viewChanged = position.getYaw() != lastYaw || position.getPitch() != lastPitch;
|
boolean viewChanged = position.getYaw() != lastYaw || position.getPitch() != lastPitch;
|
||||||
@ -310,6 +324,8 @@ public class Player extends LivingEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawn() {
|
public void spawn() {
|
||||||
|
|
||||||
@ -327,6 +343,8 @@ public class Player extends LivingEntity {
|
|||||||
getOpenInventory().removeViewer(this);
|
getOpenInventory().removeViewer(this);
|
||||||
this.viewableEntities.forEach(entity -> entity.removeViewer(this));
|
this.viewableEntities.forEach(entity -> entity.removeViewer(this));
|
||||||
this.viewableChunks.forEach(chunk -> chunk.removeViewer(this));
|
this.viewableChunks.forEach(chunk -> chunk.removeViewer(this));
|
||||||
|
resetTargetBlock();
|
||||||
|
callEvent(PlayerDisconnectEvent.class, new PlayerDisconnectEvent());
|
||||||
super.remove();
|
super.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,6 +410,7 @@ public class Player extends LivingEntity {
|
|||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
viewableChunks.add(chunk);
|
viewableChunks.add(chunk);
|
||||||
chunk.addViewer(this);
|
chunk.addViewer(this);
|
||||||
|
chunk.packetUpdated = true;
|
||||||
}
|
}
|
||||||
boolean isLast = counter.get() == length - 1;
|
boolean isLast = counter.get() == length - 1;
|
||||||
if (isLast) {
|
if (isLast) {
|
||||||
@ -807,6 +826,8 @@ public class Player extends LivingEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void resetTargetBlock() {
|
public void resetTargetBlock() {
|
||||||
|
if (targetBlockPosition != null)
|
||||||
|
sendBlockBreakAnimation(targetBlockPosition, (byte) -1); // Clear the break animation
|
||||||
this.targetCustomBlock = null;
|
this.targetCustomBlock = null;
|
||||||
this.targetBlockPosition = null;
|
this.targetBlockPosition = null;
|
||||||
this.targetBlockTime = 0;
|
this.targetBlockTime = 0;
|
||||||
|
@ -11,6 +11,8 @@ import net.tofweb.starlite.CostBlockManager;
|
|||||||
import net.tofweb.starlite.Path;
|
import net.tofweb.starlite.Path;
|
||||||
import net.tofweb.starlite.Pathfinder;
|
import net.tofweb.starlite.Pathfinder;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class ChickenCreature extends EntityCreature {
|
public class ChickenCreature extends EntityCreature {
|
||||||
|
|
||||||
private Path path;
|
private Path path;
|
||||||
@ -19,6 +21,9 @@ public class ChickenCreature extends EntityCreature {
|
|||||||
private long lastTeleport;
|
private long lastTeleport;
|
||||||
private long wait = 500;
|
private long wait = 500;
|
||||||
|
|
||||||
|
private float randomX = new Random().nextFloat();
|
||||||
|
private float randomZ = new Random().nextFloat();
|
||||||
|
|
||||||
public ChickenCreature() {
|
public ChickenCreature() {
|
||||||
super(EntityType.CHICKEN);
|
super(EntityType.CHICKEN);
|
||||||
setBoundingBox(0.4f, 0.7f, 0.4f);
|
setBoundingBox(0.4f, 0.7f, 0.4f);
|
||||||
@ -27,7 +32,7 @@ public class ChickenCreature extends EntityCreature {
|
|||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
super.update();
|
super.update();
|
||||||
float speed = 0.25f;
|
float speed = 0.025f;
|
||||||
|
|
||||||
if (hasPassenger()) {
|
if (hasPassenger()) {
|
||||||
Entity passenger = getPassengers().iterator().next();
|
Entity passenger = getPassengers().iterator().next();
|
||||||
@ -81,6 +86,8 @@ public class ChickenCreature extends EntityCreature {
|
|||||||
|
|
||||||
move(x, 0, z, updateView);
|
move(x, 0, z, updateView);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
move(randomX * speed, 0, randomZ * speed, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (path == null) {
|
/*if (path == null) {
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
package fr.themode.minestom.event;
|
||||||
|
|
||||||
|
public class PlayerDisconnectEvent extends Event {
|
||||||
|
}
|
@ -1,15 +1,17 @@
|
|||||||
package fr.themode.minestom.instance;
|
package fr.themode.minestom.instance;
|
||||||
|
|
||||||
|
import fr.themode.minestom.Main;
|
||||||
|
import fr.themode.minestom.utils.thread.MinestomThread;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
public class BlockBatch implements BlockModifier {
|
public class BlockBatch implements BlockModifier {
|
||||||
|
|
||||||
private static volatile ExecutorService batchesPool = Executors.newFixedThreadPool(2);
|
private static final ExecutorService batchesPool = new MinestomThread(Main.THREAD_COUNT_BLOCK_BATCH, "Ms-BlockBatchPool");
|
||||||
|
|
||||||
private InstanceContainer instance;
|
private InstanceContainer instance;
|
||||||
|
|
||||||
|
@ -33,7 +33,8 @@ public class Chunk implements Viewable {
|
|||||||
// Cache
|
// Cache
|
||||||
private Set<Player> viewers = new CopyOnWriteArraySet<>();
|
private Set<Player> viewers = new CopyOnWriteArraySet<>();
|
||||||
private Packet fullDataPacket;
|
private Packet fullDataPacket;
|
||||||
protected volatile boolean packetUpdated;
|
|
||||||
|
public volatile boolean packetUpdated;
|
||||||
|
|
||||||
public Chunk(Biome biome, int chunkX, int chunkZ) {
|
public Chunk(Biome biome, int chunkX, int chunkZ) {
|
||||||
this.biome = biome;
|
this.biome = biome;
|
||||||
@ -66,9 +67,9 @@ public class Chunk implements Viewable {
|
|||||||
this.blocksId[index] = blockType;
|
this.blocksId[index] = blockType;
|
||||||
this.customBlocks[index] = customId;
|
this.customBlocks[index] = customId;
|
||||||
if (isBlockEntity(blockType)) {
|
if (isBlockEntity(blockType)) {
|
||||||
blockEntities.add(index);
|
this.blockEntities.add(index);
|
||||||
} else {
|
} else {
|
||||||
blockEntities.remove(index);
|
this.blockEntities.remove(index);
|
||||||
}
|
}
|
||||||
this.packetUpdated = false;
|
this.packetUpdated = false;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package fr.themode.minestom.instance;
|
package fr.themode.minestom.instance;
|
||||||
|
|
||||||
import fr.themode.minestom.Main;
|
import fr.themode.minestom.Main;
|
||||||
|
import fr.themode.minestom.utils.thread.MinestomThread;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -13,7 +13,7 @@ import java.util.function.Consumer;
|
|||||||
*/
|
*/
|
||||||
public class ChunkBatch implements BlockModifier {
|
public class ChunkBatch implements BlockModifier {
|
||||||
|
|
||||||
private static volatile ExecutorService batchesPool = Executors.newFixedThreadPool(Main.THREAD_COUNT_CHUNK_BATCH);
|
private static final ExecutorService batchesPool = new MinestomThread(Main.THREAD_COUNT_CHUNK_BATCH, "Ms-ChunkBatchPool");
|
||||||
|
|
||||||
private InstanceContainer instance;
|
private InstanceContainer instance;
|
||||||
private Chunk chunk;
|
private Chunk chunk;
|
||||||
@ -47,9 +47,21 @@ public class ChunkBatch implements BlockModifier {
|
|||||||
this.dataList.add(data);
|
this.dataList.add(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush(Consumer<Chunk> callback) {
|
public void flushChunkGenerator(ChunkGenerator chunkGenerator, Consumer<Chunk> callback) {
|
||||||
synchronized (chunk) {
|
|
||||||
batchesPool.execute(() -> {
|
batchesPool.execute(() -> {
|
||||||
|
chunkGenerator.generateChunkData(this, chunk.getChunkX(), chunk.getChunkZ());
|
||||||
|
singleThreadFlush(callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush(Consumer<Chunk> callback) {
|
||||||
|
batchesPool.execute(() -> {
|
||||||
|
singleThreadFlush(callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void singleThreadFlush(Consumer<Chunk> callback) {
|
||||||
|
synchronized (chunk) {
|
||||||
for (BlockData data : dataList) {
|
for (BlockData data : dataList) {
|
||||||
data.apply(chunk);
|
data.apply(chunk);
|
||||||
}
|
}
|
||||||
@ -59,7 +71,6 @@ public class ChunkBatch implements BlockModifier {
|
|||||||
instance.sendChunkUpdate(chunk);
|
instance.sendChunkUpdate(chunk);
|
||||||
if (callback != null)
|
if (callback != null)
|
||||||
callback.accept(chunk);
|
callback.accept(chunk);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
package fr.themode.minestom.instance;
|
package fr.themode.minestom.instance;
|
||||||
|
|
||||||
import fr.themode.minestom.Main;
|
import fr.themode.minestom.io.IOManager;
|
||||||
import fr.themode.minestom.utils.CompressionUtils;
|
import fr.themode.minestom.utils.CompressionUtils;
|
||||||
import fr.themode.minestom.utils.SerializerUtils;
|
import fr.themode.minestom.utils.SerializerUtils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class ChunkLoaderIO {
|
public class ChunkLoaderIO {
|
||||||
|
|
||||||
private static final int COMPRESSION_LEVEL = 1;
|
|
||||||
|
|
||||||
private ExecutorService chunkLoaderPool = Executors.newFixedThreadPool(Main.THREAD_COUNT_CHUNK_IO);
|
|
||||||
|
|
||||||
private static File getChunkFile(int chunkX, int chunkZ, File folder) {
|
private static File getChunkFile(int chunkX, int chunkZ, File folder) {
|
||||||
return new File(folder, getChunkFileName(chunkX, chunkZ));
|
return new File(folder, getChunkFileName(chunkX, chunkZ));
|
||||||
}
|
}
|
||||||
@ -25,7 +19,7 @@ public class ChunkLoaderIO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void saveChunk(Chunk chunk, File folder, Runnable callback) {
|
protected void saveChunk(Chunk chunk, File folder, Runnable callback) {
|
||||||
chunkLoaderPool.execute(() -> {
|
IOManager.submit(() -> {
|
||||||
File chunkFile = getChunkFile(chunk.getChunkX(), chunk.getChunkZ(), folder);
|
File chunkFile = getChunkFile(chunk.getChunkX(), chunk.getChunkZ(), folder);
|
||||||
try (FileOutputStream fos = new FileOutputStream(chunkFile)) {
|
try (FileOutputStream fos = new FileOutputStream(chunkFile)) {
|
||||||
byte[] data = chunk.getSerializedData();
|
byte[] data = chunk.getSerializedData();
|
||||||
@ -42,7 +36,7 @@ public class ChunkLoaderIO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void loadChunk(int chunkX, int chunkZ, Instance instance, Consumer<Chunk> callback) {
|
protected void loadChunk(int chunkX, int chunkZ, Instance instance, Consumer<Chunk> callback) {
|
||||||
chunkLoaderPool.execute(() -> {
|
IOManager.submit(() -> {
|
||||||
File chunkFile = getChunkFile(chunkX, chunkZ, instance.getFolder());
|
File chunkFile = getChunkFile(chunkX, chunkZ, instance.getFolder());
|
||||||
if (!chunkFile.exists()) {
|
if (!chunkFile.exists()) {
|
||||||
instance.createChunk(chunkX, chunkZ, callback); // Chunk file does not exist, create new chunk
|
instance.createChunk(chunkX, chunkZ, callback); // Chunk file does not exist, create new chunk
|
||||||
|
@ -185,8 +185,10 @@ public abstract class Instance implements BlockModifier {
|
|||||||
// Send all visible entities
|
// Send all visible entities
|
||||||
for (long chunkIndex : visibleChunksEntity) {
|
for (long chunkIndex : visibleChunksEntity) {
|
||||||
getEntitiesInChunk(chunkIndex).forEach(ent -> {
|
getEntitiesInChunk(chunkIndex).forEach(ent -> {
|
||||||
if (isPlayer)
|
if (isPlayer) {
|
||||||
ent.addViewer((Player) entity);
|
ent.addViewer((Player) entity);
|
||||||
|
}
|
||||||
|
|
||||||
if (ent instanceof Player) {
|
if (ent instanceof Player) {
|
||||||
entity.addViewer((Player) ent);
|
entity.addViewer((Player) ent);
|
||||||
}
|
}
|
||||||
@ -249,6 +251,7 @@ public abstract class Instance implements BlockModifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Set<Entity> getEntitiesInChunk(long index) {
|
private Set<Entity> getEntitiesInChunk(long index) {
|
||||||
return chunkEntities.getOrDefault(index, new CopyOnWriteArraySet<>());
|
Set<Entity> entities = chunkEntities.get(index);
|
||||||
|
return entities != null ? entities : new CopyOnWriteArraySet<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,8 +175,7 @@ public class InstanceContainer extends Instance {
|
|||||||
cacheChunk(chunk);
|
cacheChunk(chunk);
|
||||||
if (chunkGenerator != null) {
|
if (chunkGenerator != null) {
|
||||||
ChunkBatch chunkBatch = createChunkBatch(chunk);
|
ChunkBatch chunkBatch = createChunkBatch(chunk);
|
||||||
chunkGenerator.generateChunkData(chunkBatch, chunkX, chunkZ);
|
chunkBatch.flushChunkGenerator(chunkGenerator, callback);
|
||||||
chunkBatch.flush(callback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +197,7 @@ public class InstanceContainer extends Instance {
|
|||||||
public void sendChunk(Player player, Chunk chunk) {
|
public void sendChunk(Player player, Chunk chunk) {
|
||||||
Packet data = chunk.getFullDataPacket();
|
Packet data = chunk.getFullDataPacket();
|
||||||
if (data == null || !chunk.packetUpdated) {
|
if (data == null || !chunk.packetUpdated) {
|
||||||
|
System.out.println("UPDATE CHUNK");
|
||||||
PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> {
|
PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> {
|
||||||
chunk.setFullDataPacket(buffer);
|
chunk.setFullDataPacket(buffer);
|
||||||
chunk.packetUpdated = true;
|
chunk.packetUpdated = true;
|
||||||
|
16
src/main/java/fr/themode/minestom/io/IOManager.java
Normal file
16
src/main/java/fr/themode/minestom/io/IOManager.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package fr.themode.minestom.io;
|
||||||
|
|
||||||
|
import fr.themode.minestom.Main;
|
||||||
|
import fr.themode.minestom.utils.thread.MinestomThread;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
public class IOManager {
|
||||||
|
|
||||||
|
private static final ExecutorService IO_POOL = new MinestomThread(Main.THREAD_COUNT_IO, "Ms-IOPool");
|
||||||
|
|
||||||
|
public static void submit(Runnable runnable) {
|
||||||
|
IO_POOL.execute(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -48,7 +48,6 @@ public class PlayerDiggingListener {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CANCELLED_DIGGING:
|
case CANCELLED_DIGGING:
|
||||||
player.sendBlockBreakAnimation(blockPosition, (byte) -1);
|
|
||||||
player.resetTargetBlock();
|
player.resetTargetBlock();
|
||||||
removeEffect(player);
|
removeEffect(player);
|
||||||
break;
|
break;
|
||||||
|
@ -6,15 +6,15 @@ import fr.themode.minestom.entity.Player;
|
|||||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||||
import fr.themode.minestom.net.player.PlayerConnection;
|
import fr.themode.minestom.net.player.PlayerConnection;
|
||||||
import fr.themode.minestom.utils.PacketUtils;
|
import fr.themode.minestom.utils.PacketUtils;
|
||||||
|
import fr.themode.minestom.utils.thread.MinestomThread;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class PacketWriterUtils {
|
public class PacketWriterUtils {
|
||||||
|
|
||||||
private static ExecutorService batchesPool = Executors.newFixedThreadPool(Main.THREAD_COUNT_PACKET_WRITER);
|
private static ExecutorService batchesPool = new MinestomThread(Main.THREAD_COUNT_PACKET_WRITER, "Ms-PacketWriterPool");
|
||||||
|
|
||||||
public static void writeCallbackPacket(ServerPacket serverPacket, Consumer<Packet> consumer) {
|
public static void writeCallbackPacket(ServerPacket serverPacket, Consumer<Packet> consumer) {
|
||||||
batchesPool.execute(() -> {
|
batchesPool.execute(() -> {
|
||||||
|
@ -34,9 +34,9 @@ public class SpawnMobPacket implements ServerPacket {
|
|||||||
writer.writeShort(velocityZ);
|
writer.writeShort(velocityZ);
|
||||||
if (consumer != null) {
|
if (consumer != null) {
|
||||||
writer.write(consumer);
|
writer.write(consumer);
|
||||||
} else {
|
|
||||||
writer.writeByte((byte) 0xff);
|
|
||||||
}
|
}
|
||||||
|
writer.writeByte((byte) 0xff);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -23,7 +23,6 @@ public class ChunkUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static long[] getChunksInRange(final Position position, int range) {
|
public static long[] getChunksInRange(final Position position, int range) {
|
||||||
|
|
||||||
long[] visibleChunks = new long[MathUtils.square(range + 1)];
|
long[] visibleChunks = new long[MathUtils.square(range + 1)];
|
||||||
final int startLoop = -(range / 2);
|
final int startLoop = -(range / 2);
|
||||||
final int endLoop = range / 2 + 1;
|
final int endLoop = range / 2 + 1;
|
||||||
|
@ -32,8 +32,13 @@ public class EntityUtils {
|
|||||||
if (instance == null)
|
if (instance == null)
|
||||||
return false;
|
return false;
|
||||||
Position position = entity.getPosition();
|
Position position = entity.getPosition();
|
||||||
|
try {
|
||||||
short blockId = instance.getBlockId(position.toBlockPosition().subtract(0, 1, 0));
|
short blockId = instance.getBlockId(position.toBlockPosition().subtract(0, 1, 0));
|
||||||
return blockId != 0;
|
return blockId != 0;
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// Probably an entity at the border of an unloaded chunk
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ public class PacketUtils {
|
|||||||
|
|
||||||
public static void writePacket(ServerPacket serverPacket, Consumer<Packet> callback) {
|
public static void writePacket(ServerPacket serverPacket, Consumer<Packet> callback) {
|
||||||
int id = serverPacket.getId();
|
int id = serverPacket.getId();
|
||||||
//System.out.println("SEND PACKET: 0x"+Integer.toHexString(id));
|
|
||||||
Packet packet = Packet.builder();
|
Packet packet = Packet.builder();
|
||||||
Utils.writeVarInt(packet, id);
|
Utils.writeVarInt(packet, id);
|
||||||
PacketWriter packetWriter = new PacketWriter(packet);
|
PacketWriter packetWriter = new PacketWriter(packet);
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package fr.themode.minestom.utils;
|
||||||
|
|
||||||
|
public class PrimitiveConversion {
|
||||||
|
|
||||||
|
public static Class getObjectClass(Class clazz) {
|
||||||
|
if (clazz == boolean.class)
|
||||||
|
return Boolean.class;
|
||||||
|
if (clazz == byte.class)
|
||||||
|
return Byte.class;
|
||||||
|
if (clazz == char.class)
|
||||||
|
return Character.class;
|
||||||
|
if (clazz == short.class)
|
||||||
|
return Short.class;
|
||||||
|
if (clazz == int.class)
|
||||||
|
return Integer.class;
|
||||||
|
if (clazz == long.class)
|
||||||
|
return Long.class;
|
||||||
|
if (clazz == float.class)
|
||||||
|
return Float.class;
|
||||||
|
if (clazz == double.class)
|
||||||
|
return Double.class;
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package fr.themode.minestom.utils.thread;
|
||||||
|
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class MinestomThread extends ThreadPoolExecutor {
|
||||||
|
|
||||||
|
public MinestomThread(int nThreads, String name) {
|
||||||
|
super(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), r -> {
|
||||||
|
Thread thread = new Thread(r);
|
||||||
|
thread.setName(thread.getName().replace("Thread", name));
|
||||||
|
return thread;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user