diff --git a/src/main/java/net/minestom/server/UpdateManager.java b/src/main/java/net/minestom/server/UpdateManager.java
index a3fbac535..95858fe6b 100644
--- a/src/main/java/net/minestom/server/UpdateManager.java
+++ b/src/main/java/net/minestom/server/UpdateManager.java
@@ -9,9 +9,8 @@ import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.server.play.KeepAlivePacket;
-import net.minestom.server.thread.DefaultThreadProvider;
+import net.minestom.server.thread.PerInstanceThreadProvider;
import net.minestom.server.thread.ThreadProvider;
-import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.utils.thread.MinestomThread;
import net.minestom.server.utils.validate.Check;
@@ -25,7 +24,12 @@ public final class UpdateManager {
private ExecutorService mainUpdate = new MinestomThread(1, MinecraftServer.THREAD_NAME_MAIN_UPDATE);
private boolean stopRequested;
- private ThreadProvider threadProvider = new DefaultThreadProvider();
+ private ThreadProvider threadProvider;
+
+ {
+ threadProvider = new PerInstanceThreadProvider();
+ //threadProvider = new PerGroupChunkProvider();
+ }
/**
* Should only be created in MinecraftServer
@@ -46,6 +50,7 @@ public final class UpdateManager {
currentTime = System.nanoTime();
// Server tick
+ //long testTime = System.nanoTime();
threadProvider.start();
for (Instance instance : instanceManager.getInstances()) {
for (Chunk chunk : instance.getChunks()) {
@@ -53,6 +58,8 @@ public final class UpdateManager {
}
}
threadProvider.end();
+ threadProvider.update();
+ //System.out.println("time: " + (System.nanoTime() - testTime));
// Waiting players update
entityManager.updateWaitingPlayers();
diff --git a/src/main/java/net/minestom/server/entity/ItemEntity.java b/src/main/java/net/minestom/server/entity/ItemEntity.java
index 01743a618..4540ec3bb 100644
--- a/src/main/java/net/minestom/server/entity/ItemEntity.java
+++ b/src/main/java/net/minestom/server/entity/ItemEntity.java
@@ -145,24 +145,49 @@ public class ItemEntity extends ObjectEntity {
return 1;
}
+ /**
+ * Get the item stack on ground
+ *
+ * @return the item stack
+ */
public ItemStack getItemStack() {
return itemStack;
}
+ /**
+ * Change the item stack on ground
+ *
+ * @param itemStack the item stack
+ */
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack;
sendMetadataIndex(7); // Refresh the ItemStack for viewers
}
+ /**
+ * Get if the item is currently pickable
+ *
+ * {@link #setPickable(boolean)} needs to be true and the delay {@link #getPickupDelay()}
+ * to be long gone
+ *
+ * @return true if the item is pickable, false otherwise
+ */
public boolean isPickable() {
return pickable && (System.currentTimeMillis() - getSpawnTime() >= pickupDelay);
}
+ /**
+ * Make the item pickable
+ *
+ * @param pickable true to make the item pickable, false otherwise
+ */
public void setPickable(boolean pickable) {
this.pickable = pickable;
}
/**
+ * Get if the item is mergeable
+ *
* @return true if the entity is mergeable, false otherwise
*/
public boolean isMergeable() {
@@ -179,16 +204,28 @@ public class ItemEntity extends ObjectEntity {
this.mergeable = mergeable;
}
+ /**
+ * Get the merge range
+ *
+ * @return the merge range
+ */
public float getMergeRange() {
return mergeRange;
}
+ /**
+ * Change the merge range
+ *
+ * @param mergeRange the merge range
+ */
public void setMergeRange(float mergeRange) {
this.mergeRange = mergeRange;
}
/**
- * @return the pickup delay in milliseconds, defined by {@link #setPickupDelay(long, TimeUnit)}
+ * Get the pickup delay in milliseconds, defined by {@link #setPickupDelay(long, TimeUnit)}
+ *
+ * @return the pickup delay
*/
public long getPickupDelay() {
return pickupDelay;
diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java
index 4cd389c0f..2591da4cf 100644
--- a/src/main/java/net/minestom/server/entity/LivingEntity.java
+++ b/src/main/java/net/minestom/server/entity/LivingEntity.java
@@ -220,6 +220,8 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
/**
+ * Damage the entity by a value, the type of the damage also has to be specified
+ *
* @param type the damage type
* @param value the amount of damage
* @return true if damage has been applied, false if it didn't
@@ -348,7 +350,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
// Equipments
- public void syncEquipments(PlayerConnection connection) {
+ protected void syncEquipments(PlayerConnection connection) {
for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) {
final EntityEquipmentPacket entityEquipmentPacket = getEquipmentPacket(slot);
if (entityEquipmentPacket == null)
@@ -357,7 +359,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
}
- public void syncEquipments() {
+ protected void syncEquipments() {
for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) {
syncEquipment(slot);
}
diff --git a/src/main/java/net/minestom/server/entity/type/EntityBat.java b/src/main/java/net/minestom/server/entity/type/EntityBat.java
index a47c5cd55..7dce1bb10 100644
--- a/src/main/java/net/minestom/server/entity/type/EntityBat.java
+++ b/src/main/java/net/minestom/server/entity/type/EntityBat.java
@@ -34,10 +34,20 @@ public class EntityBat extends EntityCreature {
}
}
+ /**
+ * Get if the bat is hanging
+ *
+ * @return true if the bat is hanging, false otherwise
+ */
public boolean isHanging() {
return hanging;
}
+ /**
+ * Make the bat hanging or cancel
+ *
+ * @param hanging true to make the bat hanging, false otherwise
+ */
public void setHanging(boolean hanging) {
this.hanging = hanging;
}
diff --git a/src/main/java/net/minestom/server/entity/type/EntityBoat.java b/src/main/java/net/minestom/server/entity/type/EntityBoat.java
index 32b6fc2b9..5bba17117 100644
--- a/src/main/java/net/minestom/server/entity/type/EntityBoat.java
+++ b/src/main/java/net/minestom/server/entity/type/EntityBoat.java
@@ -4,17 +4,20 @@ import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
+import net.minestom.server.utils.validate.Check;
import java.util.function.Consumer;
public class EntityBoat extends ObjectEntity {
+ private BoatType boatType;
private boolean leftPaddleTurning;
private boolean rightPaddleTurning;
public EntityBoat(Position spawnPosition) {
super(EntityType.BOAT, spawnPosition);
setBoundingBox(1.375f, 0.5625f, 1.375f);
+ this.boatType = BoatType.OAK;
}
@Override
@@ -26,6 +29,7 @@ public class EntityBoat extends ObjectEntity {
public Consumer getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
+ fillMetadataIndex(packet, 10);
fillMetadataIndex(packet, 11);
fillMetadataIndex(packet, 12);
@@ -36,7 +40,11 @@ public class EntityBoat extends ObjectEntity {
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
super.fillMetadataIndex(packet, index);
- if (index == 11) {
+ if (index == 10) {
+ packet.writeByte((byte) 10);
+ packet.writeByte(METADATA_VARINT);
+ packet.writeVarInt(boatType.ordinal());
+ } else if (index == 11) {
packet.writeByte((byte) 11);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(leftPaddleTurning);
@@ -47,6 +55,26 @@ public class EntityBoat extends ObjectEntity {
}
}
+ /**
+ * Get the boat type
+ *
+ * @return the boat type
+ */
+ public BoatType getBoatType() {
+ return boatType;
+ }
+
+ /**
+ * Change the boat type
+ *
+ * @param boatType the new boat type
+ */
+ public void setBoatType(BoatType boatType) {
+ Check.notNull(boatType, "The boat type cannot be null");
+ this.boatType = boatType;
+ sendMetadataIndex(10);
+ }
+
public void refreshPaddle(boolean left, boolean right) {
this.leftPaddleTurning = left;
this.rightPaddleTurning = right;
@@ -54,4 +82,9 @@ public class EntityBoat extends ObjectEntity {
sendMetadataIndex(12);
}
+ public enum BoatType {
+ OAK, SPRUCE, BIRCH, JUNGLE, ACACIA, DARK_OAK
+ }
+
+
}
diff --git a/src/main/java/net/minestom/server/entity/type/EntityItemFrame.java b/src/main/java/net/minestom/server/entity/type/EntityItemFrame.java
new file mode 100644
index 000000000..79155e424
--- /dev/null
+++ b/src/main/java/net/minestom/server/entity/type/EntityItemFrame.java
@@ -0,0 +1,100 @@
+package net.minestom.server.entity.type;
+
+import net.minestom.server.entity.EntityType;
+import net.minestom.server.entity.ObjectEntity;
+import net.minestom.server.item.ItemStack;
+import net.minestom.server.network.packet.PacketWriter;
+import net.minestom.server.utils.Position;
+import net.minestom.server.utils.Rotation;
+import net.minestom.server.utils.item.ItemStackUtils;
+
+import java.util.function.Consumer;
+
+// FIXME: https://wiki.vg/Object_Data#Item_Frame_.28id_71.29
+// "You have to set both Orientation and Yaw/Pitch accordingly, otherwise it will not work."
+public class EntityItemFrame extends ObjectEntity {
+
+ private ItemFrameOrientation orientation;
+ private ItemStack itemStack;
+ private Rotation rotation;
+
+ public EntityItemFrame(Position spawnPosition, ItemFrameOrientation orientation) {
+ super(EntityType.ITEM_FRAME, spawnPosition);
+ this.orientation = orientation;
+ this.rotation = Rotation.NONE;
+ }
+
+ @Override
+ public Consumer getMetadataConsumer() {
+ return packet -> {
+ super.getMetadataConsumer().accept(packet);
+ fillMetadataIndex(packet, 7);
+ fillMetadataIndex(packet, 8);
+ };
+ }
+
+ @Override
+ protected void fillMetadataIndex(PacketWriter packet, int index) {
+ super.fillMetadataIndex(packet, index);
+ if (index == 7) {
+ packet.writeByte((byte) 7);
+ packet.writeByte(METADATA_SLOT);
+ packet.writeItemStack(ItemStackUtils.notNull(itemStack));
+ } else if (index == 8) {
+ packet.writeByte((byte) 8);
+ packet.writeByte(METADATA_VARINT);
+ packet.writeVarInt(rotation.ordinal());
+ }
+ }
+
+ @Override
+ public int getObjectData() {
+ return orientation.ordinal();
+ }
+
+ /**
+ * Get the item stack in the frame
+ *
+ * @return the item stack in the frame
+ */
+ public ItemStack getItemStack() {
+ return itemStack;
+ }
+
+ /**
+ * Change the item stack in the frame
+ *
+ * @param itemStack the new item stack in the frame
+ */
+ public void setItemStack(ItemStack itemStack) {
+ this.itemStack = itemStack;
+ sendMetadataIndex(7);
+ }
+
+ /**
+ * Get the item rotation
+ *
+ * @return the item rotation
+ */
+ public Rotation getRotation() {
+ return rotation;
+ }
+
+ /**
+ * Change the item rotation
+ *
+ * @param rotation the new item rotation
+ */
+ public void setRotation(Rotation rotation) {
+ this.rotation = rotation;
+ sendMetadataIndex(8);
+ }
+
+ /**
+ * Represent the orientation of the frame
+ */
+ public enum ItemFrameOrientation {
+ DOWN, UP, NORTH, SOUTH, WEST, EAST
+ }
+
+}
diff --git a/src/main/java/net/minestom/server/entity/type/EntityPig.java b/src/main/java/net/minestom/server/entity/type/EntityPig.java
index e992205a3..50690b409 100644
--- a/src/main/java/net/minestom/server/entity/type/EntityPig.java
+++ b/src/main/java/net/minestom/server/entity/type/EntityPig.java
@@ -34,10 +34,20 @@ public class EntityPig extends EntityCreature {
}
}
+ /**
+ * Get if the pig has a saddle
+ *
+ * @return true if the pig has a saddle, false otherwise
+ */
public boolean hasSaddle() {
return saddle;
}
+ /**
+ * Set a saddle to the pig
+ *
+ * @param saddle true to add a saddle, false to remove it
+ */
public void setSaddle(boolean saddle) {
this.saddle = saddle;
sendMetadataIndex(16);
diff --git a/src/main/java/net/minestom/server/entity/type/EntityPigZombie.java b/src/main/java/net/minestom/server/entity/type/EntityPigZombie.java
index dd6397d6e..cb79e4933 100644
--- a/src/main/java/net/minestom/server/entity/type/EntityPigZombie.java
+++ b/src/main/java/net/minestom/server/entity/type/EntityPigZombie.java
@@ -40,10 +40,20 @@ public class EntityPigZombie extends EntityCreature {
}
}
+ /**
+ * Get if the pig zombie is a baby
+ *
+ * @return true if it is a baby, false otherwise
+ */
public boolean isBaby() {
return baby;
}
+ /**
+ * Set the pig zombie a baby or adult
+ *
+ * @param baby true to make it a baby, false otherwise
+ */
public void setBaby(boolean baby) {
this.baby = baby;
sendMetadataIndex(15);
diff --git a/src/main/java/net/minestom/server/entity/type/EntitySpider.java b/src/main/java/net/minestom/server/entity/type/EntitySpider.java
index ea8cf6d8b..f2b214f39 100644
--- a/src/main/java/net/minestom/server/entity/type/EntitySpider.java
+++ b/src/main/java/net/minestom/server/entity/type/EntitySpider.java
@@ -34,10 +34,20 @@ public class EntitySpider extends EntityCreature {
}
}
+ /**
+ * Get if the spider is climbing
+ *
+ * @return true if the spider is climbing, false otherwise
+ */
public boolean isClimbing() {
return climbing;
}
+ /**
+ * Make the spider climbs
+ *
+ * @param climbing true to make the spider climbs, false otherwise
+ */
public void setClimbing(boolean climbing) {
this.climbing = climbing;
sendMetadataIndex(15);
diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java
index 0051792dc..1018881f0 100644
--- a/src/main/java/net/minestom/server/instance/InstanceContainer.java
+++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java
@@ -365,6 +365,15 @@ public class InstanceContainer extends Instance {
saveChunksToStorageFolder(callback);
}
+ /**
+ * Save the instance without callback
+ *
+ * @see #saveInstance(Runnable)
+ */
+ public void saveInstance() {
+ saveInstance(null);
+ }
+
@Override
public void saveChunkToStorageFolder(Chunk chunk, Runnable callback) {
Check.notNull(getStorageFolder(), "You cannot save the chunk if no StorageFolder has been defined");
diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java
index dfd98db8d..6f1455992 100644
--- a/src/main/java/net/minestom/server/inventory/Inventory.java
+++ b/src/main/java/net/minestom/server/inventory/Inventory.java
@@ -160,6 +160,16 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
return false;
}
+ @Override
+ public void clear() {
+ // Clear the item array
+ for (int i = 0; i < getSize(); i++) {
+ setItemStackInternal(i, ItemStack.getAirItem());
+ }
+ // Send the cleared inventory to viewers
+ update();
+ }
+
@Override
public ItemStack getItemStack(int slot) {
return itemStacks[slot];
@@ -286,6 +296,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
protected void setItemStackInternal(int slot, ItemStack itemStack) {
itemStacks[slot] = itemStack;
+ this.windowItemsBufferUpdated = false;
}
/**
@@ -606,11 +617,4 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
update(player);
}
}
-
- public void clear() {
- // TODO: optimize by sending whole inventory at once? (will need to change to setItemStackInternal)
- for (int i = 0; i < getSize(); i++) {
- setItemStack(i, ItemStack.getAirItem());
- }
- }
}
diff --git a/src/main/java/net/minestom/server/inventory/InventoryModifier.java b/src/main/java/net/minestom/server/inventory/InventoryModifier.java
index eede7e99a..31afc4606 100644
--- a/src/main/java/net/minestom/server/inventory/InventoryModifier.java
+++ b/src/main/java/net/minestom/server/inventory/InventoryModifier.java
@@ -26,6 +26,11 @@ public interface InventoryModifier {
*/
boolean addItemStack(ItemStack itemStack);
+ /**
+ * Clear the inventory
+ */
+ void clear();
+
/**
* Get the item at the specified slot
*
diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java
index 23775bfe6..27bda5169 100644
--- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java
+++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java
@@ -121,6 +121,16 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
return false;
}
+ @Override
+ public void clear() {
+ // Clear the item array
+ for (int i = 0; i < getSize(); i++) {
+ setItemStackInternal(i, ItemStack.getAirItem());
+ }
+ // Send the cleared inventory to the inventory's owner
+ update();
+ }
+
@Override
public int getSize() {
return INVENTORY_SIZE;
@@ -282,6 +292,10 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
//refreshSlot(slot);
}
+ protected void setItemStackInternal(int slot, ItemStack itemStack) {
+ items[slot] = itemStack;
+ }
+
/**
* Set an item from a packet slot
*
diff --git a/src/main/java/net/minestom/server/inventory/type/AnvilInventory.java b/src/main/java/net/minestom/server/inventory/type/AnvilInventory.java
index 5cfa8618f..7ef7f2aae 100644
--- a/src/main/java/net/minestom/server/inventory/type/AnvilInventory.java
+++ b/src/main/java/net/minestom/server/inventory/type/AnvilInventory.java
@@ -6,11 +6,28 @@ import net.minestom.server.inventory.InventoryType;
public class AnvilInventory extends Inventory {
+ private short repairCost;
+
public AnvilInventory(String title) {
super(InventoryType.ANVIL, title);
}
+ /**
+ * Get the anvil repair cost
+ *
+ * @return the repair cost
+ */
+ public short getRepairCost() {
+ return repairCost;
+ }
+
+ /**
+ * Set the anvil repair cost
+ *
+ * @param cost the new anvil repair cost
+ */
public void setRepairCost(short cost) {
+ this.repairCost = repairCost;
sendProperty(InventoryProperty.ANVIL_REPAIR_COST, cost);
}
}
diff --git a/src/main/java/net/minestom/server/inventory/type/BeaconInventory.java b/src/main/java/net/minestom/server/inventory/type/BeaconInventory.java
index 6904bcc23..4aefda2a6 100644
--- a/src/main/java/net/minestom/server/inventory/type/BeaconInventory.java
+++ b/src/main/java/net/minestom/server/inventory/type/BeaconInventory.java
@@ -7,19 +7,68 @@ import net.minestom.server.potion.PotionType;
public class BeaconInventory extends Inventory {
+ private short powerLevel;
+ private PotionType firstPotionEffect;
+ private PotionType secondPotionEffect;
+
public BeaconInventory(String title) {
super(InventoryType.BEACON, title);
}
+ /**
+ * Get the beacon power level
+ *
+ * @return the power level
+ */
+ public short getPowerLevel() {
+ return powerLevel;
+ }
+
+ /**
+ * Change the beacon power level
+ *
+ * @param powerLevel the new beacon power level
+ */
public void setPowerLevel(short powerLevel) {
+ this.powerLevel = powerLevel;
sendProperty(InventoryProperty.BEACON_POWER_LEVEL, powerLevel);
}
+ /**
+ * Get the first potion effect
+ *
+ * @return the first potion effect, can be null
+ */
+ public PotionType getFirstPotionEffect() {
+ return firstPotionEffect;
+ }
+
+ /**
+ * Change the first potion effect
+ *
+ * @param firstPotionEffect the new first potion effect, can be null
+ */
public void setFirstPotionEffect(PotionType firstPotionEffect) {
+ this.firstPotionEffect = firstPotionEffect;
sendProperty(InventoryProperty.BEACON_FIRST_POTION, (short) firstPotionEffect.getId());
}
+ /**
+ * Get the second potion effect
+ *
+ * @return the second potion effect, can be null
+ */
+ public PotionType getSecondPotionEffect() {
+ return secondPotionEffect;
+ }
+
+ /**
+ * Change the second potion effect
+ *
+ * @param secondPotionEffect the new second potion effect, can be null
+ */
public void setSecondPotionEffect(PotionType secondPotionEffect) {
+ this.secondPotionEffect = secondPotionEffect;
sendProperty(InventoryProperty.BEACON_SECOND_POTION, (short) secondPotionEffect.getId());
}
diff --git a/src/main/java/net/minestom/server/inventory/type/BrewingStandInventory.java b/src/main/java/net/minestom/server/inventory/type/BrewingStandInventory.java
index e35d0637f..7f9540e07 100644
--- a/src/main/java/net/minestom/server/inventory/type/BrewingStandInventory.java
+++ b/src/main/java/net/minestom/server/inventory/type/BrewingStandInventory.java
@@ -6,15 +6,48 @@ import net.minestom.server.inventory.InventoryType;
public class BrewingStandInventory extends Inventory {
+ private short brewTime;
+ private short fuelTime;
+
public BrewingStandInventory(String title) {
super(InventoryType.BREWING_STAND, title);
}
+ /**
+ * Get the brewing stand brew time
+ *
+ * @return the brew time in tick
+ */
+ public short getBrewTime() {
+ return brewTime;
+ }
+
+ /**
+ * Change the brew time
+ *
+ * @param brewTime the new brew time in tick
+ */
public void setBrewTime(short brewTime) {
+ this.brewTime = brewTime;
sendProperty(InventoryProperty.BREWING_STAND_BREW_TIME, brewTime);
}
+ /**
+ * Get the brewing stand fuel time
+ *
+ * @return the fuel time in tick
+ */
+ public short getFuelTime() {
+ return fuelTime;
+ }
+
+ /**
+ * Change the fuel time
+ *
+ * @param fuelTime the new fuel time in tick
+ */
public void setFuelTime(short fuelTime) {
+ this.fuelTime = fuelTime;
sendProperty(InventoryProperty.BREWING_STAND_FUEL_TIME, fuelTime);
}
diff --git a/src/main/java/net/minestom/server/inventory/type/EnchantmentTableInventory.java b/src/main/java/net/minestom/server/inventory/type/EnchantmentTableInventory.java
index 60f38d4f0..54453c4ad 100644
--- a/src/main/java/net/minestom/server/inventory/type/EnchantmentTableInventory.java
+++ b/src/main/java/net/minestom/server/inventory/type/EnchantmentTableInventory.java
@@ -1,11 +1,143 @@
package net.minestom.server.inventory.type;
import net.minestom.server.inventory.Inventory;
+import net.minestom.server.inventory.InventoryProperty;
import net.minestom.server.inventory.InventoryType;
+import net.minestom.server.item.Enchantment;
public class EnchantmentTableInventory extends Inventory {
+ private short[] levelRequirements = new short[EnchantmentSlot.values().length];
+ private short seed;
+ private short[] enchantmentShown = new short[EnchantmentSlot.values().length];
+ private short[] enchantmentLevel = new short[EnchantmentSlot.values().length];
+
public EnchantmentTableInventory(String title) {
super(InventoryType.ENCHANTMENT, title);
}
+
+ /**
+ * Get the level requirement in a slot
+ *
+ * @param enchantmentSlot the slot to check the level requirement
+ * @return the level requirement of the slot
+ */
+ public short getLevelRequirement(EnchantmentSlot enchantmentSlot) {
+ return levelRequirements[enchantmentSlot.ordinal()];
+ }
+
+ /**
+ * Set the level requirement of a slot
+ *
+ * @param enchantmentSlot the slot
+ * @param level the level
+ */
+ public void setLevelRequirement(EnchantmentSlot enchantmentSlot, short level) {
+ switch (enchantmentSlot) {
+ case TOP:
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_LEVEL_REQUIREMENT_TOP, level);
+ break;
+ case MIDDLE:
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_LEVEL_REQUIREMENT_MIDDLE, level);
+ break;
+ case BOTTOM:
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_LEVEL_REQUIREMENT_BOTTOM, level);
+ break;
+ }
+ this.levelRequirements[enchantmentSlot.ordinal()] = level;
+ }
+
+ /**
+ * Get the enchantment seed
+ *
+ * @return the enchantment seed
+ */
+ public short getSeed() {
+ return seed;
+ }
+
+ /**
+ * Set the enchantment seed
+ *
+ * @param seed the enchantment seed
+ */
+ public void setSeed(short seed) {
+ this.seed = seed;
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_SEED, seed);
+ }
+
+ /**
+ * Get the enchantment shown in a slot
+ *
+ * @param enchantmentSlot the enchantment slot
+ * @return the enchantment shown in the slot, null if it is hidden
+ */
+ public Enchantment getEnchantmentShown(EnchantmentSlot enchantmentSlot) {
+ final short id = enchantmentShown[enchantmentSlot.ordinal()];
+ if (id == -1)
+ return null;
+ return Enchantment.fromId(id);
+ }
+
+ /**
+ * Set the enchantment shown in a slot
+ *
+ * Can be set to null to hide it
+ *
+ * @param enchantmentSlot the enchantment slot
+ * @param enchantment the enchantment
+ */
+ public void setEnchantmentShown(EnchantmentSlot enchantmentSlot, Enchantment enchantment) {
+ final short id = enchantment == null ? -1 : (short) enchantment.getId();
+ switch (enchantmentSlot) {
+ case TOP:
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_ID_TOP, id);
+ break;
+ case MIDDLE:
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_ID_MIDDLE, id);
+ break;
+ case BOTTOM:
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_ID_BOTTOM, id);
+ break;
+ }
+ this.enchantmentShown[enchantmentSlot.ordinal()] = id;
+ }
+
+ /**
+ * Get the enchantment level shown on mouse hover
+ *
+ * @param enchantmentSlot the enchantment slot
+ * @return the level shown, -1 if no enchant
+ */
+ public short getEnchantmentLevel(EnchantmentSlot enchantmentSlot) {
+ return enchantmentLevel[enchantmentSlot.ordinal()];
+ }
+
+ /**
+ * Set the enchantment level shown on mouse hover
+ *
+ * Can be set to -1 if no enchant
+ *
+ * @param enchantmentSlot the enchantment slot
+ * @param level the level shown
+ */
+ public void setEnchantmentLevel(EnchantmentSlot enchantmentSlot, short level) {
+ switch (enchantmentSlot) {
+ case TOP:
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_LEVEL_TOP, level);
+ break;
+ case MIDDLE:
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_LEVEL_MIDDLE, level);
+ break;
+ case BOTTOM:
+ sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_LEVEL_BOTTOM, level);
+ break;
+ }
+ this.enchantmentLevel[enchantmentSlot.ordinal()] = level;
+ }
+
+ public enum EnchantmentSlot {
+ TOP, MIDDLE, BOTTOM
+ }
+
}
diff --git a/src/main/java/net/minestom/server/inventory/type/FurnaceInventory.java b/src/main/java/net/minestom/server/inventory/type/FurnaceInventory.java
index c7f8e6129..a7b37d89d 100644
--- a/src/main/java/net/minestom/server/inventory/type/FurnaceInventory.java
+++ b/src/main/java/net/minestom/server/inventory/type/FurnaceInventory.java
@@ -6,28 +6,58 @@ import net.minestom.server.inventory.InventoryType;
public class FurnaceInventory extends Inventory {
+ private short remainingFuelTick;
+ private short maximumFuelBurnTime;
+ private short progressArrow;
+ private short maximumProgress;
+
public FurnaceInventory(String title) {
super(InventoryType.FURNACE, title);
}
/**
- * Represent the amount of tick until the fire icon come empty`
+ * Represent the amount of tick until the fire icon come empty
+ *
+ * @return the amount of tick until the fire icon come empty
+ */
+ public short getRemainingFuelTick() {
+ return remainingFuelTick;
+ }
+
+ /**
+ * Represent the amount of tick until the fire icon come empty
*
* @param remainingFuelTick
*/
public void setRemainingFuelTick(short remainingFuelTick) {
+ this.remainingFuelTick = remainingFuelTick;
sendProperty(InventoryProperty.FURNACE_FIRE_ICON, remainingFuelTick);
}
+ public short getMaximumFuelBurnTime() {
+ return maximumFuelBurnTime;
+ }
+
public void setMaximumFuelBurnTime(short maximumFuelBurnTime) {
+ this.maximumFuelBurnTime = maximumFuelBurnTime;
sendProperty(InventoryProperty.FURNACE_MAXIMUM_FUEL_BURN_TIME, maximumFuelBurnTime);
}
+ public short getProgressArrow() {
+ return progressArrow;
+ }
+
public void setProgressArrow(short progressArrow) {
+ this.progressArrow = progressArrow;
sendProperty(InventoryProperty.FURNACE_PROGRESS_ARROW, progressArrow);
}
+ public short getMaximumProgress() {
+ return maximumProgress;
+ }
+
public void setMaximumProgress(short maximumProgress) {
+ this.maximumProgress = maximumProgress;
sendProperty(InventoryProperty.FURNACE_MAXIMUM_PROGRESS, maximumProgress);
}
}
diff --git a/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java b/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java
index 0286677b5..4812fe9e9 100644
--- a/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java
+++ b/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java
@@ -20,7 +20,7 @@ public class VillagerInventory extends Inventory {
public void addTrade(TradeListPacket.Trade trade) {
TradeListPacket.Trade[] oldTrades = getTrades();
- int length = oldTrades.length + 1;
+ final int length = oldTrades.length + 1;
TradeListPacket.Trade[] trades = new TradeListPacket.Trade[length];
System.arraycopy(oldTrades, 0, trades, 0, oldTrades.length);
trades[length] = trade;
@@ -30,7 +30,7 @@ public class VillagerInventory extends Inventory {
public void removeTrade(int index) {
TradeListPacket.Trade[] oldTrades = getTrades();
- int length = oldTrades.length - 1;
+ final int length = oldTrades.length - 1;
TradeListPacket.Trade[] trades = new TradeListPacket.Trade[length];
ArrayUtils.removeElement(trades, index);
this.tradeListPacket.trades = trades;
diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java
index 9f65cfcad..b0d5d99bf 100644
--- a/src/main/java/net/minestom/server/item/ItemStack.java
+++ b/src/main/java/net/minestom/server/item/ItemStack.java
@@ -596,6 +596,9 @@ public class ItemStack implements DataContainer {
if (material == Material.FIREWORK_ROCKET)
return new FireworkMeta();
+ if (material == Material.PLAYER_HEAD)
+ return new PlayerHeadMeta();
+
if (material == Material.LEATHER_HELMET ||
material == Material.LEATHER_CHESTPLATE ||
material == Material.LEATHER_LEGGINGS ||
diff --git a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java
index 0f496c68b..69843f476 100644
--- a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java
+++ b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java
@@ -82,6 +82,24 @@ public class CrossbowMeta implements ItemMeta {
return projectile3;
}
+ /**
+ * Get if the crossbow is currently charged
+ *
+ * @return true if the crossbow is charged, false otherwise
+ */
+ public boolean isCharged() {
+ return charged;
+ }
+
+ /**
+ * Make the bow charged or uncharged
+ *
+ * @param charged true to make the crossbow charged, false otherwise
+ */
+ public void setCharged(boolean charged) {
+ this.charged = charged;
+ }
+
@Override
public boolean hasNbt() {
return ItemStackUtils.isVisible(projectile1);
diff --git a/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java b/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java
new file mode 100644
index 000000000..97a50b83c
--- /dev/null
+++ b/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java
@@ -0,0 +1,38 @@
+package net.minestom.server.item.metadata;
+
+import net.minestom.server.entity.PlayerSkin;
+import org.jglrxavpok.hephaistos.nbt.NBTCompound;
+
+public class PlayerHeadMeta implements ItemMeta {
+
+ private String playerName;
+ private PlayerSkin playerSkin;
+
+ @Override
+ public boolean hasNbt() {
+ return playerSkin != null;
+ }
+
+ @Override
+ public boolean isSimilar(ItemMeta itemMeta) {
+ if (!(itemMeta instanceof PlayerHeadMeta))
+ return false;
+ final PlayerHeadMeta playerHeadMeta = (PlayerHeadMeta) itemMeta;
+ return playerHeadMeta.playerSkin == playerSkin;
+ }
+
+ @Override
+ public void read(NBTCompound compound) {
+
+ }
+
+ @Override
+ public void write(NBTCompound compound) {
+
+ }
+
+ @Override
+ public ItemMeta clone() {
+ return null;
+ }
+}
diff --git a/src/main/java/net/minestom/server/item/metadata/PotionMeta.java b/src/main/java/net/minestom/server/item/metadata/PotionMeta.java
index f48a278ab..a3b23c1fd 100644
--- a/src/main/java/net/minestom/server/item/metadata/PotionMeta.java
+++ b/src/main/java/net/minestom/server/item/metadata/PotionMeta.java
@@ -4,71 +4,56 @@ import net.minestom.server.potion.PotionType;
import net.minestom.server.registry.Registries;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
public class PotionMeta implements ItemMeta {
- private Set potionTypes = new HashSet<>();
+ private PotionType potionType;
/**
- * Get the item potion types
+ * Get the potion type
*
- * @return an unmodifiable {@link Set} containing the item potion types
+ * @return the potion type
*/
- public Set getPotionTypes() {
- return Collections.unmodifiableSet(potionTypes);
+ public PotionType getPotionType() {
+ return potionType;
}
/**
- * Add a potion type to the item
+ * Change the potion type
*
- * @param potionType the potion type to add
+ * @param potionType the new potion type
*/
- public void addPotionType(PotionType potionType) {
- this.potionTypes.add(potionType);
- }
-
- /**
- * Remove a potion type to the item
- *
- * @param potionType the potion type to remove
- */
- public void removePotionType(PotionType potionType) {
- this.potionTypes.remove(potionType);
+ public void setPotionType(PotionType potionType) {
+ this.potionType = potionType;
}
@Override
public boolean hasNbt() {
- return !potionTypes.isEmpty();
+ return potionType != null;
}
@Override
public boolean isSimilar(ItemMeta itemMeta) {
- return itemMeta instanceof PotionMeta && ((PotionMeta) itemMeta).potionTypes.equals(potionTypes);
+ return itemMeta instanceof PotionMeta && ((PotionMeta) itemMeta).potionType == potionType;
}
@Override
public void read(NBTCompound compound) {
if (compound.containsKey("Potion")) {
- addPotionType(Registries.getPotionType(compound.getString("Potion")));
+ this.potionType = Registries.getPotionType(compound.getString("Potion"));
}
}
@Override
public void write(NBTCompound compound) {
- if (!potionTypes.isEmpty()) {
- for (PotionType potionType : potionTypes) {
- compound.setString("Potion", potionType.getNamespaceID());
- }
+ if (potionType != null) {
+ compound.setString("Potion", potionType.getNamespaceID());
}
}
@Override
public ItemMeta clone() {
PotionMeta potionMeta = new PotionMeta();
- potionMeta.potionTypes.addAll(potionTypes);
+ potionMeta.potionType = potionType;
return potionMeta;
}
diff --git a/src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java b/src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java
new file mode 100644
index 000000000..9fafb9cb5
--- /dev/null
+++ b/src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java
@@ -0,0 +1,48 @@
+package net.minestom.server.item.metadata;
+
+import net.minestom.server.entity.EntityType;
+import org.jglrxavpok.hephaistos.nbt.NBTCompound;
+
+// TODO for which item
+public class SpawnEggMeta implements ItemMeta {
+
+ private EntityType entityType;
+
+ @Override
+ public boolean hasNbt() {
+ return entityType != null;
+ }
+
+ @Override
+ public boolean isSimilar(ItemMeta itemMeta) {
+ if (!(itemMeta instanceof SpawnEggMeta))
+ return false;
+ final SpawnEggMeta spawnEggMeta = (SpawnEggMeta) itemMeta;
+ return spawnEggMeta.entityType == entityType;
+ }
+
+ @Override
+ public void read(NBTCompound compound) {
+ if (compound.containsKey("EntityTag")) {
+
+ }
+ }
+
+ @Override
+ public void write(NBTCompound compound) {
+ if (!hasNbt())
+ return;
+ NBTCompound entityCompound = new NBTCompound();
+ if (entityType != null) {
+ entityCompound.setString("id", entityType.getNamespaceID());
+ }
+
+ }
+
+ @Override
+ public ItemMeta clone() {
+ SpawnEggMeta spawnEggMeta = new SpawnEggMeta();
+ spawnEggMeta.entityType = entityType;
+ return spawnEggMeta;
+ }
+}
diff --git a/src/main/java/net/minestom/server/storage/StorageFolder.java b/src/main/java/net/minestom/server/storage/StorageFolder.java
index a3360becc..d770fea2a 100644
--- a/src/main/java/net/minestom/server/storage/StorageFolder.java
+++ b/src/main/java/net/minestom/server/storage/StorageFolder.java
@@ -24,15 +24,15 @@ public class StorageFolder {
private Map cachedData;
- protected StorageFolder(StorageSystem storageSystem, String folderPath) {
+ protected StorageFolder(StorageSystem storageSystem, String folderPath, StorageOptions storageOptions) {
this.storageSystem = storageSystem;
this.folderPath = folderPath;
this.cachedData = new HashMap<>();
- this.storageSystem.open(folderPath);
+ this.storageSystem.open(folderPath, storageOptions);
}
-
+
public byte[] get(String key) {
return storageSystem.get(key);
}
diff --git a/src/main/java/net/minestom/server/storage/StorageManager.java b/src/main/java/net/minestom/server/storage/StorageManager.java
index 297872a36..ca872f0cd 100644
--- a/src/main/java/net/minestom/server/storage/StorageManager.java
+++ b/src/main/java/net/minestom/server/storage/StorageManager.java
@@ -23,16 +23,34 @@ public class StorageManager {
* WARNING: a storage folder needs to be created with an unique storage system linked
* you cannot open the save folder with two or more different StorageSystem implementation
*
- * @param folderPath the path to the folder
- * @param storageSystem the storage system used in the specified folder
+ * @param folderPath the path to the folder
+ * @param storageOptions the storage option
+ * @param storageSystem the storage system used in the specified folder
* @return the specified storage folder
*/
- public StorageFolder getFolder(String folderPath, StorageSystem storageSystem) {
+ public StorageFolder getFolder(String folderPath, StorageOptions storageOptions, StorageSystem storageSystem) {
+ Check.notNull(storageOptions, "The storage option cannot be null");
StorageFolder storageFolder =
- folderMap.computeIfAbsent(folderPath, s -> new StorageFolder(storageSystem, folderPath));
+ folderMap.computeIfAbsent(folderPath, s -> new StorageFolder(storageSystem, folderPath, storageOptions));
return storageFolder;
}
+ /**
+ * Used to get an access to the specified folder
+ * The default StorageSystem provider will be used
+ *
+ * @param folderPath the path to the folder
+ * @param storageOptions the storage option
+ * @return the specified storage default with the default
+ * @throws NullPointerException if no default StorageSystem is defined {@link #defineDefaultStorageSystem(Supplier)}
+ */
+ public StorageFolder getFolder(String folderPath, StorageOptions storageOptions) {
+ Check.notNull(defaultStorageSystemSupplier,
+ "You need to either define a default storage system or specify your storage system for this specific folder");
+ StorageSystem storageSystem = defaultStorageSystemSupplier.get();
+ return getFolder(folderPath, storageOptions, storageSystem);
+ }
+
/**
* Used to get an access to the specified folder
* The default StorageSystem provider will be used
@@ -42,11 +60,7 @@ public class StorageManager {
* @throws NullPointerException if no default StorageSystem is defined {@link #defineDefaultStorageSystem(Supplier)}
*/
public StorageFolder getFolder(String folderPath) {
- Check.notNull(defaultStorageSystemSupplier,
- "You need to either define a default storage system or specify your storage system for this specific folder");
-
- StorageSystem storageSystem = defaultStorageSystemSupplier.get();
- return getFolder(folderPath, storageSystem);
+ return getFolder(folderPath, new StorageOptions());
}
/**
@@ -71,7 +85,7 @@ public class StorageManager {
}
/**
- * Get all folders which have been loaded by {@link #getFolder(String)} or {@link #getFolder(String, StorageSystem)}
+ * Get all folders which have been loaded by {@link #getFolder(String)} or {@link #getFolder(String, StorageOptions, StorageSystem)}
*
* @return an unmodifiable list of all the loaded StorageFolder
*/
diff --git a/src/main/java/net/minestom/server/storage/StorageOptions.java b/src/main/java/net/minestom/server/storage/StorageOptions.java
new file mode 100644
index 000000000..2e63e99cb
--- /dev/null
+++ b/src/main/java/net/minestom/server/storage/StorageOptions.java
@@ -0,0 +1,26 @@
+package net.minestom.server.storage;
+
+public class StorageOptions {
+
+ private boolean compression;
+
+ /**
+ * Get if compression should be enabled
+ *
+ * @return true if compression should be enabled, false otherwise
+ */
+ public boolean hasCompression() {
+ return compression;
+ }
+
+ /**
+ * Define if the storage solution should use compression
+ *
+ * @param compression true to enable compression, false otherwise
+ * @return the reference to the current options
+ */
+ public StorageOptions setCompression(boolean compression) {
+ this.compression = compression;
+ return this;
+ }
+}
diff --git a/src/main/java/net/minestom/server/storage/StorageSystem.java b/src/main/java/net/minestom/server/storage/StorageSystem.java
index 0a9569f50..82f6f8714 100644
--- a/src/main/java/net/minestom/server/storage/StorageSystem.java
+++ b/src/main/java/net/minestom/server/storage/StorageSystem.java
@@ -11,9 +11,10 @@ public interface StorageSystem {
/**
* Called when a folder is opened with this StorageSystem
*
- * @param folderPath the name of the folder
+ * @param folderPath the name of the folder
+ * @param storageOptions the storage option
*/
- void open(String folderPath);
+ void open(String folderPath, StorageOptions storageOptions);
/**
* @param key
diff --git a/src/main/java/net/minestom/server/storage/systems/FileStorageSystem.java b/src/main/java/net/minestom/server/storage/systems/FileStorageSystem.java
index d8031adef..0bd3a6074 100644
--- a/src/main/java/net/minestom/server/storage/systems/FileStorageSystem.java
+++ b/src/main/java/net/minestom/server/storage/systems/FileStorageSystem.java
@@ -1,9 +1,8 @@
package net.minestom.server.storage.systems;
+import net.minestom.server.storage.StorageOptions;
import net.minestom.server.storage.StorageSystem;
-import org.rocksdb.Options;
-import org.rocksdb.RocksDB;
-import org.rocksdb.RocksDBException;
+import org.rocksdb.*;
import java.io.File;
@@ -25,9 +24,14 @@ public class FileStorageSystem implements StorageSystem {
}
@Override
- public void open(String folderPath) {
+ public void open(String folderPath, StorageOptions storageOptions) {
Options options = new Options().setCreateIfMissing(true);
+ if (storageOptions.hasCompression()) {
+ options.setCompressionType(CompressionType.ZSTD_COMPRESSION);
+ options.setCompressionOptions(new CompressionOptions().setLevel(1));
+ }
+
try {
this.rocksDB = RocksDB.open(options, folderPath);
} catch (RocksDBException e) {
diff --git a/src/main/java/net/minestom/server/thread/PerGroupChunkProvider.java b/src/main/java/net/minestom/server/thread/PerGroupChunkProvider.java
new file mode 100644
index 000000000..688d24d5e
--- /dev/null
+++ b/src/main/java/net/minestom/server/thread/PerGroupChunkProvider.java
@@ -0,0 +1,129 @@
+package net.minestom.server.thread;
+
+import net.minestom.server.instance.Chunk;
+import net.minestom.server.instance.Instance;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Separate chunks into group of linked chunks
+ *
+ * (1 chunks group = 1 thread execution)
+ */
+// FIXME: unusable at the moment, too much overhead because groups need to be created every tick
+// Should have a callback for when a chunk is loaded and unloaded, so groups are updated only once
+public class PerGroupChunkProvider extends ThreadProvider {
+
+ /**
+ * Here are stored all cached chunks waiting for a ChunkGroup
+ */
+ private Map> cachedChunks = new HashMap<>();
+
+ /**
+ * Used to know to which instance is linked a Set of chunks
+ */
+ private Map, Instance> instanceMap = new HashMap<>();
+
+ @Override
+ public void start() {
+ this.cachedChunks.clear();
+ this.instanceMap.clear();
+ }
+
+ @Override
+ public void linkThread(Instance instance, Chunk chunk) {
+ startChunkQuery(instance, chunk.getChunkX(), chunk.getChunkZ());
+ }
+
+ @Override
+ public void end() {
+
+ }
+
+ @Override
+ public void update() {
+ // The time of the tick
+ final long time = System.currentTimeMillis();
+
+ // Set of already-updated instances
+ final Set updatedInstance = new HashSet<>();
+
+ // Update all the chunks
+ for (Map.Entry, Instance> entry : instanceMap.entrySet()) {
+ Set chunks = entry.getKey();
+ Instance instance = entry.getValue();
+
+ final boolean updateInstance = updatedInstance.add(instance);
+ pool.execute(() -> {
+ /*if (updateInstance) {
+ updateInstance(instance, time);
+ }
+
+ for (Chunk chunk : chunks) {
+
+ updateChunk(instance, chunk, time);
+
+ updateEntities(instance, chunk, time);
+ }*/
+ });
+
+ }
+ }
+
+ /**
+ * Check the four chunk neighbors (up/down/left/right)
+ * and add them to the cache list
+ *
+ * @param instance the instance which is checked
+ * @param chunkX the chunk X
+ * @param chunkZ the chunk Z
+ */
+ private void startChunkQuery(Instance instance, int chunkX, int chunkZ) {
+ // Constants used to loop through the neighbors
+ final int[] posX = {1, 0, -1};
+ final int[] posZ = {1, 0, -1};
+
+ // The cache which will contain all the current chunk group
+ final Set cache = new HashSet<>();
+
+ for (int x : posX) {
+ for (int z : posZ) {
+
+ // No diagonal check
+ if ((Math.abs(x) + Math.abs(z)) == 2)
+ continue;
+
+ final int targetX = chunkX + x;
+ final int targetZ = chunkZ + z;
+
+ final Chunk chunk = instance.getChunk(targetX, targetZ);
+ if (cache.contains(chunk)) {
+ continue;
+ }
+
+ if (chunk != null) {
+ // If loaded, check if the chunk is already associated with a Set
+ if (cachedChunks.containsKey(chunk)) {
+ // Chunk is associated with a Set, add all them to the updated cache Set
+ Set oldCache = cachedChunks.get(chunk);
+ cache.addAll(oldCache);
+ this.instanceMap.remove(oldCache);
+ } else {
+ // Chunk is alone, add it to the cache list
+ cache.add(chunk);
+ }
+ }
+ }
+ }
+
+ // Add cached chunks into a cache list
+ for (Chunk cachedChunk : cache) {
+ this.cachedChunks.put(cachedChunk, cache);
+ }
+ this.instanceMap.put(cache, instance);
+ }
+
+}
diff --git a/src/main/java/net/minestom/server/thread/DefaultThreadProvider.java b/src/main/java/net/minestom/server/thread/PerInstanceThreadProvider.java
similarity index 74%
rename from src/main/java/net/minestom/server/thread/DefaultThreadProvider.java
rename to src/main/java/net/minestom/server/thread/PerInstanceThreadProvider.java
index 01738f217..baed22b9b 100644
--- a/src/main/java/net/minestom/server/thread/DefaultThreadProvider.java
+++ b/src/main/java/net/minestom/server/thread/PerInstanceThreadProvider.java
@@ -1,24 +1,17 @@
package net.minestom.server.thread;
-import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
-import net.minestom.server.utils.thread.MinestomThread;
import java.util.*;
-import java.util.concurrent.ExecutorService;
-public class DefaultThreadProvider extends ThreadProvider {
-
- private ExecutorService pool;
- private int threadCount;
+/**
+ * Separate work between instance (1 instance = 1 thread execution)
+ */
+public class PerInstanceThreadProvider extends ThreadProvider {
private Map groupMap = new HashMap<>();
- {
- setThreadCount(5);
- }
-
@Override
public void start() {
this.groupMap.clear();
@@ -28,14 +21,17 @@ public class DefaultThreadProvider extends ThreadProvider {
public void linkThread(Instance instance, Chunk chunk) {
InstanceChunk instanceChunk = new InstanceChunk(instance, chunk);
- GroupedInstanceChunk groupedInstanceChunk = groupMap.getOrDefault(instance, new GroupedInstanceChunk());
+ GroupedInstanceChunk groupedInstanceChunk = groupMap.computeIfAbsent(instance, inst -> new GroupedInstanceChunk());
groupedInstanceChunk.instanceChunks.add(instanceChunk);
-
- this.groupMap.put(instance, groupedInstanceChunk);
}
@Override
public void end() {
+
+ }
+
+ @Override
+ public void update() {
final long time = System.currentTimeMillis();
for (Map.Entry entry : groupMap.entrySet()) {
@@ -54,20 +50,6 @@ public class DefaultThreadProvider extends ThreadProvider {
}
});
}
-
- }
-
- public int getThreadCount() {
- return threadCount;
- }
-
- public synchronized void setThreadCount(int threadCount) {
- this.threadCount = threadCount;
- refreshPool();
- }
-
- private void refreshPool() {
- this.pool = new MinestomThread(threadCount, MinecraftServer.THREAD_NAME_TICK);
}
/**
diff --git a/src/main/java/net/minestom/server/thread/ThreadProvider.java b/src/main/java/net/minestom/server/thread/ThreadProvider.java
index 1d268ea20..326a32a23 100644
--- a/src/main/java/net/minestom/server/thread/ThreadProvider.java
+++ b/src/main/java/net/minestom/server/thread/ThreadProvider.java
@@ -1,17 +1,35 @@
package net.minestom.server.thread;
+import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.*;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
+import net.minestom.server.utils.thread.MinestomThread;
import java.util.Set;
+import java.util.concurrent.ExecutorService;
import java.util.function.Function;
/**
- * Used to link chunks to a certain thread
+ * Used to link chunks into multiple groups
+ * Then executed into a thread pool
*/
public abstract class ThreadProvider {
+ /**
+ * The thread pool of this thread provider
+ */
+ protected ExecutorService pool;
+ /**
+ * The amount of threads in the thread pool
+ */
+ private int threadCount;
+
+ {
+ // Default thread count in the pool
+ setThreadCount(5);
+ }
+
/**
* Called to prepare the thread provider, to provide threads for the next server tick
*/
@@ -27,11 +45,37 @@ public abstract class ThreadProvider {
/**
* Inform the server that all chunks have been assigned to a thread
- *
- * Should execute the server tick for all chunks based on their linked thread
*/
public abstract void end();
+ /**
+ * Perform a server tick for all chunks based on their linked thread
+ */
+ public abstract void update();
+
+ /**
+ * Get the current size of the thread pool
+ *
+ * @return the thread pool's size
+ */
+ public int getThreadCount() {
+ return threadCount;
+ }
+
+ /**
+ * Change the amount of threads in the thread pool
+ *
+ * @param threadCount the new amount of threads
+ */
+ public synchronized void setThreadCount(int threadCount) {
+ this.threadCount = threadCount;
+ refreshPool();
+ }
+
+ private void refreshPool() {
+ this.pool = new MinestomThread(threadCount, MinecraftServer.THREAD_NAME_TICK);
+ }
+
/**
* INSTANCE UPDATE
*/
diff --git a/src/main/java/net/minestom/server/utils/ArrayUtils.java b/src/main/java/net/minestom/server/utils/ArrayUtils.java
index 6c1034293..19750a5ea 100644
--- a/src/main/java/net/minestom/server/utils/ArrayUtils.java
+++ b/src/main/java/net/minestom/server/utils/ArrayUtils.java
@@ -34,10 +34,10 @@ public class ArrayUtils {
int[] indexes = new int[Math.max(a.length, b.length)];
for (int i = 0; i < a.length; i++) {
- long aValue = a[i];
+ final long aValue = a[i];
boolean contains = false;
for (int n = 0; n < b.length; n++) {
- long bValue = b[n];
+ final long bValue = b[n];
if (bValue == aValue) {
contains = true;
break;
diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java
index 06b657e46..0d26d5b90 100644
--- a/src/main/java/net/minestom/server/utils/NBTUtils.java
+++ b/src/main/java/net/minestom/server/utils/NBTUtils.java
@@ -136,15 +136,14 @@ public class NBTUtils {
if (nbt.containsKey("AttributeModifiers")) {
NBTList attributes = nbt.getList("AttributeModifiers");
for (NBTCompound attributeNBT : attributes) {
- // TODO: 1.16 changed how UUIDs are stored, is this part affected?
- long uuidMost = attributeNBT.getLong("UUIDMost");
- long uuidLeast = attributeNBT.getLong("UUIDLeast");
- UUID uuid = new UUID(uuidMost, uuidLeast);
- double value = attributeNBT.getDouble("Amount");
- String slot = attributeNBT.getString("Slot");
- String attributeName = attributeNBT.getString("AttributeName");
- int operation = attributeNBT.getInt("Operation");
- String name = attributeNBT.getString("Name");
+ final long uuidMost = attributeNBT.getLong("UUIDMost");
+ final long uuidLeast = attributeNBT.getLong("UUIDLeast");
+ final UUID uuid = new UUID(uuidMost, uuidLeast);
+ final double value = attributeNBT.getDouble("Amount");
+ final String slot = attributeNBT.getString("Slot");
+ final String attributeName = attributeNBT.getString("AttributeName");
+ final int operation = attributeNBT.getInt("Operation");
+ final String name = attributeNBT.getString("Name");
final Attribute attribute = Attribute.fromKey(attributeName);
// Wrong attribute name, stop here
diff --git a/src/main/java/net/minestom/server/utils/Rotation.java b/src/main/java/net/minestom/server/utils/Rotation.java
new file mode 100644
index 000000000..dc06913b6
--- /dev/null
+++ b/src/main/java/net/minestom/server/utils/Rotation.java
@@ -0,0 +1,57 @@
+package net.minestom.server.utils;
+
+public enum Rotation {
+
+ /**
+ * No rotation
+ */
+ NONE,
+ /**
+ * Rotated clockwise by 45 degrees
+ */
+ CLOCKWISE_45,
+ /**
+ * Rotated clockwise by 90 degrees
+ */
+ CLOCKWISE,
+ /**
+ * Rotated clockwise by 135 degrees
+ */
+ CLOCKWISE_135,
+ /**
+ * Flipped upside-down, a 180 degree rotation
+ */
+ FLIPPED,
+ /**
+ * Flipped upside-down + 45 degree rotation
+ */
+ FLIPPED_45,
+ /**
+ * Rotated counter-clockwise by 90 degrees
+ */
+ COUNTER_CLOCKWISE,
+ /**
+ * Rotated counter-clockwise by 45 degrees
+ */
+ COUNTER_CLOCKWISE_45;
+
+ private static final Rotation[] rotations = values();
+
+ /**
+ * Rotate clockwise by 90 degrees.
+ *
+ * @return the relative rotation
+ */
+ public Rotation rotateClockwise() {
+ return rotations[(this.ordinal() + 1) & 0x7];
+ }
+
+ /**
+ * Rotate counter-clockwise by 90 degrees.
+ *
+ * @return the relative rotation
+ */
+ public Rotation rotateCounterClockwise() {
+ return rotations[(this.ordinal() - 1) & 0x7];
+ }
+}
diff --git a/src/main/java/net/minestom/server/utils/SerializerUtils.java b/src/main/java/net/minestom/server/utils/SerializerUtils.java
index b2b0a5a33..a2bcfc8cd 100644
--- a/src/main/java/net/minestom/server/utils/SerializerUtils.java
+++ b/src/main/java/net/minestom/server/utils/SerializerUtils.java
@@ -7,9 +7,9 @@ public class SerializerUtils {
}
public static BlockPosition longToBlockPosition(long value) {
- int x = (int) (value >> 38);
- int y = (int) (value & 0xFFF);
- int z = (int) (value << 26 >> 38);
+ final int x = (int) (value >> 38);
+ final int y = (int) (value & 0xFFF);
+ final int z = (int) (value << 26 >> 38);
return new BlockPosition(x, y, z);
}