mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-01 05:58:00 +01:00
Merge branch 'master' of github.com:Minestom/Minestom
This commit is contained in:
commit
0f1f84db04
@ -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();
|
||||
|
@ -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
|
||||
* <p>
|
||||
* {@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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<PacketWriter> 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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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<PacketWriter> 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
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,11 @@ public interface InventoryModifier {
|
||||
*/
|
||||
boolean addItemStack(ItemStack itemStack);
|
||||
|
||||
/**
|
||||
* Clear the inventory
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Get the item at the specified slot
|
||||
*
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* 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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<PotionType> 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<PotionType> 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -24,15 +24,15 @@ public class StorageFolder {
|
||||
|
||||
private Map<String, SerializableData> 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);
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
* <p>
|
||||
* (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<Chunk, Set<Chunk>> cachedChunks = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Used to know to which instance is linked a Set of chunks
|
||||
*/
|
||||
private Map<Set<Chunk>, 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<Instance> updatedInstance = new HashSet<>();
|
||||
|
||||
// Update all the chunks
|
||||
for (Map.Entry<Set<Chunk>, Instance> entry : instanceMap.entrySet()) {
|
||||
Set<Chunk> 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<Chunk> 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<Chunk> 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);
|
||||
}
|
||||
|
||||
}
|
@ -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<Instance, GroupedInstanceChunk> 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<Instance, GroupedInstanceChunk> 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);
|
||||
}
|
||||
|
||||
/**
|
@ -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
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -136,15 +136,14 @@ public class NBTUtils {
|
||||
if (nbt.containsKey("AttributeModifiers")) {
|
||||
NBTList<NBTCompound> 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
|
||||
|
57
src/main/java/net/minestom/server/utils/Rotation.java
Normal file
57
src/main/java/net/minestom/server/utils/Rotation.java
Normal file
@ -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];
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user