mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-26 10:01:36 +01:00
Update
This commit is contained in:
parent
4263a3965b
commit
bdde4af581
19
src/main/java/fr/themode/minestom/Viewable.java
Normal file
19
src/main/java/fr/themode/minestom/Viewable.java
Normal file
@ -0,0 +1,19 @@
|
||||
package fr.themode.minestom;
|
||||
|
||||
import fr.themode.minestom.entity.Player;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface Viewable {
|
||||
|
||||
void addViewer(Player player);
|
||||
|
||||
void removeViewer(Player player);
|
||||
|
||||
Set<Player> getViewers();
|
||||
|
||||
default boolean isViewer(Player player) {
|
||||
return getViewers().contains(player);
|
||||
}
|
||||
|
||||
}
|
13
src/main/java/fr/themode/minestom/bossbar/BarColor.java
Normal file
13
src/main/java/fr/themode/minestom/bossbar/BarColor.java
Normal file
@ -0,0 +1,13 @@
|
||||
package fr.themode.minestom.bossbar;
|
||||
|
||||
public enum BarColor {
|
||||
|
||||
PINK,
|
||||
BLUE,
|
||||
RED,
|
||||
GREEN,
|
||||
YELLOW,
|
||||
PURPLE,
|
||||
WHITE;
|
||||
|
||||
}
|
11
src/main/java/fr/themode/minestom/bossbar/BarDivision.java
Normal file
11
src/main/java/fr/themode/minestom/bossbar/BarDivision.java
Normal file
@ -0,0 +1,11 @@
|
||||
package fr.themode.minestom.bossbar;
|
||||
|
||||
public enum BarDivision {
|
||||
|
||||
SOLID,
|
||||
SEGMENT_6,
|
||||
SEGMENT_10,
|
||||
SEGMENT_12,
|
||||
SEGMENT_20;
|
||||
|
||||
}
|
138
src/main/java/fr/themode/minestom/bossbar/BossBar.java
Normal file
138
src/main/java/fr/themode/minestom/bossbar/BossBar.java
Normal file
@ -0,0 +1,138 @@
|
||||
package fr.themode.minestom.bossbar;
|
||||
|
||||
import fr.themode.minestom.Viewable;
|
||||
import fr.themode.minestom.chat.Chat;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.net.packet.server.play.BossBarPacket;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class BossBar implements Viewable {
|
||||
|
||||
private UUID uuid = UUID.randomUUID();
|
||||
private Set<Player> viewers = new CopyOnWriteArraySet<>();
|
||||
|
||||
private String title;
|
||||
private float progress;
|
||||
private BarColor color;
|
||||
private BarDivision division;
|
||||
private byte flags;
|
||||
|
||||
public BossBar(String title, BarColor color, BarDivision division) {
|
||||
this.title = Chat.rawText(title);
|
||||
this.color = color;
|
||||
this.division = division;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewer(Player player) {
|
||||
this.viewers.add(player);
|
||||
player.refreshAddBossbar(this);
|
||||
addToPlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewer(Player player) {
|
||||
this.viewers.remove(player);
|
||||
player.refreshRemoveBossbar(this);
|
||||
removeToPlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Player> getViewers() {
|
||||
return Collections.unmodifiableSet(viewers);
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = Chat.rawText(title);
|
||||
}
|
||||
|
||||
public float getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
public void setProgress(float progress) {
|
||||
this.progress = progress;
|
||||
updateProgress();
|
||||
}
|
||||
|
||||
public BarColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(BarColor color) {
|
||||
this.color = color;
|
||||
updateStyle();
|
||||
}
|
||||
|
||||
public BarDivision getDivision() {
|
||||
return division;
|
||||
}
|
||||
|
||||
public void setDivision(BarDivision division) {
|
||||
this.division = division;
|
||||
updateStyle();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
BossBarPacket bossBarPacket = new BossBarPacket();
|
||||
bossBarPacket.uuid = uuid;
|
||||
bossBarPacket.action = BossBarPacket.Action.REMOVE;
|
||||
sendPacket(bossBarPacket);
|
||||
// TODO remove bar from player class
|
||||
}
|
||||
|
||||
private void addToPlayer(Player player) {
|
||||
BossBarPacket bossBarPacket = new BossBarPacket();
|
||||
bossBarPacket.uuid = uuid;
|
||||
bossBarPacket.action = BossBarPacket.Action.ADD;
|
||||
bossBarPacket.title = title;
|
||||
bossBarPacket.health = progress;
|
||||
bossBarPacket.color = color;
|
||||
bossBarPacket.division = division;
|
||||
bossBarPacket.flags = flags;
|
||||
player.getPlayerConnection().sendPacket(bossBarPacket);
|
||||
}
|
||||
|
||||
private void removeToPlayer(Player player) {
|
||||
BossBarPacket bossBarPacket = new BossBarPacket();
|
||||
bossBarPacket.uuid = uuid;
|
||||
bossBarPacket.action = BossBarPacket.Action.REMOVE;
|
||||
player.getPlayerConnection().sendPacket(bossBarPacket);
|
||||
}
|
||||
|
||||
private void updateTitle() {
|
||||
BossBarPacket bossBarPacket = new BossBarPacket();
|
||||
bossBarPacket.uuid = uuid;
|
||||
bossBarPacket.action = BossBarPacket.Action.UPDATE_TITLE;
|
||||
bossBarPacket.title = title;
|
||||
sendPacket(bossBarPacket);
|
||||
}
|
||||
|
||||
private void updateProgress() {
|
||||
BossBarPacket bossBarPacket = new BossBarPacket();
|
||||
bossBarPacket.uuid = uuid;
|
||||
bossBarPacket.action = BossBarPacket.Action.UPDATE_HEALTH;
|
||||
bossBarPacket.health = progress;
|
||||
sendPacket(bossBarPacket);
|
||||
}
|
||||
|
||||
private void updateStyle() {
|
||||
BossBarPacket bossBarPacket = new BossBarPacket();
|
||||
bossBarPacket.uuid = uuid;
|
||||
bossBarPacket.action = BossBarPacket.Action.UPDATE_STYLE;
|
||||
bossBarPacket.color = color;
|
||||
sendPacket(bossBarPacket);
|
||||
}
|
||||
|
||||
private void sendPacket(BossBarPacket bossBarPacket) {
|
||||
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(bossBarPacket));
|
||||
}
|
||||
}
|
8
src/main/java/fr/themode/minestom/chat/Chat.java
Normal file
8
src/main/java/fr/themode/minestom/chat/Chat.java
Normal file
@ -0,0 +1,8 @@
|
||||
package fr.themode.minestom.chat;
|
||||
|
||||
public class Chat {
|
||||
|
||||
public static String rawText(String text) {
|
||||
return "{\"text\": \"" + text + "\"}";
|
||||
}
|
||||
}
|
@ -1,36 +1,81 @@
|
||||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.instance.Chunk;
|
||||
import fr.themode.minestom.instance.Instance;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Entity {
|
||||
public abstract class Entity {
|
||||
|
||||
private static AtomicInteger lastEntityId = new AtomicInteger();
|
||||
|
||||
// Metadata
|
||||
protected static final byte METADATA_BYTE = 0;
|
||||
protected static final byte METADATA_VARINT = 1;
|
||||
protected static final byte METADATA_FLOAT = 2;
|
||||
protected static final byte METADATA_STRING = 3;
|
||||
protected static final byte METADATA_CHAT = 4;
|
||||
protected static final byte METADATA_OPTCHAT = 5;
|
||||
protected static final byte METADATA_SLOT = 6;
|
||||
protected static final byte METADATA_BOOLEAN = 7;
|
||||
|
||||
protected Instance instance;
|
||||
protected double lastX, lastY, lastZ;
|
||||
protected double x, y, z;
|
||||
protected float yaw, pitch;
|
||||
private int id;
|
||||
// Metadata
|
||||
protected boolean onFire;
|
||||
protected UUID uuid;
|
||||
private boolean isActive; // False if entity has only been instanced without being added somewhere
|
||||
protected boolean crouched;
|
||||
private boolean shouldRemove;
|
||||
protected boolean UNUSED_METADATA;
|
||||
protected boolean sprinting;
|
||||
protected boolean swimming;
|
||||
protected boolean invisible;
|
||||
protected boolean glowing;
|
||||
protected boolean usingElytra;
|
||||
protected int air = 300;
|
||||
protected String customName = "";
|
||||
protected boolean customNameVisible;
|
||||
protected boolean silent;
|
||||
protected boolean noGravity;
|
||||
protected Pose pose = Pose.STANDING;
|
||||
private int entityType;
|
||||
private long lastUpdate;
|
||||
|
||||
public Entity() {
|
||||
public Entity(int entityType) {
|
||||
this.id = generateId();
|
||||
this.entityType = entityType;
|
||||
this.uuid = UUID.randomUUID();
|
||||
}
|
||||
|
||||
|
||||
private static int generateId() {
|
||||
return lastEntityId.incrementAndGet();
|
||||
}
|
||||
|
||||
public abstract void update();
|
||||
|
||||
public void tick() {
|
||||
if (shouldUpdate()) {
|
||||
update();
|
||||
this.lastUpdate = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
@ -56,6 +101,10 @@ public class Entity {
|
||||
instance.addEntity(this);
|
||||
}
|
||||
|
||||
public float getDistance(Entity entity) {
|
||||
return (float) Math.sqrt(Math.pow(entity.getX() - getX(), 2) + Math.pow(entity.getY() - getY(), 2) + Math.pow(entity.getZ() - getZ(), 2));
|
||||
}
|
||||
|
||||
public void refreshPosition(double x, double y, double z) {
|
||||
this.lastX = this.x;
|
||||
this.lastY = this.y;
|
||||
@ -91,10 +140,101 @@ public class Entity {
|
||||
return z;
|
||||
}
|
||||
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
this.shouldRemove = true;
|
||||
}
|
||||
|
||||
public Buffer getMetadataBuffer() {
|
||||
Buffer buffer = Buffer.create();
|
||||
fillMetadataIndex(buffer, 0);
|
||||
/*Utils.writeVarInt(buffer, 0);
|
||||
Utils.writeString(buffer, customName);
|
||||
buffer.putBoolean(silent);
|
||||
buffer.putBoolean(noGravity);
|
||||
Utils.writeVarInt(buffer, pose.ordinal());*/
|
||||
|
||||
// Chicken test
|
||||
/*buffer.putByte((byte) 0); // Hand states
|
||||
buffer.putFloat(10f); // Health
|
||||
Utils.writeVarInt(buffer, 0); // Potion effect color
|
||||
buffer.putBoolean(false); // Potion effect ambient
|
||||
Utils.writeVarInt(buffer, 0); // Arrow count in entity
|
||||
buffer.putByte((byte) 0); // (Insentient)
|
||||
buffer.putBoolean(false); // baby (Ageable)*/
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private void fillMetadataIndex(Buffer buffer, int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
fillStateMetadata(buffer);
|
||||
break;
|
||||
case 1:
|
||||
fillAirTickMetaData(buffer);
|
||||
break;
|
||||
case 2:
|
||||
fillCustomNameMetaData(buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void fillStateMetadata(Buffer buffer) {
|
||||
buffer.putByte((byte) 0);
|
||||
buffer.putByte(METADATA_BYTE);
|
||||
byte index0 = 0;
|
||||
if (onFire)
|
||||
index0 += 1;
|
||||
if (crouched)
|
||||
index0 += 2;
|
||||
if (UNUSED_METADATA)
|
||||
index0 += 4;
|
||||
if (sprinting)
|
||||
index0 += 8;
|
||||
if (swimming)
|
||||
index0 += 16;
|
||||
if (invisible)
|
||||
index0 += 32;
|
||||
if (glowing)
|
||||
index0 += 64;
|
||||
if (usingElytra)
|
||||
index0 += 128;
|
||||
buffer.putByte(index0);
|
||||
}
|
||||
|
||||
private void fillAirTickMetaData(Buffer buffer) {
|
||||
buffer.putByte((byte) 1);
|
||||
buffer.putByte(METADATA_VARINT);
|
||||
Utils.writeVarInt(buffer, air);
|
||||
}
|
||||
|
||||
private void fillCustomNameMetaData(Buffer buffer) {
|
||||
buffer.putByte((byte) 2);
|
||||
buffer.putByte(METADATA_CHAT);
|
||||
Utils.writeString(buffer, customName);
|
||||
}
|
||||
|
||||
private boolean shouldUpdate() {
|
||||
return (float) (System.currentTimeMillis() - lastUpdate) >= 50f * 0.9f; // Margin of error
|
||||
}
|
||||
|
||||
public enum Pose {
|
||||
STANDING,
|
||||
FALL_FLYING,
|
||||
SLEEPING,
|
||||
SWIMMING,
|
||||
SPIN_ATTACK,
|
||||
SNEAKING,
|
||||
DYING;
|
||||
}
|
||||
|
||||
protected boolean shouldRemove() {
|
||||
return shouldRemove;
|
||||
}
|
||||
|
@ -1,25 +1,20 @@
|
||||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.Viewable;
|
||||
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.packet.server.play.*;
|
||||
import fr.themode.minestom.net.player.PlayerConnection;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public abstract class EntityCreature extends LivingEntity {
|
||||
public abstract class EntityCreature extends LivingEntity implements Viewable {
|
||||
|
||||
private Set<Player> viewers = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
private int entityType;
|
||||
private Set<Player> viewers = new CopyOnWriteArraySet<>();
|
||||
|
||||
public EntityCreature(int entityType) {
|
||||
super();
|
||||
this.entityType = entityType;
|
||||
super(entityType);
|
||||
}
|
||||
|
||||
public void move(double x, double y, double z) {
|
||||
@ -56,6 +51,7 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
sendPacketToViewers(entityTeleportPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewer(Player player) {
|
||||
this.viewers.add(player);
|
||||
PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
@ -72,10 +68,15 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
spawnMobPacket.yaw = getYaw();
|
||||
spawnMobPacket.pitch = getPitch();
|
||||
spawnMobPacket.headPitch = 0;
|
||||
EntityMetaDataPacket entityMetaDataPacket = new EntityMetaDataPacket();
|
||||
entityMetaDataPacket.entityId = getEntityId();
|
||||
entityMetaDataPacket.data = getMetadataBuffer();
|
||||
playerConnection.sendPacket(entityPacket);
|
||||
playerConnection.sendPacket(spawnMobPacket);
|
||||
playerConnection.sendPacket(entityMetaDataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewer(Player player) {
|
||||
synchronized (viewers) {
|
||||
if (!viewers.contains(player))
|
||||
@ -85,15 +86,12 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendPacketToViewers(ServerPacket packet) {
|
||||
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(packet));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Player> getViewers() {
|
||||
return Collections.unmodifiableSet(viewers);
|
||||
}
|
||||
|
||||
public int getEntityType() {
|
||||
return entityType;
|
||||
protected void sendPacketToViewers(ServerPacket packet) {
|
||||
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(packet));
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.Main;
|
||||
import fr.themode.minestom.instance.Chunk;
|
||||
import fr.themode.minestom.instance.Instance;
|
||||
import fr.themode.minestom.instance.InstanceManager;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@ -11,43 +13,98 @@ public class EntityManager {
|
||||
|
||||
private static InstanceManager instanceManager = Main.getInstanceManager();
|
||||
|
||||
private ExecutorService objectsPool = Executors.newFixedThreadPool(2);
|
||||
private ExecutorService creaturesPool = Executors.newFixedThreadPool(2);
|
||||
private ExecutorService playersPool = Executors.newFixedThreadPool(2);
|
||||
|
||||
public void update() {
|
||||
for (Instance instance : instanceManager.getInstances()) {
|
||||
// TODO loop chunks and entities on it instead of individual (to have more non-blocking operation)
|
||||
|
||||
// Creatures
|
||||
for (EntityCreature creature : instance.getCreatures()) {
|
||||
creaturesPool.submit(() -> {
|
||||
boolean shouldRemove = creature.shouldRemove();
|
||||
if (!shouldRemove) {
|
||||
creature.update();
|
||||
}
|
||||
|
||||
if (creature.shouldRemove()) {
|
||||
instance.removeEntity(creature);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Players
|
||||
for (Player player : instance.getPlayers()) {
|
||||
playersPool.submit(() -> {
|
||||
boolean shouldRemove = player.shouldRemove();
|
||||
if (!shouldRemove) {
|
||||
player.update();
|
||||
}
|
||||
|
||||
if (player.shouldRemove()) {
|
||||
instance.removeEntity(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testTick2(instance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void testTick2(Instance instance) {
|
||||
for (Chunk chunk : instance.getChunks()) {
|
||||
Set<ObjectEntity> objects = chunk.getObjectEntities();
|
||||
Set<EntityCreature> creatures = chunk.getCreatures();
|
||||
Set<Player> players = chunk.getPlayers();
|
||||
|
||||
if (!objects.isEmpty()) {
|
||||
objectsPool.submit(() -> {
|
||||
for (ObjectEntity objectEntity : objects) {
|
||||
boolean shouldRemove = objectEntity.shouldRemove();
|
||||
if (!shouldRemove) {
|
||||
objectEntity.tick();
|
||||
}
|
||||
|
||||
if (objectEntity.shouldRemove()) {
|
||||
instance.removeEntity(objectEntity);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!creatures.isEmpty()) {
|
||||
creaturesPool.submit(() -> {
|
||||
for (EntityCreature creature : creatures) {
|
||||
boolean shouldRemove = creature.shouldRemove();
|
||||
if (!shouldRemove) {
|
||||
creature.tick();
|
||||
}
|
||||
|
||||
if (creature.shouldRemove()) {
|
||||
instance.removeEntity(creature);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!players.isEmpty()) {
|
||||
playersPool.submit(() -> {
|
||||
for (Player player : players) {
|
||||
boolean shouldRemove = player.shouldRemove();
|
||||
if (!shouldRemove) {
|
||||
player.tick();
|
||||
}
|
||||
|
||||
if (player.shouldRemove()) {
|
||||
instance.removeEntity(player);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void testTick(Instance instance) {
|
||||
// Creatures
|
||||
for (EntityCreature creature : instance.getCreatures()) {
|
||||
creaturesPool.submit(() -> {
|
||||
boolean shouldRemove = creature.shouldRemove();
|
||||
if (!shouldRemove) {
|
||||
creature.tick();
|
||||
}
|
||||
|
||||
if (creature.shouldRemove()) {
|
||||
instance.removeEntity(creature);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Players
|
||||
for (Player player : instance.getPlayers()) {
|
||||
playersPool.submit(() -> {
|
||||
boolean shouldRemove = player.shouldRemove();
|
||||
if (!shouldRemove) {
|
||||
player.tick();
|
||||
}
|
||||
|
||||
if (player.shouldRemove()) {
|
||||
instance.removeEntity(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
47
src/main/java/fr/themode/minestom/entity/ItemEntity.java
Normal file
47
src/main/java/fr/themode/minestom/entity/ItemEntity.java
Normal file
@ -0,0 +1,47 @@
|
||||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
|
||||
public class ItemEntity extends ObjectEntity {
|
||||
|
||||
private ItemStack itemStack;
|
||||
private boolean pickable = true;
|
||||
|
||||
public ItemEntity(ItemStack itemStack) {
|
||||
super(34);
|
||||
this.itemStack = itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Buffer getMetadataBuffer() {
|
||||
Buffer buffer = super.getMetadataBuffer();
|
||||
buffer.putByte((byte) 7);
|
||||
buffer.putByte(METADATA_SLOT);
|
||||
Utils.writeItemStack(buffer, itemStack);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getData() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public ItemStack getItemStack() {
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
public boolean isPickable() {
|
||||
return pickable;
|
||||
}
|
||||
|
||||
public void setPickable(boolean pickable) {
|
||||
this.pickable = pickable;
|
||||
}
|
||||
}
|
@ -2,25 +2,14 @@ package fr.themode.minestom.entity;
|
||||
|
||||
public abstract class LivingEntity extends Entity {
|
||||
|
||||
protected float yaw, pitch;
|
||||
protected boolean onGround;
|
||||
|
||||
public LivingEntity() {
|
||||
super();
|
||||
public LivingEntity(int entityType) {
|
||||
super(entityType);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
}
|
||||
|
53
src/main/java/fr/themode/minestom/entity/ObjectEntity.java
Normal file
53
src/main/java/fr/themode/minestom/entity/ObjectEntity.java
Normal file
@ -0,0 +1,53 @@
|
||||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.Viewable;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityMetaDataPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.SpawnObjectPacket;
|
||||
import fr.themode.minestom.net.player.PlayerConnection;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public abstract class ObjectEntity extends Entity implements Viewable {
|
||||
|
||||
private Set<Player> viewers = new CopyOnWriteArraySet<>();
|
||||
|
||||
public ObjectEntity(int entityType) {
|
||||
super(entityType);
|
||||
}
|
||||
|
||||
public abstract int getData();
|
||||
|
||||
@Override
|
||||
public void addViewer(Player player) {
|
||||
this.viewers.add(player);
|
||||
PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
|
||||
SpawnObjectPacket spawnObjectPacket = new SpawnObjectPacket();
|
||||
spawnObjectPacket.entityId = getEntityId();
|
||||
spawnObjectPacket.uuid = getUuid();
|
||||
spawnObjectPacket.type = getEntityType();
|
||||
spawnObjectPacket.x = getX();
|
||||
spawnObjectPacket.y = getY();
|
||||
spawnObjectPacket.z = getZ();
|
||||
spawnObjectPacket.yaw = getYaw();
|
||||
spawnObjectPacket.pitch = getPitch();
|
||||
spawnObjectPacket.data = getData();
|
||||
EntityMetaDataPacket entityMetaDataPacket = new EntityMetaDataPacket();
|
||||
entityMetaDataPacket.entityId = getEntityId();
|
||||
entityMetaDataPacket.data = getMetadataBuffer();
|
||||
playerConnection.sendPacket(spawnObjectPacket);
|
||||
playerConnection.sendPacket(entityMetaDataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewer(Player player) {
|
||||
this.viewers.remove(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Player> getViewers() {
|
||||
return Collections.unmodifiableSet(viewers);
|
||||
}
|
||||
}
|
@ -1,21 +1,24 @@
|
||||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.Main;
|
||||
import fr.themode.minestom.bossbar.BossBar;
|
||||
import fr.themode.minestom.chat.Chat;
|
||||
import fr.themode.minestom.instance.CustomBlock;
|
||||
import fr.themode.minestom.inventory.Inventory;
|
||||
import fr.themode.minestom.inventory.PlayerInventory;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.net.packet.server.play.*;
|
||||
import fr.themode.minestom.net.player.PlayerConnection;
|
||||
import fr.themode.minestom.utils.GroupedCollections;
|
||||
import fr.themode.minestom.utils.Position;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class Player extends LivingEntity {
|
||||
|
||||
private boolean isSneaking;
|
||||
private boolean isSprinting;
|
||||
|
||||
private long lastKeepAlive;
|
||||
|
||||
private String username;
|
||||
@ -30,8 +33,11 @@ public class Player extends LivingEntity {
|
||||
private Position targetBlockPosition;
|
||||
private long targetBlockTime;
|
||||
|
||||
private Set<BossBar> bossBars = new CopyOnWriteArraySet<>();
|
||||
|
||||
// TODO set proper UUID
|
||||
public Player(UUID uuid, String username, PlayerConnection playerConnection) {
|
||||
super(93); // TODO correct ?
|
||||
this.uuid = uuid;
|
||||
this.username = username;
|
||||
this.playerConnection = playerConnection;
|
||||
@ -51,11 +57,25 @@ public class Player extends LivingEntity {
|
||||
sendBlockBreakAnimation(targetBlockPosition, stage);// TODO send to all near players
|
||||
if (stage > 9) {
|
||||
instance.setBlock(targetBlockPosition.getX(), targetBlockPosition.getY(), targetBlockPosition.getZ(), (short) 0);
|
||||
testParticle(targetBlockPosition.getX() + 0.5f, targetBlockPosition.getY(), targetBlockPosition.getZ() + 0.5f);
|
||||
testParticle(targetBlockPosition.getX() + 0.5f, targetBlockPosition.getY(), targetBlockPosition.getZ() + 0.5f, targetCustomBlock.getType());
|
||||
resetTargetBlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Item pickup
|
||||
if (instance != null) {
|
||||
GroupedCollections<ObjectEntity> objectEntities = instance.getObjectEntities();
|
||||
for (ObjectEntity objectEntity : objectEntities) {
|
||||
if (objectEntity instanceof ItemEntity) {
|
||||
float distance = getDistance(objectEntity);
|
||||
if (distance <= 1) { // FIXME set correct value
|
||||
getInventory().addItemStack(((ItemEntity) objectEntity).getItemStack());
|
||||
objectEntity.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Multiplayer sync
|
||||
EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket();
|
||||
@ -81,7 +101,7 @@ public class Player extends LivingEntity {
|
||||
playerConnection.sendPacket(breakAnimationPacket);
|
||||
}
|
||||
|
||||
private void testParticle(float x, float y, float z) {
|
||||
private void testParticle(float x, float y, float z, int blockId) {
|
||||
ParticlePacket particlePacket = new ParticlePacket();
|
||||
particlePacket.particleId = 3; // Block particle
|
||||
particlePacket.longDistance = false;
|
||||
@ -93,11 +113,12 @@ public class Player extends LivingEntity {
|
||||
particlePacket.offsetZ = 0.55f;
|
||||
particlePacket.particleData = 0.25f;
|
||||
particlePacket.particleCount = 100;
|
||||
particlePacket.blockId = blockId;
|
||||
playerConnection.sendPacket(particlePacket);
|
||||
}
|
||||
|
||||
public void sendMessage(String message) {
|
||||
ChatMessagePacket chatMessagePacket = new ChatMessagePacket("{\"text\": \"" + message + "\"}", ChatMessagePacket.Position.CHAT);
|
||||
ChatMessagePacket chatMessagePacket = new ChatMessagePacket(Chat.rawText(message), ChatMessagePacket.Position.CHAT);
|
||||
playerConnection.sendPacket(chatMessagePacket);
|
||||
}
|
||||
|
||||
@ -162,6 +183,10 @@ public class Player extends LivingEntity {
|
||||
return targetCustomBlock;
|
||||
}
|
||||
|
||||
public Set<BossBar> getBossBars() {
|
||||
return Collections.unmodifiableSet(bossBars);
|
||||
}
|
||||
|
||||
public void openInventory(Inventory inventory) {
|
||||
if (inventory == null)
|
||||
throw new IllegalArgumentException("Inventory cannot be null, use Player#closeInventory() to close current");
|
||||
@ -207,11 +232,11 @@ public class Player extends LivingEntity {
|
||||
}
|
||||
|
||||
public void refreshSneaking(boolean sneaking) {
|
||||
isSneaking = sneaking;
|
||||
sneaking = sneaking;
|
||||
}
|
||||
|
||||
public void refreshSprinting(boolean sprinting) {
|
||||
isSprinting = sprinting;
|
||||
sprinting = sprinting;
|
||||
}
|
||||
|
||||
public void refreshKeepAlive(long lastKeepAlive) {
|
||||
@ -238,6 +263,14 @@ public class Player extends LivingEntity {
|
||||
this.targetBlockTime = 0;
|
||||
}
|
||||
|
||||
public void refreshAddBossbar(BossBar bossBar) {
|
||||
this.bossBars.add(bossBar);
|
||||
}
|
||||
|
||||
public void refreshRemoveBossbar(BossBar bossBar) {
|
||||
this.bossBars.remove(bossBar);
|
||||
}
|
||||
|
||||
public long getLastKeepAlive() {
|
||||
return lastKeepAlive;
|
||||
}
|
||||
|
@ -5,7 +5,79 @@ import java.util.Arrays;
|
||||
public enum Biome {
|
||||
|
||||
OCEAN(0),
|
||||
DEEP_OCEAN(24),
|
||||
FROZEN_OCEAN(10),
|
||||
DEEP_FROZEN_OCEAN(50),
|
||||
COLD_OCEAN(46),
|
||||
DEEP_COLD_OCEAN(49),
|
||||
LUKEWARM_OCEAN(45),
|
||||
DEEP_LUKEWARM_OCEAN(48),
|
||||
WARM_OCEAN(44),
|
||||
DEEP_WARM_OCEAN(47),
|
||||
RIVER(7),
|
||||
FROZEN_RIVER(11),
|
||||
BEACH(16),
|
||||
STONE_SHORE(25),
|
||||
SNOWY_BEACH(26),
|
||||
FOREST(4),
|
||||
WOODED_HILLS(18),
|
||||
FLOWER_FOREST(132),
|
||||
BIRCH_FOREST(27),
|
||||
BIRCH_FOREST_HILLS(28),
|
||||
TALL_BIRCH_FOREST(155),
|
||||
TALL_BIRCH_HILLS(156),
|
||||
DARK_FOREST(29),
|
||||
DARK_FOREST_HILLS(157),
|
||||
JUNGLE(21),
|
||||
JUNGLE_HILLS(22),
|
||||
MODIFIED_JUNGLE(149),
|
||||
JUNGLE_EDGE(23),
|
||||
MODIFIED_JUNGLE_EDGE(151),
|
||||
BAMBOO_JUNGLE(168),
|
||||
BAMBOO_JUNGLE_HILLS(169),
|
||||
TAIGA(5),
|
||||
TAIGA_HILLS(19),
|
||||
TAIGA_MOUNTAINS(133),
|
||||
SNOWY_TAIGA(30),
|
||||
SNOWY_TAIGA_HILLS(31),
|
||||
SNOWY_TAIGA_MOUNTAINS(158),
|
||||
GIANT_TREE_TAIGA(32),
|
||||
GIANT_TREE_TAIGA_HILLS(33),
|
||||
GIANT_SPRUCE_TAIGA(160),
|
||||
GIANT_SPRUCE_TAIGA_HILLS(161),
|
||||
MUSHROOM_FIELDS(14),
|
||||
MUSHROOM_FIELDS_SHORE(15),
|
||||
SWAMP(6),
|
||||
SWAMP_HILLS(134),
|
||||
SAVANA(35),
|
||||
SAVANA_PLATEAU(36),
|
||||
SHATTERED_SAVANA(163),
|
||||
SHATTERED_SAVANA_PLATEAU(164),
|
||||
PLAINS(1),
|
||||
SUNFLOWER_PLAINS(129),
|
||||
DESERT(2),
|
||||
DESERT_HILLS(17),
|
||||
DESERT_LAKES(130),
|
||||
SNOWY_TUNDRA(12),
|
||||
SNOWY_MOUNTAINS(13),
|
||||
ICE_SPIKES(140),
|
||||
MOUNTAINS(3),
|
||||
WOODED_MOUTAINS(34),
|
||||
GRAVELLY_MOUNTAINS(131),
|
||||
MODIFIED_GRAVELLY_MOUNTAINS(162),
|
||||
MOUNTAIN_EDGE(20),
|
||||
BADLANDS(37),
|
||||
BADLANDS_PLATEAU(39),
|
||||
MODIFIED_BADLANDS_PLATEAU(167),
|
||||
WOODED_BADLANDS_PLATEAU(38),
|
||||
MODIFIED_WOODED_BADLANDS_PLATEAU(166),
|
||||
ERODED_BADLANDS(165),
|
||||
NETHER(8),
|
||||
THE_END(9),
|
||||
SMALL_END_ISLANDS(40),
|
||||
END_MIDLANDS(41),
|
||||
END_HIGHLANDS(42),
|
||||
END_BARRENS(43),
|
||||
VOID(127);
|
||||
|
||||
private int id;
|
||||
|
@ -7,7 +7,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class BlockBatch {
|
||||
public class BlockBatch implements BlockModifier {
|
||||
|
||||
private static volatile ExecutorService batchesPool = Executors.newFixedThreadPool(2);
|
||||
|
||||
@ -19,12 +19,9 @@ public class BlockBatch {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setBlock(int x, int y, int z, short blockId) {
|
||||
final int chunkX = Math.floorDiv(x, 16);
|
||||
final int chunkZ = Math.floorDiv(z, 16);
|
||||
Chunk chunk = this.instance.getChunk(chunkX, chunkZ);
|
||||
if (chunk == null)
|
||||
chunk = this.instance.createChunk(Biome.VOID, chunkX, chunkZ);
|
||||
Chunk chunk = this.instance.getChunkAt(x, z);
|
||||
List<BlockData> blockData = this.data.getOrDefault(chunk, new ArrayList<>());
|
||||
|
||||
BlockData data = new BlockData();
|
||||
@ -38,6 +35,22 @@ public class BlockBatch {
|
||||
this.data.put(chunk, blockData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, String blockId) {
|
||||
Chunk chunk = this.instance.getChunkAt(x, z);
|
||||
List<BlockData> blockData = this.data.getOrDefault(chunk, new ArrayList<>());
|
||||
|
||||
BlockData data = new BlockData();
|
||||
data.x = x % 16;
|
||||
data.y = y;
|
||||
data.z = z % 16;
|
||||
data.blockIdentifier = blockId;
|
||||
|
||||
blockData.add(data);
|
||||
|
||||
this.data.put(chunk, blockData);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
for (Map.Entry<Chunk, List<BlockData>> entry : data.entrySet()) {
|
||||
Chunk chunk = entry.getKey();
|
||||
@ -57,9 +70,14 @@ public class BlockBatch {
|
||||
|
||||
private int x, y, z;
|
||||
private short blockId;
|
||||
private String blockIdentifier;
|
||||
|
||||
public void apply(Chunk chunk) {
|
||||
chunk.setBlock((byte) x, (byte) y, (byte) z, blockId);
|
||||
if (blockIdentifier == null) {
|
||||
chunk.setBlock((byte) x, (byte) y, (byte) z, blockId);
|
||||
} else {
|
||||
chunk.setBlock((byte) x, (byte) y, (byte) z, blockIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,13 +6,13 @@ import java.util.function.Supplier;
|
||||
|
||||
public class BlockManager {
|
||||
|
||||
private Map<Integer, CustomBlock> blocksInternalId = new HashMap<>();
|
||||
private Map<Short, CustomBlock> blocksInternalId = new HashMap<>();
|
||||
private Map<String, CustomBlock> blocksId = new HashMap<>();
|
||||
|
||||
public void registerBlock(Supplier<CustomBlock> blocks) {
|
||||
CustomBlock customBlock = blocks.get();
|
||||
String identifier = customBlock.getIdentifier();
|
||||
int id = customBlock.getId();
|
||||
short id = customBlock.getId();
|
||||
this.blocksInternalId.put(id, customBlock);
|
||||
this.blocksId.put(identifier, customBlock);
|
||||
}
|
||||
@ -21,7 +21,7 @@ public class BlockManager {
|
||||
return blocksId.get(identifier);
|
||||
}
|
||||
|
||||
public CustomBlock getBlock(int id) {
|
||||
public CustomBlock getBlock(short id) {
|
||||
return blocksInternalId.get(id);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
package fr.themode.minestom.instance;
|
||||
|
||||
public interface BlockModifier {
|
||||
|
||||
void setBlock(int x, int y, int z, short blockId);
|
||||
|
||||
void setBlock(int x, int y, int z, String blockId);
|
||||
}
|
@ -3,6 +3,7 @@ package fr.themode.minestom.instance;
|
||||
import fr.themode.minestom.Main;
|
||||
import fr.themode.minestom.entity.Entity;
|
||||
import fr.themode.minestom.entity.EntityCreature;
|
||||
import fr.themode.minestom.entity.ObjectEntity;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
@ -13,12 +14,13 @@ public class Chunk {
|
||||
|
||||
private static final int CHUNK_SIZE = 16 * 256 * 16;
|
||||
|
||||
protected Set<ObjectEntity> objectEntities = new CopyOnWriteArraySet<>();
|
||||
protected Set<EntityCreature> creatures = new CopyOnWriteArraySet<>();
|
||||
protected Set<Player> players = new CopyOnWriteArraySet<>();
|
||||
private int chunkX, chunkZ;
|
||||
private Biome biome;
|
||||
private short[] blocksId = new short[CHUNK_SIZE];
|
||||
private int[] customBlocks = new int[CHUNK_SIZE];
|
||||
private short[] customBlocks = new short[CHUNK_SIZE];
|
||||
|
||||
public Chunk(Biome biome, int chunkX, int chunkZ) {
|
||||
this.biome = biome;
|
||||
@ -29,9 +31,7 @@ public class Chunk {
|
||||
protected void setBlock(byte x, byte y, byte z, short blockId) {
|
||||
int index = getIndex(x, y, z);
|
||||
this.blocksId[index] = blockId;
|
||||
if (blockId == 0) {
|
||||
this.customBlocks[index] = 0;
|
||||
}
|
||||
this.customBlocks[index] = 0;
|
||||
}
|
||||
|
||||
protected void setBlock(byte x, byte y, byte z, String blockId) {
|
||||
@ -49,7 +49,7 @@ public class Chunk {
|
||||
}
|
||||
|
||||
public CustomBlock getCustomBlock(byte x, byte y, byte z) {
|
||||
int id = this.customBlocks[getIndex(x, y, z)];
|
||||
short id = this.customBlocks[getIndex(x, y, z)];
|
||||
return id != 0 ? Main.getBlockManager().getBlock(id) : null;
|
||||
}
|
||||
|
||||
@ -66,6 +66,12 @@ public class Chunk {
|
||||
return;
|
||||
this.creatures.add((EntityCreature) entity);
|
||||
}
|
||||
} else if (entity instanceof ObjectEntity) {
|
||||
synchronized (objectEntities) {
|
||||
if (this.objectEntities.contains(entity))
|
||||
return;
|
||||
this.objectEntities.add((ObjectEntity) entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,6 +84,10 @@ public class Chunk {
|
||||
synchronized (creatures) {
|
||||
this.creatures.remove(entity);
|
||||
}
|
||||
} else if (entity instanceof ObjectEntity) {
|
||||
synchronized (objectEntities) {
|
||||
this.objectEntities.remove(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,6 +107,10 @@ public class Chunk {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
public Set<ObjectEntity> getObjectEntities() {
|
||||
return Collections.unmodifiableSet(objectEntities);
|
||||
}
|
||||
|
||||
public Set<EntityCreature> getCreatures() {
|
||||
return Collections.unmodifiableSet(creatures);
|
||||
}
|
||||
|
71
src/main/java/fr/themode/minestom/instance/ChunkBatch.java
Normal file
71
src/main/java/fr/themode/minestom/instance/ChunkBatch.java
Normal file
@ -0,0 +1,71 @@
|
||||
package fr.themode.minestom.instance;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class ChunkBatch implements BlockModifier {
|
||||
|
||||
private static volatile ExecutorService batchesPool = Executors.newFixedThreadPool(3);
|
||||
|
||||
private Instance instance;
|
||||
private Chunk chunk;
|
||||
|
||||
private List<BlockData> dataList = new ArrayList<>();
|
||||
|
||||
public ChunkBatch(Instance instance, Chunk chunk) {
|
||||
this.instance = instance;
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, short blockId) {
|
||||
BlockData data = new BlockData();
|
||||
data.x = (byte) x;
|
||||
data.y = (byte) y;
|
||||
data.z = (byte) z;
|
||||
data.blockId = blockId;
|
||||
|
||||
this.dataList.add(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, String blockId) {
|
||||
BlockData data = new BlockData();
|
||||
data.x = (byte) x;
|
||||
data.y = (byte) y;
|
||||
data.z = (byte) z;
|
||||
data.blockIdentifier = blockId;
|
||||
|
||||
this.dataList.add(data);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
synchronized (chunk) {
|
||||
batchesPool.submit(() -> {
|
||||
for (BlockData data : dataList) {
|
||||
data.apply(chunk);
|
||||
}
|
||||
instance.sendChunkUpdate(chunk); // TODO partial chunk data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class BlockData {
|
||||
|
||||
private byte x, y, z;
|
||||
private short blockId;
|
||||
private String blockIdentifier;
|
||||
|
||||
public void apply(Chunk chunk) {
|
||||
if (blockIdentifier == null) {
|
||||
chunk.setBlock(x, y, z, blockId);
|
||||
} else {
|
||||
chunk.setBlock(x, y, z, blockIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package fr.themode.minestom.instance;
|
||||
|
||||
public abstract class ChunkGenerator {
|
||||
|
||||
public abstract void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ);
|
||||
|
||||
public abstract Biome getBiome(int chunkX, int chunkZ);
|
||||
|
||||
}
|
@ -4,14 +4,18 @@ import fr.themode.minestom.entity.Player;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* option to set the global as "global breaking" meaning that multiple players mining the same block will break it faster (cumulation)
|
||||
*/
|
||||
public abstract class CustomBlock {
|
||||
|
||||
private static final AtomicInteger idCounter = new AtomicInteger();
|
||||
|
||||
private int id;
|
||||
private short id;
|
||||
|
||||
public CustomBlock() {
|
||||
this.id = idCounter.incrementAndGet();
|
||||
this.id = (short) idCounter.incrementAndGet();
|
||||
}
|
||||
|
||||
public abstract short getType();
|
||||
@ -23,7 +27,7 @@ public abstract class CustomBlock {
|
||||
*/
|
||||
public abstract int getBreakDelay(Player player);
|
||||
|
||||
public int getId() {
|
||||
public short getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,37 @@
|
||||
package fr.themode.minestom.instance;
|
||||
|
||||
import fr.themode.minestom.Viewable;
|
||||
import fr.themode.minestom.entity.Entity;
|
||||
import fr.themode.minestom.entity.EntityCreature;
|
||||
import fr.themode.minestom.entity.ObjectEntity;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.net.packet.server.play.ChunkDataPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.DestroyEntitiesPacket;
|
||||
import fr.themode.minestom.utils.GroupedCollections;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class Instance {
|
||||
public class Instance implements BlockModifier {
|
||||
|
||||
private UUID uniqueId;
|
||||
|
||||
private GroupedCollections<ObjectEntity> objectEntities = new GroupedCollections<>(new CopyOnWriteArrayList<>());
|
||||
private GroupedCollections<EntityCreature> creatures = new GroupedCollections<>(new CopyOnWriteArrayList());
|
||||
private GroupedCollections<Player> players = new GroupedCollections<>(new CopyOnWriteArrayList());
|
||||
|
||||
private Set<Chunk> chunksSet = new CopyOnWriteArraySet<>(); // TODO change for a map with position as key and chunk as value
|
||||
private ChunkGenerator chunkGenerator;
|
||||
private Map<Long, Chunk> chunks = new ConcurrentHashMap<>();
|
||||
|
||||
public Instance(UUID uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setBlock(int x, int y, int z, short blockId) {
|
||||
Chunk chunk = getChunkAt(x, z);
|
||||
synchronized (chunk) {
|
||||
@ -33,6 +40,7 @@ public class Instance {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setBlock(int x, int y, int z, String blockId) {
|
||||
Chunk chunk = getChunkAt(x, z);
|
||||
synchronized (chunk) {
|
||||
@ -41,6 +49,11 @@ public class Instance {
|
||||
}
|
||||
}
|
||||
|
||||
public Chunk loadChunk(int chunkX, int chunkZ) {
|
||||
Chunk chunk = getChunk(chunkX, chunkZ);
|
||||
return chunk == null ? createChunk(chunkX, chunkZ) : chunk; // TODO load from file
|
||||
}
|
||||
|
||||
public short getBlockId(int x, int y, int z) {
|
||||
Chunk chunk = getChunkAt(x, z);
|
||||
return chunk.getBlockId((byte) (x % 16), (byte) y, (byte) (z % 16));
|
||||
@ -56,11 +69,7 @@ public class Instance {
|
||||
}
|
||||
|
||||
public Chunk getChunk(int chunkX, int chunkZ) {
|
||||
for (Chunk chunk : getChunks()) {
|
||||
if (chunk.getChunkX() == chunkX && chunk.getChunkZ() == chunkZ)
|
||||
return chunk;
|
||||
}
|
||||
return createChunk(Biome.VOID, chunkX, chunkZ); // TODO generation API
|
||||
return chunks.getOrDefault(getChunkKey(chunkX, chunkZ), null);
|
||||
}
|
||||
|
||||
public Chunk getChunkAt(double x, double z) {
|
||||
@ -69,8 +78,12 @@ public class Instance {
|
||||
return getChunk(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public Set<Chunk> getChunks() {
|
||||
return Collections.unmodifiableSet(chunksSet);
|
||||
public void setChunkGenerator(ChunkGenerator chunkGenerator) {
|
||||
this.chunkGenerator = chunkGenerator;
|
||||
}
|
||||
|
||||
public Collection<Chunk> getChunks() {
|
||||
return Collections.unmodifiableCollection(chunks.values());
|
||||
}
|
||||
|
||||
public void addEntity(Entity entity) {
|
||||
@ -79,9 +92,10 @@ public class Instance {
|
||||
lastInstance.removeEntity(entity);
|
||||
}
|
||||
|
||||
if (entity instanceof EntityCreature) {
|
||||
if (entity instanceof Viewable) {
|
||||
// TODO based on distance with players
|
||||
getPlayers().forEach(p -> ((EntityCreature) entity).addViewer(p));
|
||||
Viewable viewable = (Viewable) entity;
|
||||
getPlayers().forEach(p -> ((Viewable) entity).addViewer(p));
|
||||
} else if (entity instanceof Player) {
|
||||
Player player = (Player) entity;
|
||||
sendChunks(player);
|
||||
@ -97,15 +111,23 @@ public class Instance {
|
||||
if (entityInstance == null || entityInstance != this)
|
||||
return;
|
||||
|
||||
if (entity instanceof EntityCreature) {
|
||||
EntityCreature creature = (EntityCreature) entity;
|
||||
creature.getViewers().forEach(p -> creature.removeViewer(p));
|
||||
if (entity instanceof Viewable) {
|
||||
DestroyEntitiesPacket destroyEntitiesPacket = new DestroyEntitiesPacket();
|
||||
destroyEntitiesPacket.entityIds = new int[]{entity.getEntityId()};
|
||||
|
||||
Viewable viewable = (Viewable) entity;
|
||||
viewable.getViewers().forEach(p -> p.getPlayerConnection().sendPacket(destroyEntitiesPacket)); // TODO destroy batch
|
||||
viewable.getViewers().forEach(p -> viewable.removeViewer(p));
|
||||
}
|
||||
|
||||
Chunk chunk = getChunkAt(entity.getX(), entity.getZ());
|
||||
chunk.removeEntity(entity);
|
||||
}
|
||||
|
||||
public GroupedCollections<ObjectEntity> getObjectEntities() {
|
||||
return objectEntities;
|
||||
}
|
||||
|
||||
public GroupedCollections<EntityCreature> getCreatures() {
|
||||
return creatures;
|
||||
}
|
||||
@ -118,14 +140,25 @@ public class Instance {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
protected Chunk createChunk(Biome biome, int chunkX, int chunkZ) {
|
||||
protected Chunk createChunk(int chunkX, int chunkZ) {
|
||||
Biome biome = chunkGenerator != null ? chunkGenerator.getBiome(chunkX, chunkZ) : Biome.VOID;
|
||||
Chunk chunk = new Chunk(biome, chunkX, chunkZ);
|
||||
this.objectEntities.addCollection(chunk.objectEntities);
|
||||
this.creatures.addCollection(chunk.creatures);
|
||||
this.players.addCollection(chunk.players);
|
||||
this.chunksSet.add(chunk);
|
||||
this.chunks.put(getChunkKey(chunkX, chunkZ), chunk);
|
||||
if (chunkGenerator != null) {
|
||||
ChunkBatch chunkBatch = createChunkBatch(chunk);
|
||||
chunkGenerator.generateChunkData(chunkBatch, chunkX, chunkZ);
|
||||
chunkBatch.flush();
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
protected ChunkBatch createChunkBatch(Chunk chunk) {
|
||||
return new ChunkBatch(this, chunk);
|
||||
}
|
||||
|
||||
protected void sendChunkUpdate(Chunk chunk) {
|
||||
ChunkDataPacket chunkDataPacket = new ChunkDataPacket();
|
||||
chunkDataPacket.fullChunk = false; // TODO partial chunk data
|
||||
@ -141,4 +174,8 @@ public class Instance {
|
||||
player.getPlayerConnection().sendPacket(chunkDataPacket);
|
||||
}
|
||||
}
|
||||
|
||||
private long getChunkKey(int chunkX, int chunkZ) {
|
||||
return (((long) chunkX) << 32) | (chunkZ & 0xffffffffL);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package fr.themode.minestom.instance.demo;
|
||||
|
||||
import fr.themode.minestom.instance.Biome;
|
||||
import fr.themode.minestom.instance.ChunkBatch;
|
||||
import fr.themode.minestom.instance.ChunkGenerator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class ChunkGeneratorDemo extends ChunkGenerator {
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
@Override
|
||||
public void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ) {
|
||||
for (byte x = 0; x < 16; x++)
|
||||
for (byte z = 0; z < 16; z++) {
|
||||
if (random.nextInt(2) == 1) {
|
||||
batch.setBlock(x, (byte) 4, z, (short) 10);
|
||||
} else {
|
||||
batch.setBlock(x, (byte) 4, z, "custom_block");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int chunkX, int chunkZ) {
|
||||
return Biome.PLAINS;
|
||||
}
|
||||
}
|
@ -7,12 +7,12 @@ public class StoneBlock extends CustomBlock {
|
||||
|
||||
@Override
|
||||
public short getType() {
|
||||
return 1;
|
||||
return 117;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "stone_block";
|
||||
return "custom_block";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
package fr.themode.minestom.inventory;
|
||||
|
||||
import fr.themode.minestom.Viewable;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.net.packet.server.play.SetSlotPacket;
|
||||
@ -12,7 +13,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Inventory implements InventoryModifier, InventoryClickHandler {
|
||||
public class Inventory implements InventoryModifier, InventoryClickHandler, Viewable {
|
||||
|
||||
private static AtomicInteger lastInventoryId = new AtomicInteger();
|
||||
|
||||
@ -81,16 +82,19 @@ public class Inventory implements InventoryModifier, InventoryClickHandler {
|
||||
getViewers().forEach(p -> p.getPlayerConnection().sendPacket(windowItemsPacket));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Player> getViewers() {
|
||||
return Collections.unmodifiableSet(viewers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewer(Player player) {
|
||||
this.viewers.add(player);
|
||||
WindowItemsPacket windowItemsPacket = getWindowItemsPacket();
|
||||
player.getPlayerConnection().sendPacket(windowItemsPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewer(Player player) {
|
||||
this.viewers.remove(player);
|
||||
}
|
||||
|
@ -2,10 +2,15 @@ package fr.themode.minestom.net.packet.client.login;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.Main;
|
||||
import fr.themode.minestom.bossbar.BarColor;
|
||||
import fr.themode.minestom.bossbar.BarDivision;
|
||||
import fr.themode.minestom.bossbar.BossBar;
|
||||
import fr.themode.minestom.entity.GameMode;
|
||||
import fr.themode.minestom.entity.ItemEntity;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.entity.demo.ChickenCreature;
|
||||
import fr.themode.minestom.instance.Instance;
|
||||
import fr.themode.minestom.instance.demo.ChunkGeneratorDemo;
|
||||
import fr.themode.minestom.inventory.Inventory;
|
||||
import fr.themode.minestom.inventory.InventoryType;
|
||||
import fr.themode.minestom.inventory.PlayerInventory;
|
||||
@ -34,11 +39,17 @@ public class LoginStartPacket implements ClientPreplayPacket {
|
||||
private static Instance instance;
|
||||
|
||||
static {
|
||||
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
|
||||
instance = Main.getInstanceManager().createInstance();
|
||||
for (int x = -64; x < 64; x++)
|
||||
for (int z = -64; z < 64; z++) {
|
||||
instance.setBlock(x, 4, z, (short) 10);
|
||||
instance.setChunkGenerator(chunkGeneratorDemo);
|
||||
int loopStart = -4;
|
||||
int loopEnd = 4;
|
||||
long time = System.currentTimeMillis();
|
||||
for (int x = loopStart; x < loopEnd; x++)
|
||||
for (int z = loopStart; z < loopEnd; z++) {
|
||||
instance.loadChunk(x, z);
|
||||
}
|
||||
System.out.println("Time to load all chunks: " + (System.currentTimeMillis() - time) + " ms");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -106,7 +117,6 @@ public class LoginStartPacket implements ClientPreplayPacket {
|
||||
|
||||
for (int x = 0; x < 4; x++)
|
||||
for (int z = 0; z < 4; z++) {
|
||||
// TODO test entity
|
||||
ChickenCreature chickenCreature = new ChickenCreature();
|
||||
chickenCreature.refreshPosition(0 + (double) x * 1, 5, 0 + (double) z * 1);
|
||||
chickenCreature.setInstance(instance);
|
||||
@ -151,6 +161,18 @@ public class LoginStartPacket implements ClientPreplayPacket {
|
||||
player.openInventory(inv);
|
||||
inv.setItemStack(1, new ItemStack(1, (byte) 2));
|
||||
inv.updateItems();
|
||||
|
||||
BossBar bossBar = new BossBar("Le titre", BarColor.BLUE, BarDivision.SEGMENT_12);
|
||||
bossBar.setProgress(0.75f);
|
||||
bossBar.addViewer(player);
|
||||
|
||||
for (int x = 0; x < 4; x++)
|
||||
for (int z = 0; z < 4; z++) {
|
||||
ItemEntity itemEntity = new ItemEntity(new ItemStack(1, (byte) 32));
|
||||
itemEntity.refreshPosition(x, 5, z);
|
||||
itemEntity.setInstance(instance);
|
||||
//itemEntity.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,7 +25,7 @@ public class ClientPlayerBlockPlacementPacket implements ClientPlayPacket {
|
||||
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;
|
||||
|
||||
instance.setBlock(position.getX() + offsetX, position.getY() + offsetY, position.getZ() + offsetZ, "stone_block");
|
||||
instance.setBlock(position.getX() + offsetX, position.getY() + offsetY, position.getZ() + offsetZ, "custom_block");
|
||||
player.getInventory().refreshSlot(player.getHeldSlot());
|
||||
// TODO consume block in hand for survival players
|
||||
/*Random random = new Random();
|
||||
|
@ -0,0 +1,69 @@
|
||||
package fr.themode.minestom.net.packet.server.play;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.bossbar.BarColor;
|
||||
import fr.themode.minestom.bossbar.BarDivision;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BossBarPacket implements ServerPacket {
|
||||
|
||||
public UUID uuid;
|
||||
public Action action;
|
||||
|
||||
public String title;
|
||||
public float health;
|
||||
public BarColor color;
|
||||
public BarDivision division;
|
||||
public byte flags;
|
||||
|
||||
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
Utils.writeUuid(buffer, uuid);
|
||||
Utils.writeVarInt(buffer, action.ordinal());
|
||||
|
||||
switch (action) {
|
||||
case ADD:
|
||||
Utils.writeString(buffer, title);
|
||||
buffer.putFloat(health);
|
||||
Utils.writeVarInt(buffer, color.ordinal());
|
||||
Utils.writeVarInt(buffer, division.ordinal());
|
||||
buffer.putByte(flags);
|
||||
break;
|
||||
case REMOVE:
|
||||
|
||||
break;
|
||||
case UPDATE_HEALTH:
|
||||
buffer.putFloat(health);
|
||||
break;
|
||||
case UPDATE_TITLE:
|
||||
Utils.writeString(buffer, title);
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
Utils.writeVarInt(buffer, color.ordinal());
|
||||
Utils.writeVarInt(buffer, division.ordinal());
|
||||
break;
|
||||
case UPDATE_FLAGS:
|
||||
buffer.putByte(flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x0C;
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
ADD,
|
||||
REMOVE,
|
||||
UPDATE_HEALTH,
|
||||
UPDATE_TITLE,
|
||||
UPDATE_STYLE,
|
||||
UPDATE_FLAGS;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package fr.themode.minestom.net.packet.server.play;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
|
||||
public class DisplayScoreboardPacket implements ServerPacket {
|
||||
|
||||
public byte position;
|
||||
public String scoreName;
|
||||
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
buffer.putByte(position);
|
||||
Utils.writeString(buffer, scoreName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x42;
|
||||
}
|
||||
}
|
@ -7,10 +7,13 @@ import fr.themode.minestom.utils.Utils;
|
||||
public class EntityMetaDataPacket implements ServerPacket {
|
||||
|
||||
public int entityId;
|
||||
public Buffer data;
|
||||
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
Utils.writeVarInt(buffer, entityId);
|
||||
buffer.putBuffer(data);
|
||||
buffer.putByte((byte) 0xFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -12,7 +12,8 @@ public class ParticlePacket implements ServerPacket {
|
||||
public float offsetX, offsetY, offsetZ;
|
||||
public float particleData;
|
||||
public int particleCount;
|
||||
// TODO data
|
||||
|
||||
public int blockId;
|
||||
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
@ -26,7 +27,8 @@ public class ParticlePacket implements ServerPacket {
|
||||
buffer.putFloat(offsetZ);
|
||||
buffer.putFloat(particleData);
|
||||
buffer.putInt(particleCount);
|
||||
Utils.writeVarInt(buffer, 1);
|
||||
if (particleId == 3)
|
||||
Utils.writeVarInt(buffer, blockId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,28 @@
|
||||
package fr.themode.minestom.net.packet.server.play;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
|
||||
public class ScoreboardObjectivePacket implements ServerPacket {
|
||||
|
||||
public String objectiveName;
|
||||
public byte mode;
|
||||
public String objectiveValue;
|
||||
public int type;
|
||||
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
Utils.writeString(buffer, objectiveName);
|
||||
buffer.putByte(mode);
|
||||
if (mode == 0 || mode == 2) {
|
||||
Utils.writeString(buffer, objectiveValue);
|
||||
Utils.writeVarInt(buffer, type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x49;
|
||||
}
|
||||
}
|
@ -20,8 +20,7 @@ public class SpawnMobPacket implements ServerPacket {
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
Utils.writeVarInt(buffer, entityId);
|
||||
buffer.putLong(entityUuid.getMostSignificantBits());
|
||||
buffer.putLong(entityUuid.getLeastSignificantBits());
|
||||
Utils.writeUuid(buffer, entityUuid);
|
||||
Utils.writeVarInt(buffer, entityType);
|
||||
buffer.putDouble(x);
|
||||
buffer.putDouble(y);
|
||||
|
@ -0,0 +1,35 @@
|
||||
package fr.themode.minestom.net.packet.server.play;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SpawnObjectPacket implements ServerPacket {
|
||||
|
||||
public int entityId;
|
||||
public UUID uuid;
|
||||
public int type;
|
||||
public double x, y, z;
|
||||
public float yaw, pitch;
|
||||
public int data;
|
||||
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
Utils.writeVarInt(buffer, entityId);
|
||||
Utils.writeUuid(buffer, uuid);
|
||||
Utils.writeVarInt(buffer, type);
|
||||
buffer.putDouble(x);
|
||||
buffer.putDouble(y);
|
||||
buffer.putDouble(z);
|
||||
buffer.putFloat(yaw);
|
||||
buffer.putFloat(pitch);
|
||||
buffer.putInt(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x00;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package fr.themode.minestom.net.packet.server.play;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
|
||||
public class TeamsPacket implements ServerPacket {
|
||||
|
||||
public String teamName;
|
||||
public Action action;
|
||||
|
||||
public String teamDisplayName;
|
||||
public byte friendlyFlags;
|
||||
public String nameTagVisibility;
|
||||
public String collisionRule;
|
||||
public int teamColor;
|
||||
public String teamPrefix;
|
||||
public String teamSuffix;
|
||||
public int entityCount;
|
||||
public String[] entities;
|
||||
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
Utils.writeString(buffer, teamName);
|
||||
buffer.putByte((byte) action.ordinal());
|
||||
|
||||
switch (action) {
|
||||
case CREATE_TEAM:
|
||||
case UPDATE_TEAM_INFO:
|
||||
Utils.writeString(buffer, teamDisplayName);
|
||||
buffer.putByte(friendlyFlags);
|
||||
Utils.writeString(buffer, nameTagVisibility);
|
||||
Utils.writeString(buffer, collisionRule);
|
||||
Utils.writeVarInt(buffer, teamColor);
|
||||
Utils.writeString(buffer, teamPrefix);
|
||||
Utils.writeString(buffer, teamSuffix);
|
||||
break;
|
||||
case REMOVE_TEAM:
|
||||
|
||||
break;
|
||||
case ADD_PLAYERS_TEAM:
|
||||
case REMOVE_PLAYERS_TEAM:
|
||||
Utils.writeVarInt(buffer, entities.length);
|
||||
for (String entity : entities) {
|
||||
Utils.writeString(buffer, entity);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (action == Action.CREATE_TEAM) {
|
||||
Utils.writeVarInt(buffer, entities.length);
|
||||
for (String entity : entities) {
|
||||
Utils.writeString(buffer, entity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x4B;
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
CREATE_TEAM,
|
||||
REMOVE_TEAM,
|
||||
UPDATE_TEAM_INFO,
|
||||
ADD_PLAYERS_TEAM,
|
||||
REMOVE_PLAYERS_TEAM;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package fr.themode.minestom.net.packet.server.play;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
|
||||
public class UpdateScorePacket implements ServerPacket {
|
||||
|
||||
public String entityName;
|
||||
public byte action;
|
||||
public String objectiveName;
|
||||
public int value;
|
||||
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
Utils.writeString(buffer, entityName);
|
||||
buffer.putByte(action);
|
||||
Utils.writeString(buffer, objectiveName);
|
||||
if (action != 1) {
|
||||
Utils.writeVarInt(buffer, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x4C;
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import fr.themode.minestom.item.ItemStack;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Utils {
|
||||
@ -136,6 +137,11 @@ public class Utils {
|
||||
return new Position(x, y, z);
|
||||
}
|
||||
|
||||
public static void writeUuid(Buffer buffer, UUID uuid) {
|
||||
buffer.putLong(uuid.getMostSignificantBits());
|
||||
buffer.putLong(uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
public static void writeItemStack(Buffer buffer, ItemStack itemStack) {
|
||||
if (itemStack == null) {
|
||||
buffer.putBoolean(false);
|
||||
|
Loading…
Reference in New Issue
Block a user