mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-25 01:21:20 +01:00
Improved thread safety
This commit is contained in:
parent
87345f70ab
commit
3b6b5676ed
@ -81,26 +81,14 @@ public class Entity {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(double z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
this.shouldRemove = true;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityRelativeMovePacket;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityTeleportPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.SpawnMobPacket;
|
||||
import fr.themode.minestom.net.player.PlayerConnection;
|
||||
|
||||
@ -19,6 +22,40 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
public void move(double x, double y, double z) {
|
||||
double newX = getX() + x;
|
||||
double newY = getY() + y;
|
||||
double newZ = getZ() + z;
|
||||
|
||||
if (chunkTest(newX, newZ))
|
||||
return;
|
||||
|
||||
EntityRelativeMovePacket entityRelativeMovePacket = new EntityRelativeMovePacket();
|
||||
entityRelativeMovePacket.entityId = getEntityId();
|
||||
entityRelativeMovePacket.deltaX = (short) ((newX * 32 - getX() * 32) * 128);
|
||||
entityRelativeMovePacket.deltaY = (short) ((newY * 32 - getY() * 32) * 128);
|
||||
entityRelativeMovePacket.deltaZ = (short) ((newZ * 32 - getZ() * 32) * 128);
|
||||
entityRelativeMovePacket.onGround = true;
|
||||
sendPacketToViewers(entityRelativeMovePacket);
|
||||
|
||||
refreshPosition(newX, newY, newZ);
|
||||
}
|
||||
|
||||
public void teleport(double x, double y, double z) {
|
||||
if (chunkTest(x, z))
|
||||
return;
|
||||
|
||||
EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket();
|
||||
entityTeleportPacket.entityId = getEntityId();
|
||||
entityTeleportPacket.x = x;
|
||||
entityTeleportPacket.y = y;
|
||||
entityTeleportPacket.z = z;
|
||||
entityTeleportPacket.yaw = getYaw();
|
||||
entityTeleportPacket.pitch = getPitch();
|
||||
entityTeleportPacket.onGround = true;
|
||||
sendPacketToViewers(entityTeleportPacket);
|
||||
}
|
||||
|
||||
public void addViewer(Player player) {
|
||||
this.viewers.add(player);
|
||||
PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
@ -48,6 +85,10 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendPacketToViewers(ServerPacket packet) {
|
||||
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(packet));
|
||||
}
|
||||
|
||||
public Set<Player> getViewers() {
|
||||
return Collections.unmodifiableSet(viewers);
|
||||
}
|
||||
|
@ -11,35 +11,42 @@ public class EntityManager {
|
||||
|
||||
private static InstanceManager instanceManager = Main.getInstanceManager();
|
||||
|
||||
private ExecutorService creaturesPool = Executors.newFixedThreadPool(3);
|
||||
private ExecutorService creaturesPool = Executors.newFixedThreadPool(4);
|
||||
private ExecutorService playersPool = Executors.newFixedThreadPool(2);
|
||||
|
||||
public void update() {
|
||||
|
||||
for (Instance instance : instanceManager.getInstances()) {
|
||||
|
||||
synchronized (instance) {
|
||||
// Creatures
|
||||
for (EntityCreature creature : instance.getCreatures()) {
|
||||
creaturesPool.submit(() -> {
|
||||
// Creatures
|
||||
//long time = System.nanoTime();
|
||||
for (EntityCreature creature : instance.getCreatures()) {
|
||||
creaturesPool.submit(() -> {
|
||||
boolean shouldRemove = creature.shouldRemove();
|
||||
if (!shouldRemove) {
|
||||
creature.update();
|
||||
boolean shouldRemove = creature.shouldRemove();
|
||||
if (shouldRemove) {
|
||||
instance.removeEntity(creature);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Players
|
||||
for (Player player : instance.getPlayers()) {
|
||||
playersPool.submit(() -> {
|
||||
player.update();
|
||||
boolean shouldRemove = player.shouldRemove();
|
||||
if (shouldRemove) {
|
||||
instance.removeEntity(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (creature.shouldRemove()) {
|
||||
instance.removeEntity(creature);
|
||||
}
|
||||
});
|
||||
}
|
||||
/*creaturesPool.shutdown();
|
||||
while (!creaturesPool.isTerminated()) {
|
||||
|
||||
}
|
||||
System.out.println("delay: " + (System.nanoTime() - time));
|
||||
creaturesPool = Executors.newFixedThreadPool(4);*/
|
||||
|
||||
// Players
|
||||
for (Player player : instance.getPlayers()) {
|
||||
playersPool.submit(() -> {
|
||||
player.update();
|
||||
boolean shouldRemove = player.shouldRemove();
|
||||
if (shouldRemove) {
|
||||
instance.removeEntity(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,10 @@ public abstract class LivingEntity extends Entity {
|
||||
|
||||
public abstract void update();
|
||||
|
||||
public boolean chunkTest(double x, double z) {
|
||||
return getInstance().getChunk((int) Math.floor(x / 16), (int) Math.floor(z / 16)) == null;
|
||||
}
|
||||
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.Main;
|
||||
import fr.themode.minestom.instance.Chunk;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityTeleportPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.PlayerPositionAndLookPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.UpdateViewPositionPacket;
|
||||
@ -44,21 +43,16 @@ public class Player extends LivingEntity {
|
||||
playerConnection.sendPacket(new UpdateViewPositionPacket(Math.floorDiv((int) x, 16), Math.floorDiv((int) z, 16)));
|
||||
}
|
||||
|
||||
public boolean chunkTest(double x, double z) {
|
||||
Chunk newChunk = getInstance().getChunk((int) Math.floor(x / 16), (int) Math.floor(z / 16));
|
||||
if (newChunk == null) {
|
||||
PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket();
|
||||
positionAndLookPacket.x = getX();
|
||||
positionAndLookPacket.y = getY();
|
||||
positionAndLookPacket.z = getZ();
|
||||
positionAndLookPacket.yaw = getYaw();
|
||||
positionAndLookPacket.pitch = getPitch();
|
||||
positionAndLookPacket.flags = 0x00;
|
||||
positionAndLookPacket.teleportId = 67;
|
||||
getPlayerConnection().sendPacket(positionAndLookPacket);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
public void teleport(double x, double y, double z) {
|
||||
PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket();
|
||||
positionAndLookPacket.x = x;
|
||||
positionAndLookPacket.y = y;
|
||||
positionAndLookPacket.z = z;
|
||||
positionAndLookPacket.yaw = getYaw();
|
||||
positionAndLookPacket.pitch = getPitch();
|
||||
positionAndLookPacket.flags = 0x00;
|
||||
positionAndLookPacket.teleportId = 67;
|
||||
getPlayerConnection().sendPacket(positionAndLookPacket);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package fr.themode.minestom.entity.demo;
|
||||
|
||||
import fr.themode.minestom.entity.EntityCreature;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityRelativeMovePacket;
|
||||
|
||||
public class ChickenCreature extends EntityCreature {
|
||||
|
||||
@ -11,16 +10,13 @@ public class ChickenCreature extends EntityCreature {
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
onGround = true;
|
||||
|
||||
double speed = 0.075;
|
||||
double newPos = getZ() + speed;
|
||||
|
||||
EntityRelativeMovePacket entityRelativeMovePacket = new EntityRelativeMovePacket();
|
||||
entityRelativeMovePacket.entityId = getEntityId();
|
||||
entityRelativeMovePacket.deltaZ = (short) ((newPos * 32 - getZ() * 32) * 128);
|
||||
entityRelativeMovePacket.onGround = true;
|
||||
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(entityRelativeMovePacket));
|
||||
setZ(newPos);
|
||||
/*Player player = Main.getConnectionManager().getPlayer("TheMode911");
|
||||
if (player != null) {
|
||||
teleport(player.getX(), 5, player.getZ());
|
||||
}*/
|
||||
|
||||
move(0, 0, speed);
|
||||
}
|
||||
}
|
||||
|
@ -7,13 +7,13 @@ import fr.themode.minestom.net.packet.server.play.ChunkDataPacket;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class Chunk {
|
||||
|
||||
protected Set<EntityCreature> creatures = Collections.synchronizedSet(new HashSet<>());
|
||||
protected Set<Player> players = Collections.synchronizedSet(new HashSet<>());
|
||||
protected Set<EntityCreature> creatures = new CopyOnWriteArraySet<>();
|
||||
protected Set<Player> players = new CopyOnWriteArraySet<>();
|
||||
private int chunkX, chunkZ;
|
||||
private Biome biome;
|
||||
private HashMap<Short, Block> blocks = new HashMap<>();
|
||||
|
@ -22,12 +22,11 @@ public class Instance {
|
||||
|
||||
// TODO BlockBatch with pool
|
||||
public synchronized void setBlock(int x, int y, int z, Block block) {
|
||||
int chunkX = Math.floorDiv(x, 16);
|
||||
int chunkZ = Math.floorDiv(z, 16);
|
||||
final int chunkX = Math.floorDiv(x, 16);
|
||||
final int chunkZ = Math.floorDiv(z, 16);
|
||||
Chunk chunk = getChunk(chunkX, chunkZ);
|
||||
if (chunk == null) {
|
||||
chunk = new Chunk(Biome.VOID, chunkX, chunkZ);
|
||||
this.chunksSet.add(chunk);
|
||||
chunk = createChunk(Biome.VOID, chunkX, chunkZ);
|
||||
}
|
||||
synchronized (chunk) {
|
||||
chunk.setBlock(x % 16, y, z % 16, block);
|
||||
@ -59,7 +58,7 @@ public class Instance {
|
||||
}
|
||||
|
||||
if (entity instanceof EntityCreature) {
|
||||
// TODO based on distance with player
|
||||
// TODO based on distance with players
|
||||
getPlayers().forEach(p -> ((EntityCreature) entity).addViewer(p));
|
||||
} else if (entity instanceof Player) {
|
||||
getCreatures().forEach(entityCreature -> entityCreature.addViewer((Player) entity));
|
||||
@ -103,8 +102,8 @@ public class Instance {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
private Chunk createChunk(int chunkX, int chunkZ) {
|
||||
Chunk chunk = new Chunk(Biome.VOID, chunkX, chunkZ);
|
||||
private Chunk createChunk(Biome biome, int chunkX, int chunkZ) {
|
||||
Chunk chunk = new Chunk(biome, chunkX, chunkZ);
|
||||
this.chunksSet.add(chunk);
|
||||
return chunk;
|
||||
}
|
||||
|
@ -18,6 +18,14 @@ public class ConnectionManager {
|
||||
return Collections.unmodifiableCollection(players);
|
||||
}
|
||||
|
||||
public Player getPlayer(String username) {
|
||||
for (Player player : getOnlinePlayers()) {
|
||||
if (player.getUsername().equalsIgnoreCase(username))
|
||||
return player;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Is only used at LoginStartPacket#process
|
||||
public void createPlayer(UUID uuid, String username, PlayerConnection connection) {
|
||||
Player player = new Player(uuid, username, connection);
|
||||
|
@ -102,12 +102,13 @@ public class LoginStartPacket implements ClientPreplayPacket {
|
||||
playerInfoPacket.playerInfos.add(addPlayer);
|
||||
connection.sendPacket(playerInfoPacket);
|
||||
|
||||
for (int x = -2; x < 2; x++)
|
||||
for (int z = -2; z < 2; z++) {
|
||||
for (int x = -10; x < 10; x++)
|
||||
for (int z = -10; z < 10; z++) {
|
||||
// TODO test entity
|
||||
ChickenCreature chickenCreature = new ChickenCreature();
|
||||
chickenCreature.refreshPosition(0 + (double) x * 1, 5, 0 + (double) z * 1);
|
||||
instance.addEntity(chickenCreature);
|
||||
chickenCreature.setInstance(instance);
|
||||
//instance.addEntity(chickenCreature);
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,8 +13,10 @@ public class ClientPlayerPositionAndLookPacket implements ClientPlayPacket {
|
||||
@Override
|
||||
public void process(Player player) {
|
||||
boolean chunkTest = player.chunkTest(x, z);
|
||||
if (chunkTest)
|
||||
if (chunkTest) {
|
||||
player.teleport(player.getX(), player.getY(), player.getZ());
|
||||
return;
|
||||
}
|
||||
|
||||
player.refreshPosition(x, y, z);
|
||||
player.refreshView(yaw, pitch);
|
||||
|
@ -12,8 +12,10 @@ public class ClientPlayerPositionPacket implements ClientPlayPacket {
|
||||
@Override
|
||||
public void process(Player player) {
|
||||
boolean chunkTest = player.chunkTest(x, z);
|
||||
if (chunkTest)
|
||||
if (chunkTest) {
|
||||
player.teleport(player.getX(), player.getY(), player.getZ());
|
||||
return;
|
||||
}
|
||||
|
||||
player.refreshPosition(x, y, z);
|
||||
player.refreshOnGround(onGround);
|
||||
|
@ -16,7 +16,7 @@ public class EntityTeleportPacket implements ServerPacket {
|
||||
Utils.writeVarInt(buffer, entityId);
|
||||
buffer.putDouble(x);
|
||||
buffer.putDouble(y);
|
||||
buffer.putDouble(y);
|
||||
buffer.putDouble(z);
|
||||
buffer.putByte((byte) (this.yaw * 256 / 360));
|
||||
buffer.putByte((byte) (this.pitch * 256 / 360));
|
||||
buffer.putBoolean(onGround);
|
||||
|
Loading…
Reference in New Issue
Block a user