mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-27 19:47:44 +01:00
Update
This commit is contained in:
parent
f43bf11e66
commit
dedc17f42e
@ -20,4 +20,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.4.14'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import fr.adamaq01.ozao.net.server.Connection;
|
|||||||
import fr.adamaq01.ozao.net.server.Server;
|
import fr.adamaq01.ozao.net.server.Server;
|
||||||
import fr.adamaq01.ozao.net.server.ServerHandler;
|
import fr.adamaq01.ozao.net.server.ServerHandler;
|
||||||
import fr.adamaq01.ozao.net.server.backend.tcp.TCPServer;
|
import fr.adamaq01.ozao.net.server.backend.tcp.TCPServer;
|
||||||
|
import fr.themode.minestom.data.DataManager;
|
||||||
import fr.themode.minestom.entity.EntityManager;
|
import fr.themode.minestom.entity.EntityManager;
|
||||||
import fr.themode.minestom.entity.Player;
|
import fr.themode.minestom.entity.Player;
|
||||||
import fr.themode.minestom.instance.BlockManager;
|
import fr.themode.minestom.instance.BlockManager;
|
||||||
@ -42,6 +43,7 @@ public class Main {
|
|||||||
private static InstanceManager instanceManager;
|
private static InstanceManager instanceManager;
|
||||||
private static BlockManager blockManager;
|
private static BlockManager blockManager;
|
||||||
private static EntityManager entityManager;
|
private static EntityManager entityManager;
|
||||||
|
private static DataManager dataManager;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
connectionManager = new ConnectionManager();
|
connectionManager = new ConnectionManager();
|
||||||
@ -51,6 +53,7 @@ public class Main {
|
|||||||
instanceManager = new InstanceManager();
|
instanceManager = new InstanceManager();
|
||||||
blockManager = new BlockManager();
|
blockManager = new BlockManager();
|
||||||
entityManager = new EntityManager();
|
entityManager = new EntityManager();
|
||||||
|
dataManager = new DataManager();
|
||||||
|
|
||||||
blockManager.registerBlock(StoneBlock::new);
|
blockManager.registerBlock(StoneBlock::new);
|
||||||
|
|
||||||
@ -142,6 +145,10 @@ public class Main {
|
|||||||
return entityManager;
|
return entityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DataManager getDataManager() {
|
||||||
|
return dataManager;
|
||||||
|
}
|
||||||
|
|
||||||
public static ConnectionManager getConnectionManager() {
|
public static ConnectionManager getConnectionManager() {
|
||||||
return connectionManager;
|
return connectionManager;
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ public abstract class Entity implements Viewable, DataContainer {
|
|||||||
@Override
|
@Override
|
||||||
public void addViewer(Player player) {
|
public void addViewer(Player player) {
|
||||||
this.viewers.add(player);
|
this.viewers.add(player);
|
||||||
player.viewableEntity.add(this);
|
player.viewableEntities.add(this);
|
||||||
PlayerConnection playerConnection = player.getPlayerConnection();
|
PlayerConnection playerConnection = player.getPlayerConnection();
|
||||||
playerConnection.sendPacket(getVelocityPacket());
|
playerConnection.sendPacket(getVelocityPacket());
|
||||||
playerConnection.sendPacket(getPassengersPacket());
|
playerConnection.sendPacket(getPassengersPacket());
|
||||||
@ -165,7 +165,7 @@ public abstract class Entity implements Viewable, DataContainer {
|
|||||||
destroyEntitiesPacket.entityIds = new int[]{getEntityId()};
|
destroyEntitiesPacket.entityIds = new int[]{getEntityId()};
|
||||||
player.getPlayerConnection().sendPacket(destroyEntitiesPacket);
|
player.getPlayerConnection().sendPacket(destroyEntitiesPacket);
|
||||||
}
|
}
|
||||||
player.viewableEntity.remove(this);
|
player.viewableEntities.remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,19 +2,14 @@ package fr.themode.minestom.entity;
|
|||||||
|
|
||||||
import fr.themode.minestom.Main;
|
import fr.themode.minestom.Main;
|
||||||
import fr.themode.minestom.event.PlayerLoginEvent;
|
import fr.themode.minestom.event.PlayerLoginEvent;
|
||||||
import fr.themode.minestom.event.PlayerSpawnEvent;
|
|
||||||
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.ChunkUtils;
|
|
||||||
import fr.themode.minestom.utils.Position;
|
|
||||||
|
|
||||||
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;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class EntityManager {
|
public class EntityManager {
|
||||||
|
|
||||||
@ -41,35 +36,8 @@ public class EntityManager {
|
|||||||
PlayerLoginEvent loginEvent = new PlayerLoginEvent();
|
PlayerLoginEvent loginEvent = new PlayerLoginEvent();
|
||||||
playerCache.callEvent(PlayerLoginEvent.class, loginEvent);
|
playerCache.callEvent(PlayerLoginEvent.class, loginEvent);
|
||||||
Instance spawningInstance = loginEvent.getSpawningInstance() == null ? instanceManager.createInstanceContainer() : loginEvent.getSpawningInstance();
|
Instance spawningInstance = loginEvent.getSpawningInstance() == null ? instanceManager.createInstanceContainer() : loginEvent.getSpawningInstance();
|
||||||
Position position = playerCache.getPosition();
|
|
||||||
|
|
||||||
long[] visibleChunks = ChunkUtils.getChunksInRange(position, Main.CHUNK_VIEW_DISTANCE);
|
playerCache.setInstance(spawningInstance);
|
||||||
int length = visibleChunks.length;
|
|
||||||
|
|
||||||
AtomicInteger counter = new AtomicInteger(0);
|
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunks[i]);
|
|
||||||
int chunkX = chunkPos[0];
|
|
||||||
int chunkZ = chunkPos[1];
|
|
||||||
Consumer<Chunk> callback = (chunk) -> {
|
|
||||||
boolean isLast = counter.get() == length - 1;
|
|
||||||
if (isLast) {
|
|
||||||
// This is the last chunk to be loaded, spawn player
|
|
||||||
playerCache.spawned = true;
|
|
||||||
playerCache.setInstance(spawningInstance);
|
|
||||||
PlayerSpawnEvent spawnEvent = new PlayerSpawnEvent();
|
|
||||||
playerCache.callEvent(PlayerSpawnEvent.class, spawnEvent);
|
|
||||||
playerCache.updateViewPosition(chunk);
|
|
||||||
} else {
|
|
||||||
// Increment the counter of current loaded chunks
|
|
||||||
counter.incrementAndGet();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// WARNING: if auto load is disabled and no chunks are loaded beforehand, player will be stuck.
|
|
||||||
spawningInstance.loadChunk(chunkX, chunkZ, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -77,7 +45,6 @@ public class EntityManager {
|
|||||||
|
|
||||||
// TODO optimize for when there are too many entities on one chunk
|
// TODO optimize for when there are too many entities on one chunk
|
||||||
private void testTick2(Instance instance) {
|
private void testTick2(Instance instance) {
|
||||||
|
|
||||||
for (Chunk chunk : instance.getChunks()) {
|
for (Chunk chunk : instance.getChunks()) {
|
||||||
Set<Entity> entities = instance.getChunkEntities(chunk);
|
Set<Entity> entities = instance.getChunkEntities(chunk);
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@ import java.util.Set;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class Player extends LivingEntity {
|
public class Player extends LivingEntity {
|
||||||
|
|
||||||
@ -62,7 +64,8 @@ public class Player extends LivingEntity {
|
|||||||
System.out.println("Time to load all chunks: " + (System.currentTimeMillis() - time) + " ms");
|
System.out.println("Time to load all chunks: " + (System.currentTimeMillis() - time) + " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set<Entity> viewableEntity = new CopyOnWriteArraySet<>();
|
protected Set<Entity> viewableEntities = new CopyOnWriteArraySet<>();
|
||||||
|
protected Set<Chunk> viewableChunks = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
private PlayerSettings settings;
|
private PlayerSettings settings;
|
||||||
private float exp;
|
private float exp;
|
||||||
@ -87,8 +90,6 @@ public class Player extends LivingEntity {
|
|||||||
private boolean jump;
|
private boolean jump;
|
||||||
private boolean unmount;
|
private boolean unmount;
|
||||||
|
|
||||||
protected boolean spawned;
|
|
||||||
|
|
||||||
public Player(UUID uuid, String username, PlayerConnection playerConnection) {
|
public Player(UUID uuid, String username, PlayerConnection playerConnection) {
|
||||||
super(100);
|
super(100);
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
@ -247,6 +248,9 @@ public class Player extends LivingEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tick event
|
||||||
|
callEvent(PlayerTickEvent.class, new PlayerTickEvent());
|
||||||
|
|
||||||
|
|
||||||
// Multiplayer sync
|
// Multiplayer sync
|
||||||
Position position = getPosition();
|
Position position = getPosition();
|
||||||
@ -324,7 +328,7 @@ public class Player extends LivingEntity {
|
|||||||
clearBossBars();
|
clearBossBars();
|
||||||
if (getOpenInventory() != null)
|
if (getOpenInventory() != null)
|
||||||
getOpenInventory().removeViewer(this);
|
getOpenInventory().removeViewer(this);
|
||||||
this.viewableEntity.forEach(entity -> entity.removeViewer(this));
|
this.viewableEntities.forEach(entity -> entity.removeViewer(this));
|
||||||
super.remove();
|
super.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,10 +371,46 @@ public class Player extends LivingEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setInstance(Instance instance) {
|
public void setInstance(Instance instance) {
|
||||||
if (!spawned)
|
if (instance == null)
|
||||||
throw new IllegalStateException("Player#setInstance is only available during and after PlayerSpawnEvent");
|
throw new IllegalArgumentException("instance cannot be null!");
|
||||||
|
if (this.instance == instance)
|
||||||
|
throw new IllegalArgumentException("Instance should be different than the current one");
|
||||||
|
|
||||||
super.setInstance(instance);
|
for (Chunk viewableChunk : viewableChunks) {
|
||||||
|
viewableChunk.removeViewer(this);
|
||||||
|
}
|
||||||
|
viewableChunks.clear();
|
||||||
|
|
||||||
|
long[] visibleChunks = ChunkUtils.getChunksInRange(position, getChunkRange());
|
||||||
|
int length = visibleChunks.length;
|
||||||
|
|
||||||
|
AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunks[i]);
|
||||||
|
int chunkX = chunkPos[0];
|
||||||
|
int chunkZ = chunkPos[1];
|
||||||
|
Consumer<Chunk> callback = (chunk) -> {
|
||||||
|
if (chunk != null) {
|
||||||
|
viewableChunks.add(chunk);
|
||||||
|
chunk.addViewer(this);
|
||||||
|
}
|
||||||
|
boolean isLast = counter.get() == length - 1;
|
||||||
|
if (isLast) {
|
||||||
|
// This is the last chunk to be loaded, spawn player
|
||||||
|
super.setInstance(instance);
|
||||||
|
PlayerSpawnEvent spawnEvent = new PlayerSpawnEvent(instance);
|
||||||
|
callEvent(PlayerSpawnEvent.class, spawnEvent);
|
||||||
|
updateViewPosition(chunk);
|
||||||
|
} else {
|
||||||
|
// Increment the counter of current loaded chunks
|
||||||
|
counter.incrementAndGet();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// WARNING: if auto load is disabled and no chunks are loaded beforehand, player will be stuck.
|
||||||
|
instance.loadOptionalChunk(chunkX, chunkZ, callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -516,6 +556,10 @@ public class Player extends LivingEntity {
|
|||||||
unloadChunkPacket.chunkX = chunkPos[0];
|
unloadChunkPacket.chunkX = chunkPos[0];
|
||||||
unloadChunkPacket.chunkZ = chunkPos[1];
|
unloadChunkPacket.chunkZ = chunkPos[1];
|
||||||
playerConnection.sendPacket(unloadChunkPacket);
|
playerConnection.sendPacket(unloadChunkPacket);
|
||||||
|
|
||||||
|
Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]);
|
||||||
|
if (chunk != null)
|
||||||
|
chunk.removeViewer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateViewPosition(newChunk);
|
updateViewPosition(newChunk);
|
||||||
@ -529,6 +573,8 @@ public class Player extends LivingEntity {
|
|||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
return; // Cannot load chunk (auto load is not enabled)
|
return; // Cannot load chunk (auto load is not enabled)
|
||||||
}
|
}
|
||||||
|
this.viewableChunks.add(chunk);
|
||||||
|
chunk.addViewer(this);
|
||||||
instance.sendChunk(this, chunk);
|
instance.sendChunk(this, chunk);
|
||||||
if (isFar && isLast) {
|
if (isFar && isLast) {
|
||||||
updatePlayerPosition();
|
updatePlayerPosition();
|
||||||
@ -678,6 +724,10 @@ public class Player extends LivingEntity {
|
|||||||
inventory.update();
|
inventory.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Chunk> getViewableChunks() {
|
||||||
|
return Collections.unmodifiableSet(viewableChunks);
|
||||||
|
}
|
||||||
|
|
||||||
public void clearBossBars() {
|
public void clearBossBars() {
|
||||||
this.bossBars.forEach(bossBar -> bossBar.removeViewer(this));
|
this.bossBars.forEach(bossBar -> bossBar.removeViewer(this));
|
||||||
}
|
}
|
||||||
@ -767,6 +817,12 @@ public class Player extends LivingEntity {
|
|||||||
this.unmount = unmount;
|
this.unmount = unmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getChunkRange() {
|
||||||
|
int serverRange = Main.CHUNK_VIEW_DISTANCE;
|
||||||
|
int playerRange = getSettings().viewDistance;
|
||||||
|
return serverRange;//playerRange < serverRange ? playerRange : serverRange;
|
||||||
|
}
|
||||||
|
|
||||||
public long getLastKeepAlive() {
|
public long getLastKeepAlive() {
|
||||||
return lastKeepAlive;
|
return lastKeepAlive;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
package fr.themode.minestom.event;
|
package fr.themode.minestom.event;
|
||||||
|
|
||||||
|
import fr.themode.minestom.instance.Instance;
|
||||||
|
|
||||||
public class PlayerSpawnEvent extends Event {
|
public class PlayerSpawnEvent extends Event {
|
||||||
|
|
||||||
|
private Instance spawnInstance;
|
||||||
|
|
||||||
|
public PlayerSpawnEvent(Instance spawnInstance) {
|
||||||
|
this.spawnInstance = spawnInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instance getSpawnInstance() {
|
||||||
|
return spawnInstance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
package fr.themode.minestom.event;
|
||||||
|
|
||||||
|
public class PlayerTickEvent extends Event {
|
||||||
|
}
|
@ -3,6 +3,8 @@ package fr.themode.minestom.instance;
|
|||||||
import fr.adamaq01.ozao.net.Buffer;
|
import fr.adamaq01.ozao.net.Buffer;
|
||||||
import fr.adamaq01.ozao.net.packet.Packet;
|
import fr.adamaq01.ozao.net.packet.Packet;
|
||||||
import fr.themode.minestom.Main;
|
import fr.themode.minestom.Main;
|
||||||
|
import fr.themode.minestom.Viewable;
|
||||||
|
import fr.themode.minestom.entity.Player;
|
||||||
import fr.themode.minestom.net.packet.server.play.ChunkDataPacket;
|
import fr.themode.minestom.net.packet.server.play.ChunkDataPacket;
|
||||||
import fr.themode.minestom.utils.PacketUtils;
|
import fr.themode.minestom.utils.PacketUtils;
|
||||||
import fr.themode.minestom.utils.SerializerUtils;
|
import fr.themode.minestom.utils.SerializerUtils;
|
||||||
@ -10,10 +12,11 @@ import fr.themode.minestom.utils.SerializerUtils;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
public class Chunk {
|
public class Chunk implements Viewable {
|
||||||
|
|
||||||
public static final int CHUNK_SIZE_X = 16;
|
public static final int CHUNK_SIZE_X = 16;
|
||||||
public static final int CHUNK_SIZE_Y = 256;
|
public static final int CHUNK_SIZE_Y = 256;
|
||||||
@ -29,6 +32,7 @@ public class Chunk {
|
|||||||
private Set<Integer> blockEntities = new CopyOnWriteArraySet<>();
|
private Set<Integer> blockEntities = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
|
private Set<Player> viewers = new CopyOnWriteArraySet<>();
|
||||||
private Buffer fullDataPacket;
|
private Buffer fullDataPacket;
|
||||||
|
|
||||||
public Chunk(Biome biome, int chunkX, int chunkZ) {
|
public Chunk(Biome biome, int chunkX, int chunkZ) {
|
||||||
@ -155,4 +159,21 @@ public class Chunk {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "Chunk[" + chunkX + ":" + chunkZ + "]";
|
return "Chunk[" + chunkX + ":" + chunkZ + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UNSAFE
|
||||||
|
@Override
|
||||||
|
public void addViewer(Player player) {
|
||||||
|
this.viewers.add(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UNSAFE
|
||||||
|
@Override
|
||||||
|
public void removeViewer(Player player) {
|
||||||
|
this.viewers.remove(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Player> getViewers() {
|
||||||
|
return Collections.unmodifiableSet(viewers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,8 @@ public abstract class Instance implements BlockModifier {
|
|||||||
|
|
||||||
public abstract void sendChunkUpdate(Player player, Chunk chunk);
|
public abstract void sendChunkUpdate(Player player, Chunk chunk);
|
||||||
|
|
||||||
|
public abstract void sendChunkSectionUpdate(Chunk chunk, int section, Player player);
|
||||||
|
|
||||||
protected abstract void retrieveChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
|
protected abstract void retrieveChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
|
||||||
|
|
||||||
public abstract void createChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
|
public abstract void createChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
|
||||||
|
@ -4,6 +4,8 @@ import fr.adamaq01.ozao.net.Buffer;
|
|||||||
import fr.themode.minestom.entity.Player;
|
import fr.themode.minestom.entity.Player;
|
||||||
import fr.themode.minestom.event.PlayerBlockBreakEvent;
|
import fr.themode.minestom.event.PlayerBlockBreakEvent;
|
||||||
import fr.themode.minestom.net.PacketWriterUtils;
|
import fr.themode.minestom.net.PacketWriterUtils;
|
||||||
|
import fr.themode.minestom.net.packet.server.play.BlockChangePacket;
|
||||||
|
import fr.themode.minestom.net.packet.server.play.ChunkDataPacket;
|
||||||
import fr.themode.minestom.net.packet.server.play.ParticlePacket;
|
import fr.themode.minestom.net.packet.server.play.ParticlePacket;
|
||||||
import fr.themode.minestom.utils.BlockPosition;
|
import fr.themode.minestom.utils.BlockPosition;
|
||||||
import fr.themode.minestom.utils.ChunkUtils;
|
import fr.themode.minestom.utils.ChunkUtils;
|
||||||
@ -37,11 +39,11 @@ public class InstanceContainer extends Instance {
|
|||||||
public synchronized void setBlock(int x, int y, int z, short blockId) {
|
public synchronized void setBlock(int x, int y, int z, short blockId) {
|
||||||
Chunk chunk = getChunkAt(x, z);
|
Chunk chunk = getChunkAt(x, z);
|
||||||
synchronized (chunk) {
|
synchronized (chunk) {
|
||||||
chunk.setBlock((byte) (x % 16), (byte) y, (byte) (z % 16), blockId);
|
byte chunkX = (byte) (x % 16);
|
||||||
PacketWriterUtils.writeCallbackPacket(chunk.getFreshPartialDataPacket(), buffer -> {
|
byte chunkY = (byte) y;
|
||||||
chunk.setFullDataPacket(buffer);
|
byte chunkZ = (byte) (z % 16);
|
||||||
sendChunkUpdate(chunk);
|
chunk.setBlock(chunkX, chunkY, chunkZ, blockId);
|
||||||
});
|
sendBlockChange(chunk, x, y, z, blockId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,21 +51,21 @@ public class InstanceContainer extends Instance {
|
|||||||
public synchronized void setBlock(int x, int y, int z, String blockId) {
|
public synchronized void setBlock(int x, int y, int z, String blockId) {
|
||||||
Chunk chunk = getChunkAt(x, z);
|
Chunk chunk = getChunkAt(x, z);
|
||||||
synchronized (chunk) {
|
synchronized (chunk) {
|
||||||
chunk.setCustomBlock((byte) (x % 16), (byte) y, (byte) (z % 16), blockId);
|
byte chunkX = (byte) (x % 16);
|
||||||
PacketWriterUtils.writeCallbackPacket(chunk.getFreshPartialDataPacket(), buffer -> {
|
byte chunkY = (byte) y;
|
||||||
chunk.setFullDataPacket(buffer);
|
byte chunkZ = (byte) (z % 16);
|
||||||
sendChunkUpdate(chunk);
|
chunk.setCustomBlock(chunkX, chunkY, chunkZ, blockId);
|
||||||
});
|
short id = chunk.getBlockId(chunkX, chunkY, chunkZ);
|
||||||
|
sendBlockChange(chunk, x, y, z, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO deplace
|
|
||||||
@Override
|
@Override
|
||||||
public void breakBlock(Player player, BlockPosition blockPosition) {
|
public void breakBlock(Player player, BlockPosition blockPosition) {
|
||||||
Chunk chunk = getChunkAt(blockPosition);
|
Chunk chunk = getChunkAt(blockPosition);
|
||||||
short blockId = chunk.getBlockId((byte) (blockPosition.getX() % 16), (byte) blockPosition.getY(), (byte) (blockPosition.getZ() % 16));
|
short blockId = chunk.getBlockId((byte) (blockPosition.getX() % 16), (byte) blockPosition.getY(), (byte) (blockPosition.getZ() % 16));
|
||||||
if (blockId == 0) {
|
if (blockId == 0) {
|
||||||
sendChunkUpdate(player, chunk);
|
sendChunkSectionUpdate(chunk, ChunkUtils.getSectionAt(blockPosition.getY()), player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,10 +89,9 @@ public class InstanceContainer extends Instance {
|
|||||||
particlePacket.particleData = 0.3f;
|
particlePacket.particleData = 0.3f;
|
||||||
particlePacket.particleCount = 100;
|
particlePacket.particleCount = 100;
|
||||||
particlePacket.blockId = blockId;
|
particlePacket.blockId = blockId;
|
||||||
player.getPlayerConnection().sendPacket(particlePacket);
|
chunk.sendPacketToViewers(particlePacket);
|
||||||
player.sendPacketToViewers(particlePacket);
|
|
||||||
} else {
|
} else {
|
||||||
sendChunkUpdate(player, chunk);
|
sendChunkSectionUpdate(chunk, ChunkUtils.getSectionAt(blockPosition.getY()), player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +157,17 @@ public class InstanceContainer extends Instance {
|
|||||||
chunkData.getData().resetReaderIndex();
|
chunkData.getData().resetReaderIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendChunkSectionUpdate(Chunk chunk, int section, Player player) {
|
||||||
|
ChunkDataPacket chunkDataPacket = new ChunkDataPacket();
|
||||||
|
chunkDataPacket.fullChunk = false;
|
||||||
|
chunkDataPacket.chunk = chunk;
|
||||||
|
int[] sections = new int[16];
|
||||||
|
sections[section] = 1;
|
||||||
|
chunkDataPacket.sections = sections;
|
||||||
|
PacketWriterUtils.writeAndSend(player, chunkDataPacket);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void retrieveChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
|
protected void retrieveChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
|
||||||
if (folder != null) {
|
if (folder != null) {
|
||||||
@ -184,9 +196,12 @@ public class InstanceContainer extends Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void sendChunkUpdate(Chunk chunk) {
|
public void sendChunkUpdate(Chunk chunk) {
|
||||||
|
Set<Player> chunkViewers = chunk.getViewers();
|
||||||
|
if (!chunkViewers.isEmpty()) {
|
||||||
|
sendChunkUpdate(chunkViewers, chunk);
|
||||||
|
}
|
||||||
// Update for players in this instance
|
// Update for players in this instance
|
||||||
if (!getPlayers().isEmpty())
|
/*if (!getPlayers().isEmpty())
|
||||||
sendChunkUpdate(getPlayers(), chunk);
|
sendChunkUpdate(getPlayers(), chunk);
|
||||||
|
|
||||||
// Update for shared instances
|
// Update for shared instances
|
||||||
@ -195,7 +210,7 @@ public class InstanceContainer extends Instance {
|
|||||||
Set<Player> instancePlayers = sharedInstance.getPlayers();
|
Set<Player> instancePlayers = sharedInstance.getPlayers();
|
||||||
if (!instancePlayers.isEmpty())
|
if (!instancePlayers.isEmpty())
|
||||||
sendChunkUpdate(instancePlayers, chunk);
|
sendChunkUpdate(instancePlayers, chunk);
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -209,7 +224,7 @@ public class InstanceContainer extends Instance {
|
|||||||
public void sendChunk(Player player, Chunk chunk) {
|
public void sendChunk(Player player, Chunk chunk) {
|
||||||
/*Buffer data = chunk.getFullDataPacket();
|
/*Buffer data = chunk.getFullDataPacket();
|
||||||
if(data == null) {
|
if(data == null) {
|
||||||
PacketWriter.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> {
|
PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> {
|
||||||
chunk.setFullDataPacket(buffer);
|
chunk.setFullDataPacket(buffer);
|
||||||
sendChunkUpdate(player, chunk);
|
sendChunkUpdate(player, chunk);
|
||||||
});
|
});
|
||||||
@ -256,4 +271,11 @@ public class InstanceContainer extends Instance {
|
|||||||
this.folder = folder;
|
this.folder = folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendBlockChange(Chunk chunk, int x, int y, int z, short blockId) {
|
||||||
|
BlockChangePacket blockChangePacket = new BlockChangePacket();
|
||||||
|
blockChangePacket.blockPosition = new BlockPosition(x, y, z);
|
||||||
|
blockChangePacket.blockId = blockId;
|
||||||
|
chunk.sendPacketToViewers(blockChangePacket);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,11 @@ public class SharedInstance extends Instance {
|
|||||||
instanceContainer.sendChunkUpdate(player, chunk);
|
instanceContainer.sendChunkUpdate(player, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendChunkSectionUpdate(Chunk chunk, int section, Player player) {
|
||||||
|
instanceContainer.sendChunkSectionUpdate(chunk, section, player);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void retrieveChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
|
public void retrieveChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
|
||||||
instanceContainer.retrieveChunk(chunkX, chunkZ, callback);
|
instanceContainer.retrieveChunk(chunkX, chunkZ, callback);
|
||||||
|
@ -9,6 +9,7 @@ import fr.themode.minestom.item.ItemStack;
|
|||||||
import fr.themode.minestom.net.packet.client.play.ClientPlayerBlockPlacementPacket;
|
import fr.themode.minestom.net.packet.client.play.ClientPlayerBlockPlacementPacket;
|
||||||
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket;
|
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket;
|
||||||
import fr.themode.minestom.utils.BlockPosition;
|
import fr.themode.minestom.utils.BlockPosition;
|
||||||
|
import fr.themode.minestom.utils.ChunkUtils;
|
||||||
|
|
||||||
public class BlockPlacementListener {
|
public class BlockPlacementListener {
|
||||||
|
|
||||||
@ -23,15 +24,17 @@ public class BlockPlacementListener {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ItemStack usedItem = hand == Player.Hand.MAIN ? playerInventory.getItemInMainHand() : playerInventory.getItemInOffHand();
|
ItemStack usedItem = hand == Player.Hand.MAIN ? playerInventory.getItemInMainHand() : playerInventory.getItemInOffHand();
|
||||||
if (!usedItem.getMaterial().isBlock())
|
if (!usedItem.getMaterial().isBlock()) {
|
||||||
|
//instance.setBlock(blockPosition.clone().add(0, 1, 0), (short) 10);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int offsetX = blockFace == ClientPlayerDiggingPacket.BlockFace.WEST ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.EAST ? 1 : 0;
|
int offsetX = blockFace == ClientPlayerDiggingPacket.BlockFace.WEST ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.EAST ? 1 : 0;
|
||||||
int offsetY = blockFace == ClientPlayerDiggingPacket.BlockFace.BOTTOM ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.TOP ? 1 : 0;
|
int offsetY = blockFace == ClientPlayerDiggingPacket.BlockFace.BOTTOM ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.TOP ? 1 : 0;
|
||||||
int offsetZ = blockFace == ClientPlayerDiggingPacket.BlockFace.NORTH ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.SOUTH ? 1 : 0;
|
int offsetZ = blockFace == ClientPlayerDiggingPacket.BlockFace.NORTH ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.SOUTH ? 1 : 0;
|
||||||
|
|
||||||
blockPosition.add(offsetX, offsetY, offsetZ);
|
blockPosition.add(offsetX, offsetY, offsetZ);
|
||||||
boolean intersectPlayer = player.getBoundingBox().intersect(blockPosition);
|
boolean intersectPlayer = player.getBoundingBox().intersect(blockPosition); // TODO check if collide with nearby players
|
||||||
if (!intersectPlayer) {
|
if (!intersectPlayer) {
|
||||||
PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent((short) 10, blockPosition, packet.hand);
|
PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent((short) 10, blockPosition, packet.hand);
|
||||||
player.callEvent(PlayerBlockPlaceEvent.class, playerBlockPlaceEvent);
|
player.callEvent(PlayerBlockPlaceEvent.class, playerBlockPlaceEvent);
|
||||||
@ -49,7 +52,7 @@ public class BlockPlacementListener {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Chunk chunk = instance.getChunkAt(blockPosition);
|
Chunk chunk = instance.getChunkAt(blockPosition);
|
||||||
instance.sendChunkUpdate(player, chunk);
|
instance.sendChunkSectionUpdate(chunk, ChunkUtils.getSectionAt(blockPosition.getY()), player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
player.getInventory().refreshSlot(player.getHeldSlot());
|
player.getInventory().refreshSlot(player.getHeldSlot());
|
||||||
|
@ -25,7 +25,7 @@ public class PlayerDiggingListener {
|
|||||||
if (player.getGameMode() == GameMode.CREATIVE) {
|
if (player.getGameMode() == GameMode.CREATIVE) {
|
||||||
Instance instance = player.getInstance();
|
Instance instance = player.getInstance();
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
instance.setBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), (short) 0);
|
instance.breakBlock(player, blockPosition);
|
||||||
}
|
}
|
||||||
} else if (player.getGameMode() == GameMode.SURVIVAL) {
|
} else if (player.getGameMode() == GameMode.SURVIVAL) {
|
||||||
Instance instance = player.getInstance();
|
Instance instance = player.getInstance();
|
||||||
|
@ -5,6 +5,7 @@ import fr.adamaq01.ozao.net.packet.Packet;
|
|||||||
import fr.themode.minestom.Main;
|
import fr.themode.minestom.Main;
|
||||||
import fr.themode.minestom.entity.Player;
|
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.utils.PacketUtils;
|
import fr.themode.minestom.utils.PacketUtils;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -25,13 +26,13 @@ public class PacketWriterUtils {
|
|||||||
|
|
||||||
public static void writeAndSend(Collection<Player> players, ServerPacket serverPacket) {
|
public static void writeAndSend(Collection<Player> players, ServerPacket serverPacket) {
|
||||||
batchesPool.execute(() -> {
|
batchesPool.execute(() -> {
|
||||||
Packet p = PacketUtils.writePacket(serverPacket);
|
|
||||||
Buffer encoded = PacketUtils.encode(p);
|
|
||||||
|
|
||||||
|
|
||||||
int size = players.size();
|
int size = players.size();
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Packet p = PacketUtils.writePacket(serverPacket);
|
||||||
|
Buffer encoded = PacketUtils.encode(p);
|
||||||
|
|
||||||
encoded.getData().retain(size).markReaderIndex();
|
encoded.getData().retain(size).markReaderIndex();
|
||||||
for (Player player : players) {
|
for (Player player : players) {
|
||||||
player.getPlayerConnection().writeUnencodedPacket(encoded);
|
player.getPlayerConnection().writeUnencodedPacket(encoded);
|
||||||
@ -40,4 +41,16 @@ public class PacketWriterUtils {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void writeAndSend(PlayerConnection playerConnection, ServerPacket serverPacket) {
|
||||||
|
batchesPool.execute(() -> {
|
||||||
|
Packet p = PacketUtils.writePacket(serverPacket);
|
||||||
|
Buffer encoded = PacketUtils.encode(p);
|
||||||
|
playerConnection.writeUnencodedPacket(encoded);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeAndSend(Player player, ServerPacket serverPacket) {
|
||||||
|
writeAndSend(player.getPlayerConnection(), serverPacket);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
|
|
||||||
public boolean fullChunk;
|
public boolean fullChunk;
|
||||||
public Chunk chunk;
|
public Chunk chunk;
|
||||||
|
public int[] sections;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(PacketWriter writer) {
|
public void write(PacketWriter writer) {
|
||||||
@ -31,10 +32,11 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
int mask = 0;
|
int mask = 0;
|
||||||
Buffer blocks = Buffer.create();
|
Buffer blocks = Buffer.create();
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
// TODO if fullchunk is false then only send changed sections
|
if (fullChunk || (sections.length == 16 && sections[i] != 0)) {
|
||||||
mask |= 1 << i;
|
mask |= 1 << i;
|
||||||
short[] section = getSection(chunk, i);
|
short[] section = getSection(chunk, i);
|
||||||
Utils.writeBlocks(blocks, section, 14);
|
Utils.writeBlocks(blocks, section, 14);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Biome data
|
// Biome data
|
||||||
if (fullChunk) {
|
if (fullChunk) {
|
||||||
|
@ -4,8 +4,8 @@ import fr.adamaq01.ozao.net.Buffer;
|
|||||||
import fr.adamaq01.ozao.net.packet.Packet;
|
import fr.adamaq01.ozao.net.packet.Packet;
|
||||||
import fr.adamaq01.ozao.net.server.Connection;
|
import fr.adamaq01.ozao.net.server.Connection;
|
||||||
import fr.themode.minestom.net.ConnectionState;
|
import fr.themode.minestom.net.ConnectionState;
|
||||||
|
import fr.themode.minestom.net.PacketWriterUtils;
|
||||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||||
import fr.themode.minestom.utils.PacketUtils;
|
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
|
||||||
@ -27,9 +27,9 @@ public class PlayerConnection {
|
|||||||
|
|
||||||
|
|
||||||
// TODO make that proper (remove reflection)
|
// TODO make that proper (remove reflection)
|
||||||
private Field field;
|
private static Field field;
|
||||||
|
|
||||||
{
|
static {
|
||||||
try {
|
try {
|
||||||
field = Class.forName("fr.adamaq01.ozao.net.server.backend.tcp.TCPConnection").getDeclaredField("channel");
|
field = Class.forName("fr.adamaq01.ozao.net.server.backend.tcp.TCPConnection").getDeclaredField("channel");
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
@ -49,7 +49,7 @@ public class PlayerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void sendPacket(ServerPacket serverPacket) {
|
public void sendPacket(ServerPacket serverPacket) {
|
||||||
sendPacket(PacketUtils.writePacket(serverPacket));
|
PacketWriterUtils.writeAndSend(this, serverPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush() {
|
public void flush() {
|
||||||
|
@ -18,6 +18,10 @@ public class ChunkUtils {
|
|||||||
return new int[]{chunkX, chunkZ};
|
return new int[]{chunkX, chunkZ};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getSectionAt(int y) {
|
||||||
|
return y / 16;
|
||||||
|
}
|
||||||
|
|
||||||
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)];
|
||||||
|
Loading…
Reference in New Issue
Block a user