From 06f2ed60655c68dd7782d692a2c858450c46837e Mon Sep 17 00:00:00 2001 From: themode Date: Mon, 26 Oct 2020 13:57:02 +0100 Subject: [PATCH] Use the Contract annotation to prevent useless NPE warnings --- .../net/minestom/server/entity/Player.java | 9 ++- .../server/entity/damage/DamageType.java | 4 +- .../gamedata/loottables/LootTableManager.java | 2 +- .../server/instance/BlockModifier.java | 20 ++++--- .../minestom/server/instance/Instance.java | 17 +++--- .../server/instance/InstanceManager.java | 27 ++++++--- .../server/instance/SharedInstance.java | 3 +- .../server/instance/block/CustomBlock.java | 60 ++++++++++++------- .../minestom/server/utils/validate/Check.java | 8 +++ src/test/java/demo/PlayerInit.java | 35 ++--------- .../java/demo/blocks/BurningTorchBlock.java | 9 +-- src/test/java/demo/blocks/StoneBlock.java | 13 ++-- .../java/demo/blocks/UpdatableBlockDemo.java | 11 ++-- .../java/demo/commands/DimensionCommand.java | 6 +- .../java/demo/commands/ShutdownCommand.java | 6 +- .../java/demo/commands/SimpleCommand.java | 10 ++-- 16 files changed, 130 insertions(+), 110 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 0f0c744b2..e9426f84a 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -338,6 +338,7 @@ public class Player extends LivingEntity implements CommandSender { final Chunk chunk = instance.getChunkAt(targetBlockPosition); final int entityId = targetCustomBlock.getBreakEntityId(this); final BlockBreakAnimationPacket blockBreakAnimationPacket = new BlockBreakAnimationPacket(entityId, targetBlockPosition, targetStage); + Check.notNull(chunk, "Tried to interact with an unloaded chunk."); chunk.sendPacketToViewers(blockBreakAnimationPacket); refreshBreakDelay(targetBreakers); @@ -374,6 +375,8 @@ public class Player extends LivingEntity implements CommandSender { triggerStatus((byte) 9); // Mark item use as finished ItemUpdateStateEvent itemUpdateStateEvent = callItemUpdateStateEvent(true); + Check.notNull(itemUpdateStateEvent, "#callItemUpdateStateEvent returned null."); + // Refresh hand final boolean isOffHand = itemUpdateStateEvent.getHand() == Player.Hand.OFF; refreshActiveHand(false, isOffHand, false); @@ -780,7 +783,7 @@ public class Player extends LivingEntity implements CommandSender { } /** - * Plays a sound from an identifier (represents a custom sound in a resource pack) + * Plays a sound from an identifier (represents a custom sound in a resource pack). * * @param identifier the identifier of the sound to play * @param soundCategory the sound category @@ -1299,7 +1302,9 @@ public class Player extends LivingEntity implements CommandSender { { // Send new chunks final BlockPosition pos = position.toBlockPosition(); - onChunkChange(instance.getChunk(pos.getX() >> 4, pos.getZ() >> 4)); + final Chunk chunk = instance.getChunk(pos.getX() >> 4, pos.getZ() >> 4); + Check.notNull(chunk, "Tried to interact with an unloaded chunk."); + onChunkChange(chunk); } } diff --git a/src/main/java/net/minestom/server/entity/damage/DamageType.java b/src/main/java/net/minestom/server/entity/damage/DamageType.java index 563ac9310..f6c511b8a 100644 --- a/src/main/java/net/minestom/server/entity/damage/DamageType.java +++ b/src/main/java/net/minestom/server/entity/damage/DamageType.java @@ -64,7 +64,7 @@ public class DamageType implements DataContainer { * @return the death message, null to do not send anything. * Can be for instance, of type {@link ColoredText} or {@link RichMessage}. */ - @NotNull + @Nullable public JsonMessage buildDeathMessage(@NotNull Player killed) { return ColoredText.of("{@death." + identifier + "," + killed.getUsername() + "}"); } @@ -109,7 +109,7 @@ public class DamageType implements DataContainer { * @param killed the player who has been killed * @return the death screen text, null to do not send anything */ - @NotNull + @Nullable public ColoredText buildDeathScreenText(@NotNull Player killed) { return ColoredText.of("{@death." + identifier + "}"); } diff --git a/src/main/java/net/minestom/server/gamedata/loottables/LootTableManager.java b/src/main/java/net/minestom/server/gamedata/loottables/LootTableManager.java index 769c6b30c..fceb467ba 100644 --- a/src/main/java/net/minestom/server/gamedata/loottables/LootTableManager.java +++ b/src/main/java/net/minestom/server/gamedata/loottables/LootTableManager.java @@ -13,7 +13,7 @@ import java.io.*; /** * Handles loading and configuration of loot tables */ -public class LootTableManager { +public final class LootTableManager { private NamespaceIDHashMap> conditionDeserializers = new NamespaceIDHashMap<>(); private NamespaceIDHashMap tableTypes = new NamespaceIDHashMap<>(); diff --git a/src/main/java/net/minestom/server/instance/BlockModifier.java b/src/main/java/net/minestom/server/instance/BlockModifier.java index 55a76c80c..5146c1d37 100644 --- a/src/main/java/net/minestom/server/instance/BlockModifier.java +++ b/src/main/java/net/minestom/server/instance/BlockModifier.java @@ -9,6 +9,8 @@ import net.minestom.server.instance.block.BlockManager; import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.validate.Check; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Represents an element which can place blocks at position. @@ -30,7 +32,7 @@ public interface BlockModifier { * @param blockStateId the block state id * @param data the block {@link Data}, can be null */ - void setBlockStateId(int x, int y, int z, short blockStateId, Data data); + void setBlockStateId(int x, int y, int z, short blockStateId, @Nullable Data data); /** * Sets a {@link CustomBlock} at a position. @@ -43,7 +45,7 @@ public interface BlockModifier { * @param customBlockId the custom block id * @param data the block {@link Data}, can be null */ - void setCustomBlock(int x, int y, int z, short customBlockId, Data data); + void setCustomBlock(int x, int y, int z, short customBlockId, @Nullable Data data); /** * Sets a {@link CustomBlock} at a position with a custom state id. @@ -58,17 +60,17 @@ public interface BlockModifier { * @param customBlockId the custom block id * @param data the block {@link Data}, can be null */ - void setSeparateBlocks(int x, int y, int z, short blockStateId, short customBlockId, Data data); + void setSeparateBlocks(int x, int y, int z, short blockStateId, short customBlockId, @Nullable Data data); default void setBlockStateId(int x, int y, int z, short blockStateId) { setBlockStateId(x, y, z, blockStateId, null); } - default void setBlock(int x, int y, int z, Block block) { + default void setBlock(int x, int y, int z, @NotNull Block block) { setBlockStateId(x, y, z, block.getBlockId(), null); } - default void setBlock(BlockPosition blockPosition, Block block) { + default void setBlock(@NotNull BlockPosition blockPosition, @NotNull Block block) { Check.notNull(blockPosition, "The block position cannot be null"); Check.notNull(block, "The block cannot be null"); setBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), block); @@ -83,18 +85,18 @@ public interface BlockModifier { setCustomBlock(x, y, z, customBlockId, null); } - default void setCustomBlock(int x, int y, int z, String customBlockId, Data data) { + default void setCustomBlock(int x, int y, int z, @NotNull String customBlockId, @Nullable Data data) { CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId); Check.notNull(customBlock, "The CustomBlock " + customBlockId + " is not registered"); setCustomBlock(x, y, z, customBlock.getCustomBlockId(), data); } - default void setCustomBlock(int x, int y, int z, String customBlockId) { + default void setCustomBlock(int x, int y, int z, @NotNull String customBlockId) { setCustomBlock(x, y, z, customBlockId, null); } - default void setCustomBlock(BlockPosition blockPosition, String customBlockId) { + default void setCustomBlock(@NotNull BlockPosition blockPosition, @NotNull String customBlockId) { Check.notNull(blockPosition, "The block position cannot be null"); setCustomBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), customBlockId); } @@ -103,7 +105,7 @@ public interface BlockModifier { setSeparateBlocks(x, y, z, blockStateId, customBlockId, null); } - default void setSeparateBlocks(BlockPosition blockPosition, short blockStateId, short customBlockId) { + default void setSeparateBlocks(@NotNull BlockPosition blockPosition, short blockStateId, short customBlockId) { Check.notNull(blockPosition, "The block position cannot be null"); setSeparateBlocks(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), blockStateId, customBlockId, null); } diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index 3e7484ad5..9634da02e 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -886,6 +886,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta // Remove the entity from cache final Chunk chunk = getChunkAt(entity.getPosition()); + Check.notNull(chunk, "Tried to interact with an unloaded chunk."); removeEntityFromChunk(entity, chunk); }); } @@ -931,15 +932,13 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta */ public void removeEntityFromChunk(@NotNull Entity entity, @NotNull Chunk chunk) { synchronized (chunkEntities) { - if (chunk != null) { - final long chunkIndex = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ()); - Set entities = getEntitiesInChunk(chunkIndex); - entities.remove(entity); - if (entities.isEmpty()) { - this.chunkEntities.remove(chunkIndex); - } else { - this.chunkEntities.put(chunkIndex, entities); - } + final long chunkIndex = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ()); + Set entities = getEntitiesInChunk(chunkIndex); + entities.remove(entity); + if (entities.isEmpty()) { + this.chunkEntities.remove(chunkIndex); + } else { + this.chunkEntities.put(chunkIndex, entities); } this.entities.remove(entity); diff --git a/src/main/java/net/minestom/server/instance/InstanceManager.java b/src/main/java/net/minestom/server/instance/InstanceManager.java index 21884d432..7d9eff015 100644 --- a/src/main/java/net/minestom/server/instance/InstanceManager.java +++ b/src/main/java/net/minestom/server/instance/InstanceManager.java @@ -4,6 +4,8 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.storage.StorageLocation; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.DimensionType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.Set; @@ -25,7 +27,7 @@ public final class InstanceManager { * * @param instance the {@link Instance} to register */ - public void registerInstance(Instance instance) { + public void registerInstance(@NotNull Instance instance) { Check.stateCondition(instance instanceof SharedInstance, "Please use InstanceManager#registerSharedInstance to register a shared instance"); UNSAFE_registerInstance(instance); @@ -39,7 +41,8 @@ public final class InstanceManager { * @param storageLocation the {@link StorageLocation} of the instance, can be null * @return the created {@link InstanceContainer} */ - public InstanceContainer createInstanceContainer(DimensionType dimensionType, StorageLocation storageLocation) { + @NotNull + public InstanceContainer createInstanceContainer(@NotNull DimensionType dimensionType, @Nullable StorageLocation storageLocation) { final InstanceContainer instanceContainer = new InstanceContainer(UUID.randomUUID(), dimensionType, storageLocation); registerInstance(instanceContainer); return instanceContainer; @@ -51,7 +54,8 @@ public final class InstanceManager { * @param storageLocation the {@link StorageLocation} of the instance, can be null * @return the created {@link InstanceContainer} */ - public InstanceContainer createInstanceContainer(StorageLocation storageLocation) { + @NotNull + public InstanceContainer createInstanceContainer(@Nullable StorageLocation storageLocation) { return createInstanceContainer(DimensionType.OVERWORLD, storageLocation); } @@ -61,7 +65,8 @@ public final class InstanceManager { * @param dimensionType the {@link DimensionType} of the instance * @return the created {@link InstanceContainer} */ - public InstanceContainer createInstanceContainer(DimensionType dimensionType) { + @NotNull + public InstanceContainer createInstanceContainer(@NotNull DimensionType dimensionType) { return createInstanceContainer(dimensionType, null); } @@ -70,6 +75,7 @@ public final class InstanceManager { * * @return the created {@link InstanceContainer} */ + @NotNull public InstanceContainer createInstanceContainer() { return createInstanceContainer(DimensionType.OVERWORLD); } @@ -83,7 +89,8 @@ public final class InstanceManager { * @return the registered {@link SharedInstance} * @throws NullPointerException if {@code sharedInstance} doesn't have an {@link InstanceContainer} assigned to it */ - public SharedInstance registerSharedInstance(SharedInstance sharedInstance) { + @NotNull + public SharedInstance registerSharedInstance(@NotNull SharedInstance sharedInstance) { final InstanceContainer instanceContainer = sharedInstance.getInstanceContainer(); Check.notNull(instanceContainer, "SharedInstance needs to have an InstanceContainer to be created!"); @@ -99,7 +106,8 @@ public final class InstanceManager { * @return the created {@link SharedInstance} * @throws IllegalStateException if {@code instanceContainer} is not registered */ - public SharedInstance createSharedInstance(InstanceContainer instanceContainer) { + @NotNull + public SharedInstance createSharedInstance(@NotNull InstanceContainer instanceContainer) { Check.notNull(instanceContainer, "Instance container cannot be null when creating a SharedInstance!"); Check.stateCondition(!instanceContainer.isRegistered(), "The container needs to be register in the InstanceManager"); @@ -114,8 +122,8 @@ public final class InstanceManager { * * @param instance the {@link Instance} to unregister */ - public void unregisterInstance(Instance instance) { - Check.stateCondition(!instance.getPlayers().isEmpty(), "You cannot unregister an instance with players"); + public void unregisterInstance(@NotNull Instance instance) { + Check.stateCondition(!instance.getPlayers().isEmpty(), "You cannot unregister an instance with players inside."); synchronized (instance) { // Unload all chunks @@ -136,6 +144,7 @@ public final class InstanceManager { * * @return an unmodifiable {@link Set} containing all the registered instances */ + @NotNull public Set getInstances() { return Collections.unmodifiableSet(instances); } @@ -147,7 +156,7 @@ public final class InstanceManager { * * @param instance the {@link Instance} to register */ - private void UNSAFE_registerInstance(Instance instance) { + private void UNSAFE_registerInstance(@NotNull Instance instance) { instance.setRegistered(true); this.instances.add(instance); MinecraftServer.getUpdateManager().signalInstanceCreate(instance); diff --git a/src/main/java/net/minestom/server/instance/SharedInstance.java b/src/main/java/net/minestom/server/instance/SharedInstance.java index ce2772696..013e2a0a1 100644 --- a/src/main/java/net/minestom/server/instance/SharedInstance.java +++ b/src/main/java/net/minestom/server/instance/SharedInstance.java @@ -23,7 +23,7 @@ public class SharedInstance extends Instance { private final InstanceContainer instanceContainer; - public SharedInstance(UUID uniqueId, InstanceContainer instanceContainer) { + public SharedInstance(@NotNull UUID uniqueId, @NotNull InstanceContainer instanceContainer) { super(uniqueId, instanceContainer.getDimensionType()); this.instanceContainer = instanceContainer; } @@ -154,6 +154,7 @@ public class SharedInstance extends Instance { * * @return the associated {@link InstanceContainer} */ + @NotNull public InstanceContainer getInstanceContainer() { return instanceContainer; } diff --git a/src/main/java/net/minestom/server/instance/block/CustomBlock.java b/src/main/java/net/minestom/server/instance/block/CustomBlock.java index 377729af9..3dd7fb9b4 100644 --- a/src/main/java/net/minestom/server/instance/block/CustomBlock.java +++ b/src/main/java/net/minestom/server/instance/block/CustomBlock.java @@ -16,6 +16,8 @@ import net.minestom.server.network.packet.server.play.BlockBreakAnimationPacket; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.time.UpdateOption; import net.minestom.server.utils.validate.Check; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.HashMap; @@ -24,7 +26,7 @@ import java.util.Map; import java.util.Set; /** - * Represents the handler of a custom block type. + * Represents the handler of a custom block type which can be registered with {@link BlockManager#registerCustomBlock(CustomBlock)}. *

* There should be only one instance of this class for each custom block type, * every individual blocks will execute the callbacks present there. Each of which contains the @@ -55,12 +57,12 @@ public abstract class CustomBlock { * @param defaultBlockStateId the default block state id * @param identifier the custom block identifier */ - public CustomBlock(short defaultBlockStateId, String identifier) { + public CustomBlock(short defaultBlockStateId, @NotNull String identifier) { this.defaultBlockStateId = defaultBlockStateId; this.identifier = identifier; } - public CustomBlock(Block block, String identifier) { + public CustomBlock(@NotNull Block block, @NotNull String identifier) { this(block.getBlockId(), identifier); } @@ -73,7 +75,7 @@ public abstract class CustomBlock { * @throws UnsupportedOperationException if {@link #getUpdateOption()} * is not null but the update method is not overridden */ - public void update(Instance instance, BlockPosition blockPosition, Data data) { + public void update(@NotNull Instance instance, @NotNull BlockPosition blockPosition, @Nullable Data data) { throw new UnsupportedOperationException("Update method not overridden, check #getUpdateOption()"); } @@ -86,6 +88,7 @@ public abstract class CustomBlock { * * @return the update option of the block */ + @Nullable public UpdateOption getUpdateOption() { return null; } @@ -97,7 +100,7 @@ public abstract class CustomBlock { * @param blockPosition the position of the block * @param data the data associated with the block */ - public abstract void onPlace(Instance instance, BlockPosition blockPosition, Data data); + public abstract void onPlace(@NotNull Instance instance, @NotNull BlockPosition blockPosition, @Nullable Data data); /** * Called when a custom block has been destroyed or replaced. @@ -106,7 +109,7 @@ public abstract class CustomBlock { * @param blockPosition the position of the block * @param data the data associated with the block */ - public abstract void onDestroy(Instance instance, BlockPosition blockPosition, Data data); + public abstract void onDestroy(@NotNull Instance instance, @NotNull BlockPosition blockPosition, @Nullable Data data); /** * Handles interactions with this block. Can also block normal item use (containers should block when opening the @@ -118,7 +121,8 @@ public abstract class CustomBlock { * @param data the data at this position * @return true if this block blocks normal item use, false otherwise */ - public abstract boolean onInteract(Player player, Player.Hand hand, BlockPosition blockPosition, Data data); + public abstract boolean onInteract(@NotNull Player player, @NotNull Player.Hand hand, + @NotNull BlockPosition blockPosition, @Nullable Data data); /** * This id can be serialized in chunk file, meaning no duplicate should exist @@ -139,7 +143,7 @@ public abstract class CustomBlock { * negative value allow to skip stages (-2 will skip 2 stages per tick) * @see #enableCustomBreakDelay() to enable/disable it */ - public int getBreakDelay(Player player, BlockPosition position, byte stage, Set breakers) { + public int getBreakDelay(@NotNull Player player, @NotNull BlockPosition position, byte stage, Set breakers) { return 0; } @@ -186,7 +190,7 @@ public abstract class CustomBlock { * @param position the position at which the block is * @param touching the entity currently touching the block */ - public void handleContact(Instance instance, BlockPosition position, Entity touching) { + public void handleContact(@NotNull Instance instance, @NotNull BlockPosition position, @NotNull Entity touching) { } /** @@ -208,6 +212,7 @@ public abstract class CustomBlock { * * @return the custom block identifier */ + @NotNull public String getIdentifier() { return identifier; } @@ -219,7 +224,8 @@ public abstract class CustomBlock { * @param data data given to 'setBlock', can be null * @return Data for this block. Can be null, 'data', or a new object */ - public Data createData(Instance instance, BlockPosition blockPosition, Data data) { + @Nullable + public Data createData(@NotNull Instance instance, @NotNull BlockPosition blockPosition, @Nullable Data data) { return data; } @@ -231,7 +237,8 @@ public abstract class CustomBlock { * @param neighborPosition the neighboring block which triggered the update * @param directNeighbor is the neighbor directly connected to this block? (No diagonals) */ - public void updateFromNeighbor(Instance instance, BlockPosition thisPosition, BlockPosition neighborPosition, boolean directNeighbor) { + public void updateFromNeighbor(@NotNull Instance instance, @NotNull BlockPosition thisPosition, + @NotNull BlockPosition neighborPosition, boolean directNeighbor) { if (directNeighbor && hasUpdate()) { update(instance, thisPosition, instance.getBlockData(thisPosition)); } @@ -244,7 +251,7 @@ public abstract class CustomBlock { * @param position the position of the block * @param blockData the data of the block */ - public void scheduledUpdate(Instance instance, BlockPosition position, Data blockData) { + public void scheduledUpdate(@NotNull Instance instance, @NotNull BlockPosition position, @Nullable Data blockData) { update(instance, position, blockData); } @@ -255,7 +262,7 @@ public abstract class CustomBlock { * * @return the drag of this block */ - public float getDrag(Instance instance, BlockPosition blockPosition) { + public float getDrag(@NotNull Instance instance, @NotNull BlockPosition blockPosition) { return 0.5f; } @@ -266,8 +273,9 @@ public abstract class CustomBlock { * * @param position position of the block * @param blockData equivalent to

instance.getBlockData(position)
+ * @param nbt the nbt to write in the {@link net.minestom.server.network.packet.server.play.ChunkDataPacket} */ - public void writeBlockEntity(BlockPosition position, Data blockData, NBTCompound nbt) { + public void writeBlockEntity(@NotNull BlockPosition position, @Nullable Data blockData, @NotNull NBTCompound nbt) { } /** @@ -278,7 +286,7 @@ public abstract class CustomBlock { * @return 'true' if the explosion should happen on this block, 'false' to cancel the destruction. * Returning true does NOT block the explosion rays, ie it does not change the block explosion resistance */ - public boolean onExplode(Instance instance, BlockPosition position, Data lootTableArguments) { + public boolean onExplode(@NotNull Instance instance, @NotNull BlockPosition position, Data lootTableArguments) { return true; } @@ -288,7 +296,8 @@ public abstract class CustomBlock { * @param tableManager the loot table manager * @return the loot table associated to this block */ - public LootTable getLootTable(LootTableManager tableManager) { + @Nullable + public LootTable getLootTable(@NotNull LootTableManager tableManager) { return null; } @@ -302,7 +311,7 @@ public abstract class CustomBlock { * @param blockPosition the position of the block * @param player the player who started digging */ - public void startDigging(Instance instance, BlockPosition blockPosition, Player player) { + public void startDigging(@NotNull Instance instance, @NotNull BlockPosition blockPosition, @NotNull Player player) { // Stay null if multi player breaking is disabled Set breakers = null; @@ -339,7 +348,7 @@ public abstract class CustomBlock { * @param blockPosition the position of the block * @param player the player who stopped digging */ - public void stopDigging(Instance instance, BlockPosition blockPosition, Player player) { + public void stopDigging(@NotNull Instance instance, @NotNull BlockPosition blockPosition, @NotNull Player player) { if (enableMultiPlayerBreaking()) { // Remove cache data if (instanceBreakDataMap.containsKey(instance)) { @@ -355,6 +364,7 @@ public abstract class CustomBlock { final int entityId = instanceBreakData.breakIdMap.getInt(blockPosition); final Chunk chunk = instance.getChunkAt(blockPosition); + Check.notNull(chunk, "Tried to interact with an unloaded chunk."); chunk.sendPacketToViewers(new BlockBreakAnimationPacket(entityId, blockPosition, (byte) -1)); // Clear cache @@ -367,6 +377,7 @@ public abstract class CustomBlock { // Stop the breaking animation for the specific player id final Chunk chunk = instance.getChunkAt(blockPosition); final int entityId = getBreakEntityId(player); + Check.notNull(chunk, "Tried to interact with an unloaded chunk."); chunk.sendPacketToViewers(new BlockBreakAnimationPacket(entityId, blockPosition, (byte) -1)); } } @@ -382,7 +393,8 @@ public abstract class CustomBlock { * @return true if the block can continue being digged * @throws IllegalStateException if {@link #enableMultiPlayerBreaking()} is disabled */ - public synchronized boolean processStage(Instance instance, BlockPosition blockPosition, Player player, byte stageIncrease) { + public synchronized boolean processStage(@NotNull Instance instance, @NotNull BlockPosition blockPosition, + @NotNull Player player, byte stageIncrease) { Check.stateCondition(!enableMultiPlayerBreaking(), "CustomBlock#processState requires having the multi player breaking feature enabled"); @@ -400,6 +412,7 @@ public abstract class CustomBlock { // Send the block break animation final Chunk chunk = instance.getChunkAt(blockPosition); + Check.notNull(chunk, "Tried to interact with an unloaded chunk."); chunk.sendPacketToViewers(new BlockBreakAnimationPacket(entityId, blockPosition, stage)); // Refresh the stage @@ -411,7 +424,7 @@ public abstract class CustomBlock { return false; } - public void removeDiggingInformation(Instance instance, BlockPosition blockPosition) { + public void removeDiggingInformation(@NotNull Instance instance, @NotNull BlockPosition blockPosition) { if (!enableMultiPlayerBreaking()) { return; } @@ -431,7 +444,8 @@ public abstract class CustomBlock { * @return the {@link Set} of breakers of a block * @throws IllegalStateException if {@link #enableMultiPlayerBreaking()} is disabled */ - public Set getBreakers(Instance instance, BlockPosition blockPosition) { + @Nullable + public Set getBreakers(@NotNull Instance instance, @NotNull BlockPosition blockPosition) { Check.stateCondition(!enableMultiPlayerBreaking(), "CustomBlock#getBreakers requires having the multi player breaking feature enabled"); @@ -450,7 +464,7 @@ public abstract class CustomBlock { * @param blockPosition the position of the custom block * @return the break stage at the position. Can also be 0 when nonexistent */ - public byte getBreakStage(Instance instance, BlockPosition blockPosition) { + public byte getBreakStage(@NotNull Instance instance, @NotNull BlockPosition blockPosition) { Check.stateCondition(!enableMultiPlayerBreaking(), "CustomBlock#getBreakStage requires having the multi player breaking feature enabled"); @@ -472,7 +486,7 @@ public abstract class CustomBlock { // Contains the entity id used by the block break packet private final Object2IntMap breakIdMap = new Object2IntOpenHashMap<>(); - private void clear(BlockPosition blockPosition) { + private void clear(@NotNull BlockPosition blockPosition) { this.breakersMap.remove(blockPosition); this.breakStageMap.removeByte(blockPosition); this.breakIdMap.removeInt(blockPosition); diff --git a/src/main/java/net/minestom/server/utils/validate/Check.java b/src/main/java/net/minestom/server/utils/validate/Check.java index ef62d267b..2ce0a0c1e 100644 --- a/src/main/java/net/minestom/server/utils/validate/Check.java +++ b/src/main/java/net/minestom/server/utils/validate/Check.java @@ -1,27 +1,35 @@ package net.minestom.server.utils.validate; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Objects; +/** + * Convenient class to check for common exceptions types. + */ public final class Check { + private Check() { } + @Contract("null, _ -> fail") public static void notNull(@Nullable Object object, @NotNull String reason) { if (Objects.isNull(object)) { throw new NullPointerException(reason); } } + @Contract("true, _ -> fail") public static void argCondition(boolean condition, @NotNull String reason) { if (condition) { throw new IllegalArgumentException(reason); } } + @Contract("true, _ -> fail") public static void stateCondition(boolean condition, @NotNull String reason) { if (condition) { throw new IllegalStateException(reason); diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index cc2fe75b0..406f15552 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -19,7 +19,6 @@ import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.block.Block; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.Enchantment; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.network.ConnectionManager; @@ -43,7 +42,7 @@ public class PlayerInit { StorageLocation storageLocation = MinecraftServer.getStorageManager().getLocation("instance_data", new StorageOptions().setCompression(true)); ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo(); NoiseTestGenerator noiseTestGenerator = new NoiseTestGenerator(); - instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(DimensionType.OVERWORLD); + instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(DimensionType.OVERWORLD, storageLocation); instanceContainer.enableAutoChunkLoad(true); instanceContainer.setChunkGenerator(noiseTestGenerator); @@ -113,7 +112,7 @@ public class PlayerInit { final Block block = Block.fromStateId(event.getBlockStateId()); if (block == Block.STONE) { - event.setCustomBlock((short) 2); // custom stone block + event.setCustomBlock("custom_block"); System.out.println("custom stone"); } if (block == Block.TORCH) { @@ -154,9 +153,6 @@ public class PlayerInit { player.addEventCallback(PlayerLoginEvent.class, event -> { event.setSpawningInstance(instanceContainer); - player.setEnableRespawnScreen(false); - - player.setPermissionLevel(4); player.getInventory().addInventoryCondition((p, slot, clickType, inventoryConditionResult) -> { if (slot == -999) @@ -168,29 +164,6 @@ public class PlayerInit { } System.out.println("slot player: " + slot + " : " + itemStack.getMaterial() + " : " + (itemStack.getData() != null)); }); - - { - /*AdvancementManager advancementManager = MinecraftServer.getAdvancementManager(); - AdvancementRoot root = new AdvancementRoot(ColoredText.of("title"), ColoredText.of(ChatColor.BLUE + "description"), - Material.APPLE, FrameType.TASK, 0, 0, - "minecraft:textures/block/red_wool.png"); - root.setAchieved(true); - AdvancementTab tab = advancementManager.createTab("root", root); - Advancement advancement = new Advancement(ColoredText.of("adv"), ColoredText.of("desc"), - Material.WOODEN_AXE, FrameType.CHALLENGE, 1, 0) - .showToast(true).setHidden(false); - tab.createAdvancement("second", advancement, root); - - tab.addViewer(player); - - root.setTitle(ColoredText.of("test ttlechange")); - - Advancement advancement2 = new Advancement(ColoredText.of(ChatColor.BLUE + "Title"), - ColoredText.of("description of the advancement"), - Material.GOLD_BLOCK, FrameType.CHALLENGE, 3, 0) - .showToast(true).setHidden(false); - tab.createAdvancement("second2", advancement2, root);*/ - } }); player.addEventCallback(PlayerSpawnEvent.class, event -> { @@ -199,10 +172,10 @@ public class PlayerInit { Data data = new DataImpl(); data.set("test", 5, Integer.class); - ItemStack itemStack = new ItemStack(Material.NETHERITE_PICKAXE, (byte) 1); - itemStack.setEnchantment(Enchantment.EFFICIENCY, (short) 5); + ItemStack itemStack = new ItemStack(Material.DIAMOND_PICKAXE, (byte) 1); itemStack.setData(data); player.getInventory().addItemStack(itemStack); + //player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte)64)); }); player.addEventCallback(PlayerRespawnEvent.class, event -> { diff --git a/src/test/java/demo/blocks/BurningTorchBlock.java b/src/test/java/demo/blocks/BurningTorchBlock.java index 19dbfdc16..f7822a27e 100644 --- a/src/test/java/demo/blocks/BurningTorchBlock.java +++ b/src/test/java/demo/blocks/BurningTorchBlock.java @@ -9,6 +9,7 @@ import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.utils.BlockPosition; +import org.jetbrains.annotations.NotNull; /** * Custom block which burns entities that touch it @@ -19,7 +20,7 @@ public class BurningTorchBlock extends CustomBlock { } @Override - public void handleContact(Instance instance, BlockPosition position, Entity touching) { + public void handleContact(@NotNull Instance instance, @NotNull BlockPosition position, @NotNull Entity touching) { System.out.println("touching " + touching); if (touching instanceof LivingEntity) { ((LivingEntity) touching).damage(DamageType.GRAVITY, 0.1f); @@ -27,17 +28,17 @@ public class BurningTorchBlock extends CustomBlock { } @Override - public void onPlace(Instance instance, BlockPosition blockPosition, Data data) { + public void onPlace(@NotNull Instance instance, @NotNull BlockPosition blockPosition, Data data) { System.out.println(blockPosition); } @Override - public void onDestroy(Instance instance, BlockPosition blockPosition, Data data) { + public void onDestroy(@NotNull Instance instance, @NotNull BlockPosition blockPosition, Data data) { } @Override - public boolean onInteract(Player player, Player.Hand hand, BlockPosition blockPosition, Data data) { + public boolean onInteract(@NotNull Player player, @NotNull Player.Hand hand, @NotNull BlockPosition blockPosition, Data data) { return false; } diff --git a/src/test/java/demo/blocks/StoneBlock.java b/src/test/java/demo/blocks/StoneBlock.java index 193ea0669..5e967a198 100644 --- a/src/test/java/demo/blocks/StoneBlock.java +++ b/src/test/java/demo/blocks/StoneBlock.java @@ -6,22 +6,23 @@ import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.utils.BlockPosition; +import org.jetbrains.annotations.NotNull; import java.util.Set; public class StoneBlock extends CustomBlock { public StoneBlock() { - super(Block.STONE, "custom_block"); + super(Block.GOLD_BLOCK, "custom_block"); } @Override - public void onPlace(Instance instance, BlockPosition blockPosition, Data data) { + public void onPlace(@NotNull Instance instance, @NotNull BlockPosition blockPosition, Data data) { } @Override - public void onDestroy(Instance instance, BlockPosition blockPosition, Data data) { + public void onDestroy(@NotNull Instance instance, @NotNull BlockPosition blockPosition, Data data) { BlockPosition above = blockPosition.clone().add(0, 1, 0); CustomBlock blockAbove = instance.getCustomBlock(above); if (blockAbove == this) { @@ -31,17 +32,17 @@ public class StoneBlock extends CustomBlock { } @Override - public void updateFromNeighbor(Instance instance, BlockPosition thisPosition, BlockPosition neighborPosition, boolean directNeighbor) { + public void updateFromNeighbor(@NotNull Instance instance, @NotNull BlockPosition thisPosition, @NotNull BlockPosition neighborPosition, boolean directNeighbor) { } @Override - public boolean onInteract(Player player, Player.Hand hand, BlockPosition blockPosition, Data data) { + public boolean onInteract(@NotNull Player player, @NotNull Player.Hand hand, @NotNull BlockPosition blockPosition, Data data) { return false; } @Override - public int getBreakDelay(Player player, BlockPosition position, byte stage, Set breakers) { + public int getBreakDelay(@NotNull Player player, @NotNull BlockPosition position, byte stage, Set breakers) { return 2; } diff --git a/src/test/java/demo/blocks/UpdatableBlockDemo.java b/src/test/java/demo/blocks/UpdatableBlockDemo.java index 9ad14e775..4bf1a2c43 100644 --- a/src/test/java/demo/blocks/UpdatableBlockDemo.java +++ b/src/test/java/demo/blocks/UpdatableBlockDemo.java @@ -8,6 +8,7 @@ import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.time.UpdateOption; +import org.jetbrains.annotations.NotNull; import java.util.Set; @@ -20,22 +21,22 @@ public class UpdatableBlockDemo extends CustomBlock { } @Override - public void update(Instance instance, BlockPosition blockPosition, Data data) { + public void update(@NotNull Instance instance, @NotNull BlockPosition blockPosition, Data data) { System.out.println("BLOCK UPDATE"); } @Override - public void onPlace(Instance instance, BlockPosition blockPosition, Data data) { + public void onPlace(@NotNull Instance instance, @NotNull BlockPosition blockPosition, Data data) { } @Override - public void onDestroy(Instance instance, BlockPosition blockPosition, Data data) { + public void onDestroy(@NotNull Instance instance, @NotNull BlockPosition blockPosition, Data data) { } @Override - public boolean onInteract(Player player, Player.Hand hand, BlockPosition blockPosition, Data data) { + public boolean onInteract(@NotNull Player player, @NotNull Player.Hand hand, @NotNull BlockPosition blockPosition, Data data) { return false; } @@ -45,7 +46,7 @@ public class UpdatableBlockDemo extends CustomBlock { } @Override - public int getBreakDelay(Player player, BlockPosition position, byte stage, Set breakers) { + public int getBreakDelay(@NotNull Player player, @NotNull BlockPosition position, byte stage, Set breakers) { return 1; } diff --git a/src/test/java/demo/commands/DimensionCommand.java b/src/test/java/demo/commands/DimensionCommand.java index b1f4a1815..bfbf0667b 100644 --- a/src/test/java/demo/commands/DimensionCommand.java +++ b/src/test/java/demo/commands/DimensionCommand.java @@ -6,10 +6,12 @@ import net.minestom.server.command.CommandSender; import net.minestom.server.entity.Player; import net.minestom.server.instance.Instance; import net.minestom.server.world.DimensionType; +import org.jetbrains.annotations.NotNull; import java.util.Optional; public class DimensionCommand implements CommandProcessor { + @NotNull @Override public String getCommandName() { return "dimensiontest"; @@ -21,7 +23,7 @@ public class DimensionCommand implements CommandProcessor { } @Override - public boolean process(CommandSender sender, String command, String[] args) { + public boolean process(@NotNull CommandSender sender, @NotNull String command, @NotNull String[] args) { if (!sender.isPlayer()) return false; @@ -48,7 +50,7 @@ public class DimensionCommand implements CommandProcessor { } @Override - public boolean hasAccess(Player player) { + public boolean hasAccess(@NotNull Player player) { return true; } } diff --git a/src/test/java/demo/commands/ShutdownCommand.java b/src/test/java/demo/commands/ShutdownCommand.java index ef54e5d12..25000507e 100644 --- a/src/test/java/demo/commands/ShutdownCommand.java +++ b/src/test/java/demo/commands/ShutdownCommand.java @@ -4,12 +4,14 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandProcessor; import net.minestom.server.command.CommandSender; import net.minestom.server.entity.Player; +import org.jetbrains.annotations.NotNull; /** * A simple shutdown command. */ public class ShutdownCommand implements CommandProcessor { + @NotNull @Override public String getCommandName() { return "shutdown"; @@ -21,13 +23,13 @@ public class ShutdownCommand implements CommandProcessor { } @Override - public boolean process(CommandSender sender, String command, String[] args) { + public boolean process(@NotNull CommandSender sender, @NotNull String command, @NotNull String[] args) { MinecraftServer.stopCleanly(); return true; } @Override - public boolean hasAccess(Player player) { + public boolean hasAccess(@NotNull Player player) { return true; } } diff --git a/src/test/java/demo/commands/SimpleCommand.java b/src/test/java/demo/commands/SimpleCommand.java index be0bd4735..ae9ababc4 100644 --- a/src/test/java/demo/commands/SimpleCommand.java +++ b/src/test/java/demo/commands/SimpleCommand.java @@ -3,8 +3,10 @@ package demo.commands; import net.minestom.server.command.CommandProcessor; import net.minestom.server.command.CommandSender; import net.minestom.server.entity.Player; +import org.jetbrains.annotations.NotNull; public class SimpleCommand implements CommandProcessor { + @NotNull @Override public String getCommandName() { return "test"; @@ -16,11 +18,11 @@ public class SimpleCommand implements CommandProcessor { } @Override - public boolean process(CommandSender sender, String command, String[] args) { + public boolean process(@NotNull CommandSender sender, @NotNull String command, @NotNull String[] args) { if (!sender.isPlayer()) return false; - //sender.asPlayer().getInstance().saveChunksToStorage(() -> System.out.println("END SAVE")); + sender.asPlayer().getInstance().saveChunksToStorage(() -> System.out.println("END SAVE")); System.gc(); @@ -28,7 +30,7 @@ public class SimpleCommand implements CommandProcessor { } @Override - public boolean hasAccess(Player player) { + public boolean hasAccess(@NotNull Player player) { return true; } @@ -38,7 +40,7 @@ public class SimpleCommand implements CommandProcessor { } @Override - public String[] onWrite(String text) { + public String[] onWrite(@NotNull String text) { return new String[]{"Complete1", "Complete2"}; } }