Merge branch 'master' into new-block-api

# Conflicts:
#	src/main/java/net/minestom/server/item/ItemMetaBuilder.java
This commit is contained in:
TheMode 2021-07-01 02:22:20 +02:00
commit 5969ec1709
27 changed files with 348 additions and 190 deletions

View File

@ -108,16 +108,8 @@ public final class UpdateManager {
// Tick all instances
MinecraftServer.getInstanceManager().getInstances().forEach(instance ->
instance.tick(tickStart));
// Tick all chunks (and entities inside)
final CountDownLatch countDownLatch = threadProvider.update(tickStart);
// Wait tick end
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.threadProvider.updateAndAwait(tickStart);
// Clear removed entities & update threads
long tickTime = System.currentTimeMillis() - tickStart;

View File

@ -20,6 +20,8 @@ public interface Acquirable<T> {
* Gets all the {@link Entity entities} being ticked in the current thread.
* <p>
* Useful when you want to ensure that no acquisition is ever done.
* <p>
* Be aware that the entity stream is only updated at the beginning of the thread tick.
*
* @return the entities ticked in the current thread
*/

View File

@ -96,9 +96,18 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
protected Vector velocity = new Vector(); // Movement in block per second
protected boolean hasPhysics = true;
/**
* The amount of drag applied on the Y axle.
* <p>
* Unit: 1/tick
*/
protected double gravityDragPerTick;
/**
* Acceleration on the Y axle due to gravity
* <p>
* Unit: blocks/tick
*/
protected double gravityAcceleration;
protected double gravityTerminalVelocity;
protected int gravityTickCount; // Number of tick where gravity tick was applied
private boolean autoViewable;
@ -163,6 +172,8 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
Entity.ENTITY_BY_UUID.put(uuid, this);
this.eventNode = EventNode.value("entity-" + uuid, EventFilter.ENTITY, this::equals);
initializeDefaultGravity();
}
public Entity(@NotNull EntityType entityType) {
@ -528,13 +539,11 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
Vector newVelocityOut = new Vector();
// Gravity force
final double gravityY = !hasNoGravity() ? Math.min(
gravityDragPerTick + (gravityAcceleration * (double) gravityTickCount),
gravityTerminalVelocity) : 0;
final double gravityY = hasNoGravity() ? 0 : gravityAcceleration;
final Vector deltaPos = new Vector(
getVelocity().getX() / tps,
(getVelocity().getY() - gravityY) / tps,
getVelocity().getY() / tps - gravityY,
getVelocity().getZ() / tps
);
@ -577,6 +586,8 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
this.velocity.setX(velocity.getX() * drag);
this.velocity.setZ(velocity.getZ() * drag);
if (!hasNoGravity())
this.velocity.setY(velocity.getY() * (1-gravityDragPerTick));
if (velocity.equals(new Vector())) {
this.velocity.zero();
@ -966,15 +977,6 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
return gravityAcceleration;
}
/**
* Gets the maximum gravity velocity.
*
* @return the maximum gravity velocity in block
*/
public double getGravityTerminalVelocity() {
return gravityTerminalVelocity;
}
/**
* Gets the number of tick this entity has been applied gravity.
*
@ -989,13 +991,11 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
*
* @param gravityDragPerTick the gravity drag per tick in block
* @param gravityAcceleration the gravity acceleration in block
* @param gravityTerminalVelocity the gravity terminal velocity (maximum) in block
* @see <a href="https://minecraft.gamepedia.com/Entity#Motion_of_entities">Entities motion</a>
*/
public void setGravity(double gravityDragPerTick, double gravityAcceleration, double gravityTerminalVelocity) {
public void setGravity(double gravityDragPerTick, double gravityAcceleration) {
this.gravityDragPerTick = gravityDragPerTick;
this.gravityAcceleration = gravityAcceleration;
this.gravityTerminalVelocity = gravityTerminalVelocity;
}
/**
@ -1624,6 +1624,107 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
tag.write(nbtCompound, value);
}
/**
* Sets the Entity's {@link gravityAcceleration} and {@link gravityDragPerTick} fields to
* the default values according to <a href="https://minecraft.fandom.com/wiki/Entity#Motion_of_entities">Motion of entities</a>
*/
@SuppressWarnings("JavadocReference")
private void initializeDefaultGravity() {
// TODO Add support for these values in the data generator
// Acceleration
switch (entityType) {
// 0
case ITEM_FRAME:
this.gravityAcceleration = 0;
break;
// 0.03
case EGG:
case FISHING_BOBBER:
case EXPERIENCE_BOTTLE:
case ENDER_PEARL:
case POTION:
case SNOWBALL:
this.gravityAcceleration = 0.03;
break;
// 0.04
case BOAT:
case TNT:
case FALLING_BLOCK:
case ITEM:
case MINECART:
this.gravityAcceleration = 0.04;
break;
// 0.05
case ARROW:
case SPECTRAL_ARROW:
case TRIDENT:
this.gravityAcceleration = 0.05;
break;
// 0.06
case LLAMA_SPIT:
this.gravityAcceleration = 0.06;
break;
// 0.1
case FIREBALL:
case WITHER_SKULL:
case DRAGON_FIREBALL:
this.gravityAcceleration = 0.1;
break;
// 0.08
default:
this.gravityAcceleration = 0.08;
break;
}
// Drag
switch (entityType) {
// 0
case BOAT:
this.gravityDragPerTick = 0;
break;
// 0.01
case LLAMA_SPIT:
case ENDER_PEARL:
case POTION:
case SNOWBALL:
case EGG:
case TRIDENT:
case SPECTRAL_ARROW:
case ARROW:
this.gravityDragPerTick = 0.01;
break;
// 0.05
case MINECART:
this.gravityDragPerTick = 0.05;
break;
// 0.08
case FISHING_BOBBER:
this.gravityDragPerTick = 0.08;
break;
// 0.02
default:
this.gravityDragPerTick = 0.02;
break;
}
}
/**
* Applies knockback to the entity
*
* @param strength the strength of the knockback, 0.4 is the vanilla value for a bare hand hit
* @param x knockback on x axle, for default knockback use the following formula <pre>sin(attacker.yaw * (pi/180))</pre>
* @param z knockback on z axle, for default knockback use the following formula <pre>-cos(attacker.yaw * (pi/180))</pre>
*/
public void takeKnockback(final float strength, final double x, final double z) {
if (strength > 0) {
//TODO check possible side effects of unnatural TPS (other than 20TPS)
final Vector velocityModifier = new Vector(x, 0d, z).normalize().multiply(strength * MinecraftServer.TICK_PER_SECOND / 2);
this.velocity.setX(velocity.getX() / 2d - velocityModifier.getX());
this.velocity.setY(onGround ? Math.min(.4d, velocity.getY() / 2d + strength) * MinecraftServer.TICK_PER_SECOND : velocity.getY());
this.velocity.setZ(velocity.getZ() / 2d - velocityModifier.getZ());
}
}
public enum Pose {
STANDING,
FALL_FLYING,

View File

@ -47,7 +47,6 @@ public class EntityProjectile extends Entity {
if (getEntityMeta() instanceof ProjectileMeta) {
((ProjectileMeta) getEntityMeta()).setShooter(this.shooter);
}
setGravity(0.02f, 0.04f, 1.96f);
}
@Nullable

View File

@ -17,7 +17,6 @@ public class ExperienceOrb extends Entity {
public ExperienceOrb(short experienceCount, @NotNull Position spawnPosition) {
super(EntityType.EXPERIENCE_ORB, spawnPosition);
setGravity(0.02f, 0.04f, 1.96f);
setBoundingBox(0.5f, 0.5f, 0.5f);
//todo vanilla sets random velocity here?
this.experienceCount = experienceCount;

View File

@ -43,7 +43,6 @@ public class ItemEntity extends Entity {
public ItemEntity(@NotNull ItemStack itemStack, @NotNull Position spawnPosition) {
super(EntityType.ITEM, spawnPosition);
setItemStack(itemStack);
setGravity(0.02f, 0.04f, 1.96f);
setBoundingBox(0.25f, 0.25f, 0.25f);
}

View File

@ -90,7 +90,6 @@ public class LivingEntity extends Entity implements EquipmentHandler {
*/
public LivingEntity(@NotNull EntityType entityType, @NotNull UUID uuid) {
this(entityType, uuid, new Position());
setGravity(0.02f, 0.08f, 3.92f);
initEquipments();
}
@ -104,7 +103,6 @@ public class LivingEntity extends Entity implements EquipmentHandler {
@Deprecated
public LivingEntity(@NotNull EntityType entityType, @NotNull UUID uuid, @NotNull Position spawnPosition) {
super(entityType, uuid, spawnPosition);
setGravity(0.02f, 0.08f, 3.92f);
initEquipments();
}
@ -781,4 +779,18 @@ public class LivingEntity extends Entity implements EquipmentHandler {
return null;
}
/**
* Applies knockback
* <p>
* Note: The strength is reduced based on knockback resistance
*
* @param strength the strength of the knockback, 0.4 is the vanilla value for a bare hand hit
* @param x knockback on x axle, for default knockback use the following formula <pre>sin(attacker.yaw * (pi/180))</pre>
* @param z knockback on z axle, for default knockback use the following formula <pre>-cos(attacker.yaw * (pi/180))</pre>
*/
@Override
public void takeKnockback(float strength, final double x, final double z) {
strength *= 1 - getAttributeValue(Attribute.KNOCKBACK_RESISTANCE);
super.takeKnockback(strength, x, z);
}
}

View File

@ -1,14 +1,20 @@
package net.minestom.server.inventory.type;
import net.kyori.adventure.text.Component;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryProperty;
import net.minestom.server.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
public class AnvilInventory extends Inventory {
private short repairCost;
public AnvilInventory(String title) {
public AnvilInventory(@NotNull Component title) {
super(InventoryType.ANVIL, title);
}
public AnvilInventory(@NotNull String title) {
super(InventoryType.ANVIL, title);
}

View File

@ -1,9 +1,11 @@
package net.minestom.server.inventory.type;
import net.kyori.adventure.text.Component;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryProperty;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.potion.PotionEffect;
import org.jetbrains.annotations.NotNull;
public class BeaconInventory extends Inventory {
@ -11,7 +13,11 @@ public class BeaconInventory extends Inventory {
private PotionEffect firstPotionEffect;
private PotionEffect secondPotionEffect;
public BeaconInventory(String title) {
public BeaconInventory(@NotNull Component title) {
super(InventoryType.BEACON, title);
}
public BeaconInventory(@NotNull String title) {
super(InventoryType.BEACON, title);
}

View File

@ -1,15 +1,21 @@
package net.minestom.server.inventory.type;
import net.kyori.adventure.text.Component;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryProperty;
import net.minestom.server.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
public class BrewingStandInventory extends Inventory {
private short brewTime;
private short fuelTime;
public BrewingStandInventory(String title) {
public BrewingStandInventory(@NotNull Component title) {
super(InventoryType.BREWING_STAND, title);
}
public BrewingStandInventory(@NotNull String title) {
super(InventoryType.BREWING_STAND, title);
}

View File

@ -1,9 +1,11 @@
package net.minestom.server.inventory.type;
import net.kyori.adventure.text.Component;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryProperty;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.item.Enchantment;
import org.jetbrains.annotations.NotNull;
public class EnchantmentTableInventory extends Inventory {
@ -12,7 +14,11 @@ public class EnchantmentTableInventory extends Inventory {
private final short[] enchantmentShown = new short[EnchantmentSlot.values().length];
private final short[] enchantmentLevel = new short[EnchantmentSlot.values().length];
public EnchantmentTableInventory(String title) {
public EnchantmentTableInventory(@NotNull Component title) {
super(InventoryType.ENCHANTMENT, title);
}
public EnchantmentTableInventory(@NotNull String title) {
super(InventoryType.ENCHANTMENT, title);
}

View File

@ -1,8 +1,10 @@
package net.minestom.server.inventory.type;
import net.kyori.adventure.text.Component;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryProperty;
import net.minestom.server.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
public class FurnaceInventory extends Inventory {
@ -11,7 +13,11 @@ public class FurnaceInventory extends Inventory {
private short progressArrow;
private short maximumProgress;
public FurnaceInventory(String title) {
public FurnaceInventory(@NotNull Component title) {
super(InventoryType.FURNACE, title);
}
public FurnaceInventory(@NotNull String title) {
super(InventoryType.FURNACE, title);
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.inventory.type;
import net.kyori.adventure.text.Component;
import net.minestom.server.entity.Player;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryType;
@ -11,7 +12,12 @@ public class VillagerInventory extends Inventory {
protected TradeListPacket tradeListPacket;
public VillagerInventory(String title) {
public VillagerInventory(@NotNull Component title) {
super(InventoryType.MERCHANT, title);
setupPacket();
}
public VillagerInventory(@NotNull String title) {
super(InventoryType.MERCHANT, title);
setupPacket();
}

View File

@ -51,7 +51,7 @@ public class ItemMeta implements TagReadable, Writeable {
this.canDestroy = new HashSet<>(metaBuilder.canDestroy);
this.canPlaceOn = new HashSet<>(metaBuilder.canPlaceOn);
this.nbt = metaBuilder.nbt;
this.nbt = metaBuilder.nbt();
this.emptyBuilder = metaBuilder.getSupplier().get();
}

View File

@ -14,12 +14,17 @@ import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.Consumer;
import java.util.function.Supplier;
public abstract class ItemMetaBuilder implements TagWritable {
protected NBTCompound nbt = new NBTCompound();
private static final AtomicReferenceFieldUpdater<ItemMetaBuilder, NBTCompound> NBT_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(ItemMetaBuilder.class, NBTCompound.class, "nbt");
protected volatile boolean built = false;
private volatile NBTCompound nbt = new NBTCompound();
protected int damage;
protected boolean unbreakable;
@ -35,21 +40,21 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder damage(int damage) {
this.damage = damage;
this.nbt.setInt("Damage", damage);
mutateNbt(compound -> compound.setInt("Damage", damage));
return this;
}
@Contract("_ -> this")
public @NotNull ItemMetaBuilder unbreakable(boolean unbreakable) {
this.unbreakable = unbreakable;
this.nbt.setByte("Unbreakable", (byte) (unbreakable ? 1 : 0));
mutateNbt(compound -> compound.setByte("Unbreakable", (byte) (unbreakable ? 1 : 0)));
return this;
}
@Contract("_ -> this")
public @NotNull ItemMetaBuilder hideFlag(int hideFlag) {
this.hideFlag = hideFlag;
this.nbt.setInt("HideFlags", hideFlag);
mutateNbt(compound -> compound.setInt("HideFlags", hideFlag));
return this;
}
@ -78,7 +83,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder lore(@NotNull List<@NotNull Component> lore) {
this.lore = lore;
this.lore = new ArrayList<>(lore);
handleCompound("display", nbtCompound -> {
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
for (Component line : lore) {
@ -97,8 +102,8 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
this.enchantmentMap = enchantments;
handleMap(enchantmentMap, "Enchantments", nbt, () -> {
this.enchantmentMap = new HashMap<>(enchantments);
handleMap(enchantmentMap, "Enchantments", () -> {
NBTUtils.writeEnchant(nbt, "Enchantments", enchantmentMap);
return nbt.get("Enchantments");
});
@ -114,16 +119,16 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract("-> this")
public @NotNull ItemMetaBuilder clearEnchantment() {
this.enchantmentMap.clear();
this.enchantmentMap = Collections.emptyMap();
enchantments(enchantmentMap);
return this;
}
@Contract("_ -> this")
public @NotNull ItemMetaBuilder attributes(@NotNull List<@NotNull ItemAttribute> attributes) {
this.attributes = attributes;
this.attributes = new ArrayList<>(attributes);
handleCollection(attributes, "AttributeModifiers", nbt, () -> {
handleCollection(attributes, "AttributeModifiers", () -> {
NBTList<NBTCompound> attributesNBT = new NBTList<>(NBTTypes.TAG_Compound);
for (ItemAttribute itemAttribute : attributes) {
final UUID uuid = itemAttribute.getUuid();
@ -146,17 +151,16 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder customModelData(int customModelData) {
this.customModelData = customModelData;
this.nbt.setInt("CustomModelData", customModelData);
mutateNbt(compound -> compound.setInt("CustomModelData", customModelData));
return this;
}
@Contract("_ -> this")
public @NotNull ItemMetaBuilder canPlaceOn(@NotNull Set<@NotNull Block> blocks) {
this.canPlaceOn = blocks;
handleCollection(canPlaceOn, "CanPlaceOn", nbt, () -> {
this.canPlaceOn = new HashSet<>(blocks);
handleCollection(canPlaceOn, "CanPlaceOn", () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
canPlaceOn.forEach(block -> list.add(new NBTString(block.name())));
nbt.set("CanPlaceOn", list);
return list;
});
return this;
@ -169,11 +173,10 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder canDestroy(@NotNull Set<@NotNull Block> blocks) {
this.canDestroy = blocks;
handleCollection(canDestroy, "CanDestroy", nbt, () -> {
this.canDestroy = new HashSet<>(blocks);
handleCollection(canDestroy, "CanDestroy", () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
canDestroy.forEach(block -> list.add(new NBTString(block.name())));
nbt.set("CanDestroy", list);
return list;
});
return this;
@ -186,7 +189,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Override
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
tag.write(nbt, value);
mutateNbt(compound -> tag.write(compound, value));
}
public <T> @NotNull ItemMetaBuilder set(@NotNull Tag<T> tag, @Nullable T value) {
@ -201,63 +204,85 @@ public abstract class ItemMetaBuilder implements TagWritable {
protected abstract @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier();
protected synchronized void mutateNbt(Consumer<NBTCompound> consumer) {
if (built) {
built = false;
final var currentNbt = nbt;
NBT_UPDATER.compareAndSet(this, currentNbt, currentNbt.deepClone());
}
consumer.accept(nbt);
}
protected synchronized NBTCompound nbt() {
return nbt;
}
protected @NotNull ItemMeta generate() {
this.built = true;
return build();
}
protected void handleCompound(@NotNull String key,
@NotNull Consumer<@NotNull NBTCompound> consumer) {
NBTCompound compound = null;
boolean newNbt = false;
if (nbt.containsKey(key)) {
NBT dNbt = nbt.get(key);
if (dNbt instanceof NBTCompound) {
compound = (NBTCompound) dNbt;
}
} else {
compound = new NBTCompound();
newNbt = true;
}
if (compound != null) {
consumer.accept(compound);
if (newNbt && compound.getSize() > 0) {
this.nbt.set(key, compound);
} else if (!newNbt && compound.getSize() == 0) {
this.nbt.removeTag(key);
mutateNbt(nbt -> {
NBTCompound compound = null;
boolean newNbt = false;
if (nbt.containsKey(key)) {
NBT dNbt = nbt.get(key);
if (dNbt instanceof NBTCompound) {
compound = (NBTCompound) dNbt;
}
} else {
compound = new NBTCompound();
newNbt = true;
}
}
if (compound != null) {
consumer.accept(compound);
if (newNbt && compound.getSize() > 0) {
this.nbt.set(key, compound);
} else if (!newNbt && compound.getSize() == 0) {
this.nbt.removeTag(key);
}
}
});
}
protected void handleNullable(@Nullable Object value,
@NotNull String key,
@NotNull NBTCompound nbtCompound,
@NotNull Supplier<@NotNull NBT> supplier) {
if (value != null) {
nbtCompound.set(key, supplier.get());
} else {
nbtCompound.removeTag(key);
}
mutateNbt(compound -> {
if (value != null) {
compound.set(key, supplier.get());
} else {
compound.removeTag(key);
}
});
}
protected void handleCollection(@NotNull Collection<?> objects,
@NotNull String key,
@NotNull NBTCompound nbtCompound,
@NotNull Supplier<@NotNull NBT> supplier) {
if (!objects.isEmpty()) {
nbtCompound.set(key, supplier.get());
} else {
nbtCompound.removeTag(key);
}
mutateNbt(compound -> {
if (!objects.isEmpty()) {
compound.set(key, supplier.get());
} else {
compound.removeTag(key);
}
});
}
protected void handleMap(@NotNull Map<?, ?> objects,
@NotNull String key,
@NotNull NBTCompound nbtCompound,
@NotNull Supplier<@NotNull NBT> supplier) {
if (!objects.isEmpty()) {
nbtCompound.set(key, supplier.get());
} else {
nbtCompound.removeTag(key);
}
mutateNbt(compound -> {
if (!objects.isEmpty()) {
compound.set(key, supplier.get());
} else {
compound.removeTag(key);
}
});
}
@Contract(value = "_, _ -> new", pure = true)
@ -270,5 +295,4 @@ public abstract class ItemMetaBuilder implements TagWritable {
public interface Provider<T extends ItemMetaBuilder> {
}
}

View File

@ -109,9 +109,9 @@ public class ItemStackBuilder {
@Contract(value = "-> new", pure = true)
public @NotNull ItemStack build() {
if (amount > 0)
return new ItemStack(material, amount, metaBuilder.build(), stackingRule);
return ItemStack.AIR;
if (amount < 1)
return ItemStack.AIR;
return new ItemStack(material, amount, metaBuilder.generate(), stackingRule);
}
private static final class DefaultMeta extends ItemMetaBuilder {
@ -130,5 +130,4 @@ public class ItemStackBuilder {
return DefaultMeta::new;
}
}
}

View File

@ -45,18 +45,20 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
public Builder lodestoneTracked(boolean lodestoneTracked) {
this.lodestoneTracked = lodestoneTracked;
this.nbt.setByte("LodestoneTracked", (byte) (lodestoneTracked ? 1 : 0));
mutateNbt(compound -> compound.setByte("LodestoneTracked", (byte) (lodestoneTracked ? 1 : 0)));
return this;
}
public Builder lodestoneDimension(@Nullable String lodestoneDimension) {
this.lodestoneDimension = lodestoneDimension;
if (lodestoneDimension != null) {
this.nbt.setString("LodestoneDimension", lodestoneDimension);
} else {
this.nbt.removeTag("LodestoneDimension");
}
mutateNbt(compound -> {
if (lodestoneDimension != null) {
compound.setString("LodestoneDimension", lodestoneDimension);
} else {
compound.removeTag("LodestoneDimension");
}
});
return this;
}
@ -64,15 +66,17 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
public Builder lodestonePosition(@Nullable Position lodestonePosition) {
this.lodestonePosition = lodestonePosition;
if (lodestonePosition != null) {
NBTCompound posCompound = new NBTCompound();
posCompound.setInt("X", (int) lodestonePosition.getX());
posCompound.setInt("Y", (int) lodestonePosition.getY());
posCompound.setInt("Z", (int) lodestonePosition.getZ());
this.nbt.set("LodestonePos", posCompound);
} else {
this.nbt.removeTag("LodestonePos");
}
mutateNbt(compound -> {
if (lodestonePosition != null) {
NBTCompound posCompound = new NBTCompound();
posCompound.setInt("X", (int) lodestonePosition.getX());
posCompound.setInt("Y", (int) lodestonePosition.getY());
posCompound.setInt("Z", (int) lodestonePosition.getZ());
compound.set("LodestonePos", posCompound);
} else {
compound.removeTag("LodestonePos");
}
});
return this;
}

View File

@ -97,7 +97,7 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
if (!projectile.isAir()) {
chargedProjectiles.add(getItemCompound(projectile));
}
this.nbt.set("ChargedProjectiles", chargedProjectiles);
mutateNbt(compound -> compound.set("ChargedProjectiles", chargedProjectiles));
return this;
}
@ -123,7 +123,7 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
chargedProjectiles.add(getItemCompound(projectile1));
chargedProjectiles.add(getItemCompound(projectile2));
chargedProjectiles.add(getItemCompound(projectile3));
this.nbt.set("ChargedProjectiles", chargedProjectiles);
mutateNbt(compound -> compound.set("ChargedProjectiles", chargedProjectiles));
return this;
}
@ -135,7 +135,7 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
*/
public Builder charged(boolean charged) {
this.charged = charged;
this.nbt.setByte("Charged", (byte) (charged ? 1 : 0));
mutateNbt(compound -> compound.setByte("Charged", (byte) (charged ? 1 : 0)));
return this;
}

View File

@ -35,13 +35,13 @@ public class EnchantedBookMeta extends ItemMeta implements ItemMetaBuilder.Provi
private Map<Enchantment, Short> enchantments = new HashMap<>();
public @NotNull Builder enchantments(Map<Enchantment, Short> enchantments) {
public @NotNull Builder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
this.enchantments = enchantments;
NBTUtils.writeEnchant(nbt, "StoredEnchantments", enchantments);
mutateNbt(compound -> NBTUtils.writeEnchant(compound, "StoredEnchantments", enchantments));
return this;
}
public @NotNull Builder enchantment(Enchantment enchantment, short level) {
public @NotNull Builder enchantment(@NotNull Enchantment enchantment, short level) {
this.enchantments.put(enchantment, level);
enchantments(enchantments);
return this;

View File

@ -28,7 +28,7 @@ public class FireworkEffectMeta extends ItemMeta implements ItemMetaBuilder.Prov
public Builder effect(@Nullable FireworkEffect fireworkEffect) {
this.fireworkEffect = fireworkEffect;
this.nbt.set("Explosion", this.fireworkEffect.asCompound());
mutateNbt(compound -> compound.set("Explosion", this.fireworkEffect.asCompound()));
return this;
}

View File

@ -91,18 +91,18 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
public Builder mapId(int value) {
this.mapId = value;
this.nbt.setInt("map", mapId);
mutateNbt(compound -> compound.setInt("map", mapId));
return this;
}
public Builder mapScaleDirection(int value) {
this.mapScaleDirection = value;
this.nbt.setInt("map_scale_direction", value);
mutateNbt(compound -> compound.setInt("map_scale_direction", value));
return this;
}
public Builder decorations(List<MapDecoration> value) {
this.decorations = value;
this.decorations = new ArrayList<>(value);
NBTList<NBTCompound> decorationsList = new NBTList<>(NBTTypes.TAG_Compound);
for (MapDecoration decoration : decorations) {
@ -115,7 +115,7 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
decorationsList.add(decorationCompound);
}
this.nbt.set("Decorations", decorationsList);
mutateNbt(compound -> compound.set("Decorations", decorationsList));
return this;
}
@ -123,14 +123,16 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
public Builder mapColor(Color value) {
this.mapColor = value;
NBTCompound displayCompound;
if (nbt.containsKey("display")) {
displayCompound = nbt.getCompound("display");
} else {
displayCompound = new NBTCompound();
this.nbt.set("display", displayCompound);
}
displayCompound.setInt("MapColor", mapColor.asRGB());
mutateNbt(nbt -> {
NBTCompound displayCompound;
if (nbt.containsKey("display")) {
displayCompound = nbt.getCompound("display");
} else {
displayCompound = new NBTCompound();
nbt.set("display", displayCompound);
}
displayCompound.setInt("MapColor", mapColor.asRGB());
});
return this;
}

View File

@ -52,7 +52,7 @@ public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider<Pot
public Builder potionType(@NotNull PotionType potionType) {
this.potionType = potionType;
this.nbt.setString("Potion", potionType.getNamespaceID().asString());
mutateNbt(compound -> compound.setString("Potion", potionType.getNamespaceID().asString()));
return this;
}
@ -71,14 +71,14 @@ public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider<Pot
potionList.add(potionCompound);
}
this.nbt.set("CustomPotionEffects", potionList);
mutateNbt(compound -> compound.set("CustomPotionEffects", potionList));
return this;
}
public Builder color(@NotNull Color color) {
this.color = color;
this.nbt.setInt("CustomPotionColor", color.asRGB());
mutateNbt(compound -> compound.setInt("CustomPotionColor", color.asRGB()));
return this;
}

View File

@ -2,7 +2,6 @@ package net.minestom.server.item.metadata;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.adventure.AdventureSerializer;
import net.minestom.server.item.ItemMeta;
import net.minestom.server.item.ItemMetaBuilder;
import org.jetbrains.annotations.NotNull;
@ -53,22 +52,22 @@ public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provid
public Builder author(@Nullable String author) {
this.author = author;
handleNullable(author, "author", nbt,
handleNullable(author, "author",
() -> new NBTString(Objects.requireNonNull(author)));
return this;
}
public Builder title(@Nullable String title) {
this.title = title;
handleNullable(title, "title", nbt,
handleNullable(title, "title",
() -> new NBTString(Objects.requireNonNull(title)));
return this;
}
public Builder pages(@NotNull List<@NotNull Component> pages) {
this.pages = pages;
this.pages = new ArrayList<>(pages);
handleCollection(pages, "pages", nbt, () -> {
handleCollection(pages, "pages", () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
for (Component page : pages) {
list.add(new NBTString(GsonComponentSerializer.gson().serialize(page)));

View File

@ -86,35 +86,35 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide
public Builder resolved(boolean resolved) {
this.resolved = resolved;
this.nbt.setByte("resolved", (byte) (resolved ? 1 : 0));
mutateNbt(compound -> compound.setByte("resolved", (byte) (resolved ? 1 : 0)));
return this;
}
public Builder generation(@Nullable WrittenBookGeneration generation) {
this.generation = generation;
handleNullable(generation, "generation", nbt,
handleNullable(generation, "generation",
() -> new NBTInt(Objects.requireNonNull(generation).ordinal()));
return this;
}
public Builder author(@Nullable String author) {
this.author = author;
handleNullable(author, "author", nbt,
handleNullable(author, "author",
() -> new NBTString(Objects.requireNonNull(author)));
return this;
}
public Builder title(@Nullable String title) {
this.title = title;
handleNullable(title, "title", nbt,
handleNullable(title, "title",
() -> new NBTString(Objects.requireNonNull(title)));
return this;
}
public Builder pages(@NotNull List<@NotNull Component> pages) {
this.pages = pages;
this.pages = new ArrayList<>(pages);
handleCollection(pages, "pages", nbt, () -> {
handleCollection(pages, "pages", () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
for (Component page : pages) {
list.add(new NBTString(GsonComponentSerializer.gson().serialize(page)));

View File

@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Phaser;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
@ -30,6 +30,8 @@ public abstract class ThreadProvider {
private final Set<Entity> updatableEntities = ConcurrentHashMap.newKeySet();
private final Set<Entity> removedEntities = ConcurrentHashMap.newKeySet();
private final Phaser phaser = new Phaser(1);
public ThreadProvider(int threadCount) {
this.threads = new ArrayList<>(threadCount);
@ -112,24 +114,23 @@ public abstract class ThreadProvider {
*
* @param time the tick time in milliseconds
*/
public synchronized @NotNull CountDownLatch update(long time) {
CountDownLatch countDownLatch = new CountDownLatch(threads.size());
for (TickThread thread : threads) {
public void updateAndAwait(long time) {
for (var entry : threadChunkMap.entrySet()) {
final TickThread thread = entry.getKey();
final var chunkEntries = entry.getValue();
if (chunkEntries == null || chunkEntries.isEmpty()) {
// Nothing to tick
continue;
}
// Execute tick
thread.runnable.startTick(countDownLatch, () -> {
final var chunkEntries = threadChunkMap.get(thread);
if (chunkEntries == null || chunkEntries.isEmpty()) {
// Nothing to tick
Acquirable.refreshEntries(Collections.emptySet());
return;
}
this.phaser.register();
thread.runnable.startTick(phaser, () -> {
Acquirable.refreshEntries(chunkEntries);
final ReentrantLock lock = thread.getLock();
lock.lock();
chunkEntries.forEach(chunkEntry -> {
Chunk chunk = chunkEntry.chunk;
final Chunk chunk = chunkEntry.chunk;
if (!ChunkUtils.isLoaded(chunk))
return;
chunk.tick(time);
@ -138,18 +139,18 @@ public abstract class ThreadProvider {
for (Entity entity : entities) {
if (lock.hasQueuedThreads()) {
lock.unlock();
// #acquire callbacks should be called here
// #acquire() callbacks should be called here
lock.lock();
}
entity.tick(time);
}
}
});
Acquirable.refreshEntries(Collections.emptySet());
lock.unlock();
// #acquire() callbacks
});
}
return countDownLatch;
this.phaser.arriveAndAwaitAdvance();
}
/**

View File

@ -4,7 +4,7 @@ import net.minestom.server.MinecraftServer;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Phaser;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
@ -44,7 +44,6 @@ public class TickThread extends Thread {
}
protected static class BatchRunnable implements Runnable {
private static final AtomicReferenceFieldUpdater<BatchRunnable, TickContext> CONTEXT_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(BatchRunnable.class, TickContext.class, "tickContext");
@ -57,25 +56,20 @@ public class TickThread extends Thread {
public void run() {
Check.notNull(tickThread, "The linked BatchThread cannot be null!");
while (!stop) {
LockSupport.park(tickThread);
if (stop)
break;
TickContext localContext = tickContext;
final TickContext localContext = tickContext;
// The context is necessary to control the tick rates
if (localContext == null) {
continue;
if (localContext != null) {
// Execute tick
CONTEXT_UPDATER.compareAndSet(this, localContext, null);
localContext.runnable.run();
localContext.phaser.arriveAndDeregister();
}
// Execute tick
localContext.runnable.run();
localContext.countDownLatch.countDown();
CONTEXT_UPDATER.compareAndSet(this, localContext, null);
LockSupport.park(this);
}
}
protected void startTick(@NotNull CountDownLatch countDownLatch, @NotNull Runnable runnable) {
this.tickContext = new TickContext(countDownLatch, runnable);
protected void startTick(@NotNull Phaser phaser, @NotNull Runnable runnable) {
this.tickContext = new TickContext(phaser, runnable);
LockSupport.unpark(tickThread);
}
@ -85,13 +79,12 @@ public class TickThread extends Thread {
}
private static class TickContext {
private final CountDownLatch countDownLatch;
private final Phaser phaser;
private final Runnable runnable;
private TickContext(@NotNull CountDownLatch countDownLatch, @NotNull Runnable runnable) {
this.countDownLatch = countDownLatch;
private TickContext(@NotNull Phaser phaser, @NotNull Runnable runnable) {
this.phaser = phaser;
this.runnable = runnable;
}
}
}

View File

@ -49,16 +49,12 @@ public class PlayerInit {
.addListener(EntityAttackEvent.class, event -> {
final Entity source = event.getEntity();
final Entity entity = event.getTarget();
entity.takeKnockback(0.4f, Math.sin(source.getPosition().getYaw() * 0.017453292), -Math.cos(source.getPosition().getYaw() * 0.017453292));
if (entity instanceof Player) {
Player target = (Player) entity;
Vector velocity = source.getPosition().clone().getDirection().multiply(4);
velocity.setY(3.5f);
target.setVelocity(velocity);
target.damage(DamageType.fromEntity(source), 5);
} else {
Vector velocity = source.getPosition().clone().getDirection().multiply(3);
velocity.setY(3f);
entity.setVelocity(velocity);
}
if (source instanceof Player) {