diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 432eafa33eb..78c0b62d906 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -15,4 +15,4 @@ dependencies { implementation("net.kyori", "indra-publishing-sonatype", indraVersion) implementation("org.graalvm.buildtools", "native-gradle-plugin", "0.9.28") implementation("io.github.gradle-nexus", "publish-plugin", "2.0.0-rc-1") -} \ No newline at end of file +} diff --git a/code-generators/src/main/java/net/minestom/codegen/Generators.java b/code-generators/src/main/java/net/minestom/codegen/Generators.java index deddd0e9094..148c4bf0763 100644 --- a/code-generators/src/main/java/net/minestom/codegen/Generators.java +++ b/code-generators/src/main/java/net/minestom/codegen/Generators.java @@ -1,7 +1,6 @@ package net.minestom.codegen; import net.minestom.codegen.color.DyeColorGenerator; -import net.minestom.codegen.fluid.FluidGenerator; import net.minestom.codegen.particle.ParticleGenerator; import net.minestom.codegen.recipe.RecipeTypeGenerator; import org.slf4j.Logger; @@ -38,6 +37,9 @@ public static void main(String[] args) { generator.generate(resource("custom_statistics.json"), "net.minestom.server.statistic", "StatisticType", "StatisticTypeImpl", "StatisticTypes"); generator.generate(resource("attributes.json"), "net.minestom.server.entity.attribute", "Attribute", "AttributeImpl", "Attributes"); generator.generate(resource("feature_flags.json"), "net.minestom.server", "FeatureFlag", "FeatureFlagImpl", "FeatureFlags"); + generator.generate(resource("villager_professions.json"), "net.minestom.server.entity.villager", "VillagerProfession", "VillagerProfessionImpl", "VillagerProfessions"); + generator.generate(resource("villager_types.json"), "net.minestom.server.entity.villager", "VillagerType", "VillagerTypeImpl", "VillagerTypes"); + generator.generate(resource("fluids.json"), "net.minestom.server.fluid", "Fluid", "FluidImpl", "Fluids"); // Dynamic registries generator.generateKeys(resource("chat_types.json"), "net.minestom.server.message", "ChatType", "ChatTypes"); @@ -52,19 +54,6 @@ public static void main(String[] args) { generator.generateKeys(resource("painting_variants.json"), "net.minestom.server.entity.metadata.other", "PaintingMeta.Variant", "PaintingVariants"); generator.generateKeys(resource("jukebox_songs.json"), "net.minestom.server.instance.block.jukebox", "JukeboxSong", "JukeboxSongs"); - // Generate fluids - new FluidGenerator(resource("fluids.json"), outputFolder).generate(); - - // TODO: Generate villager professions -// new VillagerProfessionGenerator( -// new File(inputFolder, targetVersion + "_villager_professions.json"), -// outputFolder -// ).generate(); - // TODO: Generate villager types -// new VillagerTypeGenerator( -// new File(inputFolder, targetVersion + "_villager_types.json"), -// outputFolder -// ).generate(); LOGGER.info("Finished generating code"); } diff --git a/code-generators/src/main/java/net/minestom/codegen/MinestomCodeGenerator.java b/code-generators/src/main/java/net/minestom/codegen/MinestomCodeGenerator.java index eeb0c887e90..e9429b548b6 100644 --- a/code-generators/src/main/java/net/minestom/codegen/MinestomCodeGenerator.java +++ b/code-generators/src/main/java/net/minestom/codegen/MinestomCodeGenerator.java @@ -35,14 +35,6 @@ protected MinestomCodeGenerator() { return namespace.replace("minecraft:", "").toUpperCase(Locale.ROOT); } - protected static @NotNull String extractNamespaces(@NotNull String namespace, @NotNull Map arguments) { - if (arguments.isEmpty()) return extractNamespace(namespace); - - for (Map.Entry entry : arguments.entrySet()) { - namespace = namespace.replace(entry.getKey(), entry.getValue()); - } - return namespace.toUpperCase(Locale.ROOT); - } protected static String toConstant(String namespace) { return namespace.replace("minecraft:", "").toUpperCase(Locale.ROOT); diff --git a/code-generators/src/main/java/net/minestom/codegen/entity/VillagerProfessionGenerator.java b/code-generators/src/main/java/net/minestom/codegen/entity/VillagerProfessionGenerator.java deleted file mode 100644 index 9309c8ec68d..00000000000 --- a/code-generators/src/main/java/net/minestom/codegen/entity/VillagerProfessionGenerator.java +++ /dev/null @@ -1,194 +0,0 @@ -package net.minestom.codegen.entity; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.squareup.javapoet.*; -import net.minestom.codegen.MinestomCodeGenerator; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import net.minestom.codegen.util.GenerationHelper; - -import javax.lang.model.element.Modifier; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.List; - -import static net.minestom.codegen.util.GenerationHelper.*; - -@ApiStatus.NonExtendable -@ApiStatus.Internal -public final class VillagerProfessionGenerator extends MinestomCodeGenerator { - - private static final String VILLAGER_PROFESSION_DATE = "villagerProfessionData"; - private static final Logger LOGGER = LoggerFactory.getLogger(VillagerProfessionGenerator.class); - private final InputStream villagerProfessionsFile; - private final File outputFolder; - - - public VillagerProfessionGenerator(@Nullable InputStream villagerProfessionsFile, @NotNull File outputFolder) { - this.villagerProfessionsFile = villagerProfessionsFile; - this.outputFolder = outputFolder; - } - - @Override - public void generate() { - if (villagerProfessionsFile == null) { - LOGGER.error("Failed to find villager_professions.json."); - LOGGER.error("Stopped code generation for villager professions."); - return; - } - if (!outputFolder.exists() && !outputFolder.mkdirs()) { - LOGGER.error("Output folder for code generation does not exist and could not be created."); - return; - } - // Important classes we use alot - ClassName rawVillagerProfessionDataClassName = ClassName.get("net.minestom.server.raw_data", "RawVillagerProfessionData"); - - JsonArray villagerProfessions = GSON.fromJson(new InputStreamReader(villagerProfessionsFile), JsonArray.class); - ClassName villagerProfessionClassName = ClassName.get("net.minestom.server.entity.metadata.villager", "VillagerProfession"); - - // Particle - TypeSpec.Builder villagerProfessionClass = TypeSpec.classBuilder(villagerProfessionClassName) - .addSuperinterface(KEYORI_ADVENTURE_KEY) - .addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName()); - villagerProfessionClass.addField( - FieldSpec.builder(NAMESPACE_ID_CLASS, "id") - .addModifiers(Modifier.PRIVATE, Modifier.FINAL).addAnnotation(NotNull.class).build() - ); - villagerProfessionClass.addField( - FieldSpec.builder(rawVillagerProfessionDataClassName, VILLAGER_PROFESSION_DATE) - .addModifiers(Modifier.PRIVATE, Modifier.VOLATILE) - .addAnnotation(NotNull.class) - .build() - ); - villagerProfessionClass.addMethod( - MethodSpec.constructorBuilder() - .addParameter(ParameterSpec.builder(NAMESPACE_ID_CLASS, "id").addAnnotation(NotNull.class).build()) - .addParameter(ParameterSpec.builder(rawVillagerProfessionDataClassName, VILLAGER_PROFESSION_DATE).addAnnotation(NotNull.class).build()) - .addStatement(VARIABLE_SETTER, "id") - .addStatement(VARIABLE_SETTER, VILLAGER_PROFESSION_DATE) - .addModifiers(Modifier.PROTECTED) - .build() - ); - // Override key method (adventure) - villagerProfessionClass.addMethod(GenerationHelper.ADVENTURE_KEY_METHOD); - // getId method - villagerProfessionClass.addMethod(GenerationHelper.ID_GETTER); - // getVillagerProfessionData method - villagerProfessionClass.addMethod( - MethodSpec.methodBuilder("getVillagerProfessionData") - .returns(rawVillagerProfessionDataClassName) - .addAnnotation(NotNull.class) - .addStatement("return this.villagerProfessionData") - .addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .build() - ); - // setVillagerProfessionData method - villagerProfessionClass.addMethod( - MethodSpec.methodBuilder("setVillagerProfessionData") - .addParameter(ParameterSpec.builder(rawVillagerProfessionDataClassName, VILLAGER_PROFESSION_DATE).addAnnotation(NotNull.class).build()) - .addStatement("this.$L1 = $L1", VILLAGER_PROFESSION_DATE) - .addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .build() - ); - // getNumericalId - villagerProfessionClass.addMethod( - MethodSpec.methodBuilder("getNumericalId") - .returns(TypeName.INT) - .addStatement("return $T.VILLAGER_PROFESSION_REGISTRY.getId(this)", REGISTRY_CLASS) - .addModifiers(Modifier.PUBLIC) - .build() - ); - // fromId Method - villagerProfessionClass.addMethod( - MethodSpec.methodBuilder("fromId") - .returns(villagerProfessionClassName) - .addAnnotation(Nullable.class) - .addParameter(TypeName.INT, "id") - .addStatement("return $T.VILLAGER_PROFESSION_REGISTRY.get((short) id)", REGISTRY_CLASS) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .build() - ); - // fromId Method - villagerProfessionClass.addMethod( - MethodSpec.methodBuilder("fromId") - .returns(villagerProfessionClassName) - .addAnnotation(NotNull.class) - .addParameter(ADVENTURE_KEY, "id") - .addStatement("return $T.VILLAGER_PROFESSION_REGISTRY.get(id)", REGISTRY_CLASS) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .build() - ); - // toString method - villagerProfessionClass.addMethod(GenerationHelper.TO_STRING); - // values method - villagerProfessionClass.addMethod( - MethodSpec.methodBuilder("values") - .addAnnotation(NotNull.class) - .returns(ParameterizedTypeName.get(ClassName.get(List.class), villagerProfessionClassName)) - .addStatement("return $T.VILLAGER_PROFESSION_REGISTRY.values()", REGISTRY_CLASS) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .build() - ); - CodeBlock.Builder staticBlock = CodeBlock.builder(); - // Use data - for (JsonElement vp : villagerProfessions) { - JsonObject villagerProfession = vp.getAsJsonObject(); - - String villagerProfessionName = villagerProfession.get("name").getAsString(); - JsonElement workSound = villagerProfession.get("workSound"); - if (workSound == null) { - villagerProfessionClass.addField( - FieldSpec.builder( - villagerProfessionClassName, - villagerProfessionName - ).initializer( - "new $T($T.from($S), new $T(() -> null))", - villagerProfessionClassName, - NAMESPACE_ID_CLASS, - villagerProfession.get("id").getAsString(), - - rawVillagerProfessionDataClassName - ).addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).build() - ); - } else { - villagerProfessionClass.addField( - FieldSpec.builder( - villagerProfessionClassName, - villagerProfessionName - ).initializer( - "new $T($T.from($S), new $T(() -> $T.SOUND_EVENT_REGISTRY.get($S)))", - villagerProfessionClassName, - NAMESPACE_ID_CLASS, - villagerProfession.get("id").getAsString(), - - rawVillagerProfessionDataClassName, - REGISTRY_CLASS, - workSound.getAsString() - ).addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).build() - ); - } - - // Add to static init. - staticBlock.addStatement("$T.VILLAGER_PROFESSION_REGISTRY.register($N)", REGISTRY_CLASS, villagerProfessionName); - } - - villagerProfessionClass.addStaticBlock(staticBlock.build()); - - // Write files to outputFolder - writeFiles( - List.of( - JavaFile.builder("net.minestom.server.entity.metadata.villager", villagerProfessionClass.build()) - .indent(DEFAULT_INDENT) - .skipJavaLangImports(true) - .build() - ), - outputFolder - ); - } -} diff --git a/code-generators/src/main/java/net/minestom/codegen/entity/VillagerTypeGenerator.java b/code-generators/src/main/java/net/minestom/codegen/entity/VillagerTypeGenerator.java deleted file mode 100644 index 0f59af765a7..00000000000 --- a/code-generators/src/main/java/net/minestom/codegen/entity/VillagerTypeGenerator.java +++ /dev/null @@ -1,151 +0,0 @@ -package net.minestom.codegen.entity; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.squareup.javapoet.*; -import net.minestom.codegen.MinestomCodeGenerator; -import net.minestom.codegen.util.GenerationHelper; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.lang.model.element.Modifier; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.List; - -import static net.minestom.codegen.util.GenerationHelper.ADVENTURE_KEY; -import static net.minestom.codegen.util.GenerationHelper.TO_STRING; - -@ApiStatus.NonExtendable -@ApiStatus.Internal -public final class VillagerTypeGenerator extends MinestomCodeGenerator { - private static final Logger LOGGER = LoggerFactory.getLogger(VillagerTypeGenerator.class); - private final InputStream villagerTypesFile; - private final File outputFolder; - - public VillagerTypeGenerator(@Nullable InputStream villagerTypesFile, @NotNull File outputFolder) { - this.villagerTypesFile = villagerTypesFile; - this.outputFolder = outputFolder; - } - - @Override - public void generate() { - if (villagerTypesFile == null) { - LOGGER.error("Failed to find villager_types.json."); - LOGGER.error("Stopped code generation for villager types."); - return; - } - if (!outputFolder.exists() && !outputFolder.mkdirs()) { - LOGGER.error("Output folder for code generation does not exist and could not be created."); - return; - } - // Important classes we use alot - JsonArray villagerTypes = GSON.fromJson(new InputStreamReader(villagerTypesFile), JsonArray.class); - ClassName villagerTypeClassName = ClassName.get("net.minestom.server.entity.metadata.villager", "VillagerType"); - - // Particle - TypeSpec.Builder villagerTypeClass = TypeSpec.classBuilder(villagerTypeClassName) - .addSuperinterface(KEYORI_ADVENTURE_KEY) - .addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName()); - villagerTypeClass.addField( - FieldSpec.builder(NAMESPACE_ID_CLASS, "id") - .addModifiers(Modifier.PRIVATE, Modifier.FINAL).addAnnotation(NotNull.class).build() - ); - villagerTypeClass.addMethod( - MethodSpec.constructorBuilder() - .addParameter(ParameterSpec.builder(NAMESPACE_ID_CLASS, "id").addAnnotation(NotNull.class).build()) - .addStatement("this.id = id") - .addModifiers(Modifier.PROTECTED) - .build() - ); - // Override key method (adventure) - villagerTypeClass.addMethod(GenerationHelper.ID_GETTER); - // getId method - villagerTypeClass.addMethod( - MethodSpec.methodBuilder("getId") - .returns(NAMESPACE_ID_CLASS) - .addAnnotation(NotNull.class) - .addStatement("return this.id") - .addModifiers(Modifier.PUBLIC) - .build() - ); - // getNumericalId - villagerTypeClass.addMethod( - MethodSpec.methodBuilder("getNumericalId") - .returns(TypeName.INT) - .addStatement("return $T.VILLAGER_TYPE_REGISTRY.getId(this)", REGISTRY_CLASS) - .addModifiers(Modifier.PUBLIC) - .build() - ); - // fromId Method - villagerTypeClass.addMethod( - MethodSpec.methodBuilder("fromId") - .returns(villagerTypeClassName) - .addAnnotation(Nullable.class) - .addParameter(TypeName.INT, "id") - .addStatement("return $T.VILLAGER_TYPE_REGISTRY.get((short) id)", REGISTRY_CLASS) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .build() - ); - // fromId Method - villagerTypeClass.addMethod( - MethodSpec.methodBuilder("fromId") - .returns(villagerTypeClassName) - .addAnnotation(NotNull.class) - .addParameter(ADVENTURE_KEY, "id") - .addStatement("return $T.VILLAGER_TYPE_REGISTRY.get(id)", REGISTRY_CLASS) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .build() - ); - // toString method - villagerTypeClass.addMethod(TO_STRING); - // values method - villagerTypeClass.addMethod( - MethodSpec.methodBuilder("values") - .addAnnotation(NotNull.class) - .returns(ParameterizedTypeName.get(ClassName.get(List.class), villagerTypeClassName)) - .addStatement("return $T.VILLAGER_TYPE_REGISTRY.values()", REGISTRY_CLASS) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .build() - ); - CodeBlock.Builder staticBlock = CodeBlock.builder(); - // Use data - for (JsonElement vp : villagerTypes) { - JsonObject villagerProfession = vp.getAsJsonObject(); - - String villagerProfessionName = villagerProfession.get("name").getAsString(); - - villagerTypeClass.addField( - FieldSpec.builder( - villagerTypeClassName, - villagerProfessionName - ).initializer( - "new $T($T.from($S))", - villagerTypeClassName, - NAMESPACE_ID_CLASS, - villagerProfession.get("id").getAsString() - ).addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).build() - ); - // Add to static init. - staticBlock.addStatement("$T.VILLAGER_TYPE_REGISTRY.register($N)", REGISTRY_CLASS, villagerProfessionName); - } - - villagerTypeClass.addStaticBlock(staticBlock.build()); - - // Write files to outputFolder - writeFiles( - List.of( - JavaFile.builder("net.minestom.server.entity.metadata.villager", villagerTypeClass.build()) - .indent(DEFAULT_INDENT) - .skipJavaLangImports(true) - .build() - ), - outputFolder - ); - } -} diff --git a/code-generators/src/main/java/net/minestom/codegen/fluid/FluidGenerator.java b/code-generators/src/main/java/net/minestom/codegen/fluid/FluidGenerator.java deleted file mode 100644 index 070a89138fb..00000000000 --- a/code-generators/src/main/java/net/minestom/codegen/fluid/FluidGenerator.java +++ /dev/null @@ -1,141 +0,0 @@ -package net.minestom.codegen.fluid; - -import com.google.gson.JsonObject; -import com.squareup.javapoet.*; -import net.minestom.codegen.MinestomCodeGenerator; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.lang.model.element.Modifier; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; - -import static net.minestom.codegen.util.GenerationHelper.VARIABLE_SETTER; - -public final class FluidGenerator extends MinestomCodeGenerator { - private static final Logger LOGGER = LoggerFactory.getLogger(FluidGenerator.class); - private final InputStream fluidsFile; - private final File outputFolder; - - public FluidGenerator(@Nullable InputStream fluidsFile, @NotNull File outputFolder) { - this.fluidsFile = fluidsFile; - this.outputFolder = outputFolder; - } - - @Override - public void generate() { - if (fluidsFile == null) { - LOGGER.error("Failed to find fluids.json."); - LOGGER.error("Stopped code generation for fluids."); - return; - } - if (!outputFolder.exists() && !outputFolder.mkdirs()) { - LOGGER.error("Output folder for code generation does not exist and could not be created."); - return; - } - // Important classes we use alot - ClassName namespaceIDClassName = ClassName.get("net.minestom.server.utils", "NamespaceID"); - ClassName registriesClassName = ClassName.get("net.minestom.server.registry", "FluidRegistries"); - - JsonObject fluids = GSON.fromJson(new InputStreamReader(fluidsFile), JsonObject.class); - ClassName fluidClassName = ClassName.get("net.minestom.server.fluid", "Fluid"); - - // Particle - TypeSpec.Builder fluidClass = TypeSpec.enumBuilder(fluidClassName) - .addSuperinterface(ClassName.get("net.kyori.adventure.key", "Keyed")) - .addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName()); - - fluidClass.addField( - FieldSpec.builder(namespaceIDClassName, "id") - .addModifiers(PRIVATE_FINAL_MODIFIERS).addAnnotation(NotNull.class).build() - ); - // static field - fluidClass.addField( - FieldSpec.builder(ArrayTypeName.of(fluidClassName), "VALUES") - .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) - .initializer("values()") - .build() - ); - - fluidClass.addMethod( - MethodSpec.constructorBuilder() - .addParameter(ParameterSpec.builder(namespaceIDClassName, "id").addAnnotation(NotNull.class).build()) - .addStatement(VARIABLE_SETTER, "id") - .addStatement("$T.fluids.put(id, this)", registriesClassName) - .build() - ); - // Override key method (adventure) - fluidClass.addMethod( - MethodSpec.methodBuilder("key") - .returns(ClassName.get("net.kyori.adventure.key", "Key")) - .addAnnotation(Override.class) - .addAnnotation(NotNull.class) - .addStatement("return this.id") - .addModifiers(Modifier.PUBLIC) - .build() - ); - // getId method - fluidClass.addMethod( - MethodSpec.methodBuilder("getId") - .returns(TypeName.SHORT) - .addStatement("return (short) ordinal()") - .addModifiers(Modifier.PUBLIC) - .build() - ); - // getNamespaceID method - fluidClass.addMethod( - MethodSpec.methodBuilder("getNamespaceID") - .returns(namespaceIDClassName) - .addAnnotation(NotNull.class) - .addStatement("return this.id") - .addModifiers(Modifier.PUBLIC) - .build() - ); - // toString method - fluidClass.addMethod( - MethodSpec.methodBuilder("toString") - .addAnnotation(NotNull.class) - .addAnnotation(Override.class) - .returns(String.class) - // this resolves to [Namespace] - .addStatement("return \"[\" + this.id + \"]\"") - .addModifiers(Modifier.PUBLIC) - .build() - ); - - // fromId Method - fluidClass.addMethod( - MethodSpec.methodBuilder("fromId") - .returns(fluidClassName) - .addAnnotation(Nullable.class) - .addParameter(TypeName.SHORT, "id") - .beginControlFlow("if(id >= 0 && id < VALUES.length)") - .addStatement("return VALUES[id]") - .endControlFlow() - .addStatement("return null") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .build() - ); - - // Use data - fluids.entrySet().forEach(entry -> { - final String fluidName = entry.getKey(); - fluidClass.addEnumConstant(toConstant(fluidName), TypeSpec.anonymousClassBuilder( - "$T.from($S)", - namespaceIDClassName, - fluidName - ).build() - ); - }); - - // Write files to outputFolder - final JavaFile javaFile = JavaFile.builder("net.minestom.server.fluid", fluidClass.build()) - .indent(DEFAULT_INDENT) - .skipJavaLangImports(true) - .build(); - writeFile(javaFile, outputFolder); - } -} diff --git a/demo/src/main/java/net/minestom/demo/Main.java b/demo/src/main/java/net/minestom/demo/Main.java index 39c157b0913..087ca866b76 100644 --- a/demo/src/main/java/net/minestom/demo/Main.java +++ b/demo/src/main/java/net/minestom/demo/Main.java @@ -154,7 +154,7 @@ public boolean shouldShow(@NotNull Player player) { }; MinecraftServer.getRecipeManager().addRecipe(recipe); - PlayerInit.init(); + new PlayerInit().init(); // VelocityProxy.enable("abcdef"); //BungeeCordProxy.enable(); diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index 65c4d2fde7a..9311673fd6b 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -22,7 +22,16 @@ import net.minestom.server.event.entity.EntityAttackEvent; import net.minestom.server.event.item.ItemDropEvent; import net.minestom.server.event.item.PickupItemEvent; -import net.minestom.server.event.player.*; +import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; +import net.minestom.server.event.player.PlayerBlockInteractEvent; +import net.minestom.server.event.player.PlayerBlockPlaceEvent; +import net.minestom.server.event.player.PlayerDeathEvent; +import net.minestom.server.event.player.PlayerDisconnectEvent; +import net.minestom.server.event.player.PlayerHandAnimationEvent; +import net.minestom.server.event.player.PlayerPacketEvent; +import net.minestom.server.event.player.PlayerPacketOutEvent; +import net.minestom.server.event.player.PlayerSpawnEvent; +import net.minestom.server.event.player.PlayerUseItemOnBlockEvent; import net.minestom.server.event.server.ServerTickMonitorEvent; import net.minestom.server.instance.Instance; import net.minestom.server.instance.InstanceContainer; @@ -49,6 +58,7 @@ import net.minestom.server.potion.CustomPotionEffect; import net.minestom.server.potion.PotionEffect; import net.minestom.server.sound.SoundEvent; +import net.minestom.server.notifications.Notification; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.time.TimeUnit; @@ -62,9 +72,9 @@ public class PlayerInit { - private static final Inventory inventory; + private final Inventory inventory; - private static final EventNode DEMO_NODE = EventNode.all("demo") + private final EventNode DEMO_NODE = EventNode.all("demo") .addListener(EntityAttackEvent.class, event -> { final Entity source = event.getEntity(); final Entity entity = event.getTarget(); @@ -187,7 +197,6 @@ class A { .title(Component.text("Welcome!")) .icon(Material.IRON_SWORD).build(); notification.send(player); - player.playSound(Sound.sound(SoundEvent.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.PLAYER, 0.5f, 1f)); } }) @@ -225,7 +234,7 @@ class A { event.getInstance().setBlock(event.getBlockPosition(), block); }); - static { + { InstanceManager instanceManager = MinecraftServer.getInstanceManager(); InstanceContainer instanceContainer = instanceManager.createInstanceContainer(); @@ -260,9 +269,9 @@ class A { inventory.setItemStack(3, ItemStack.of(Material.DIAMOND, 34)); } - private static final AtomicReference LAST_TICK = new AtomicReference<>(); + private final AtomicReference LAST_TICK = new AtomicReference<>(); - public static void init() { + public void init() { var eventHandler = MinecraftServer.getGlobalEventHandler(); eventHandler.addChild(DEMO_NODE); diff --git a/src/autogenerated/java/net/minestom/server/color/DyeColor.java b/src/autogenerated/java/net/minestom/server/color/DyeColor.java index b5649ca07bd..4091cc1fa1b 100644 --- a/src/autogenerated/java/net/minestom/server/color/DyeColor.java +++ b/src/autogenerated/java/net/minestom/server/color/DyeColor.java @@ -46,7 +46,7 @@ public enum DyeColor implements RGBLike { public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumStringable(DyeColor.class); - private static final DyeColor[] VALUES = DyeColor.values(); + private static final DyeColor[] VALUES = values(); private final Color textureDiffuseColor; @@ -95,8 +95,7 @@ public int mapColorId() { return this.mapColorId; } - @Nullable - public static DyeColor getValue(int id) { + public static @Nullable DyeColor getValue(int id) { return VALUES[id]; } } diff --git a/src/autogenerated/java/net/minestom/server/entity/villager/VillagerProfessions.java b/src/autogenerated/java/net/minestom/server/entity/villager/VillagerProfessions.java new file mode 100644 index 00000000000..0f47b8b5050 --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/entity/villager/VillagerProfessions.java @@ -0,0 +1,37 @@ +package net.minestom.server.entity.villager; + +/** + * Code autogenerated, do not edit! + */ +@SuppressWarnings("unused") +interface VillagerProfessions { + VillagerProfession NONE = VillagerProfessionImpl.get("minecraft:none"); + + VillagerProfession ARMORER = VillagerProfessionImpl.get("minecraft:armorer"); + + VillagerProfession BUTCHER = VillagerProfessionImpl.get("minecraft:butcher"); + + VillagerProfession CARTOGRAPHER = VillagerProfessionImpl.get("minecraft:cartographer"); + + VillagerProfession CLERIC = VillagerProfessionImpl.get("minecraft:cleric"); + + VillagerProfession FARMER = VillagerProfessionImpl.get("minecraft:farmer"); + + VillagerProfession FISHERMAN = VillagerProfessionImpl.get("minecraft:fisherman"); + + VillagerProfession FLETCHER = VillagerProfessionImpl.get("minecraft:fletcher"); + + VillagerProfession LEATHERWORKER = VillagerProfessionImpl.get("minecraft:leatherworker"); + + VillagerProfession LIBRARIAN = VillagerProfessionImpl.get("minecraft:librarian"); + + VillagerProfession MASON = VillagerProfessionImpl.get("minecraft:mason"); + + VillagerProfession NITWIT = VillagerProfessionImpl.get("minecraft:nitwit"); + + VillagerProfession SHEPHERD = VillagerProfessionImpl.get("minecraft:shepherd"); + + VillagerProfession TOOLSMITH = VillagerProfessionImpl.get("minecraft:toolsmith"); + + VillagerProfession WEAPONSMITH = VillagerProfessionImpl.get("minecraft:weaponsmith"); +} diff --git a/src/autogenerated/java/net/minestom/server/entity/villager/VillagerTypes.java b/src/autogenerated/java/net/minestom/server/entity/villager/VillagerTypes.java new file mode 100644 index 00000000000..681ce44c1d3 --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/entity/villager/VillagerTypes.java @@ -0,0 +1,21 @@ +package net.minestom.server.entity.villager; + +/** + * Code autogenerated, do not edit! + */ +@SuppressWarnings("unused") +interface VillagerTypes { + VillagerType DESERT = VillagerTypeImpl.get("minecraft:desert"); + + VillagerType JUNGLE = VillagerTypeImpl.get("minecraft:jungle"); + + VillagerType PLAINS = VillagerTypeImpl.get("minecraft:plains"); + + VillagerType SAVANNA = VillagerTypeImpl.get("minecraft:savanna"); + + VillagerType SNOW = VillagerTypeImpl.get("minecraft:snow"); + + VillagerType SWAMP = VillagerTypeImpl.get("minecraft:swamp"); + + VillagerType TAIGA = VillagerTypeImpl.get("minecraft:taiga"); +} diff --git a/src/autogenerated/java/net/minestom/server/fluid/Fluid.java b/src/autogenerated/java/net/minestom/server/fluid/Fluid.java deleted file mode 100644 index e00575f9bbc..00000000000 --- a/src/autogenerated/java/net/minestom/server/fluid/Fluid.java +++ /dev/null @@ -1,62 +0,0 @@ -package net.minestom.server.fluid; - -import net.kyori.adventure.key.Key; -import net.kyori.adventure.key.Keyed; -import net.minestom.server.registry.FluidRegistries; -import net.minestom.server.utils.NamespaceID; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * AUTOGENERATED by FluidGenerator - */ -public enum Fluid implements Keyed { - EMPTY(NamespaceID.from("minecraft:empty")), - - FLOWING_WATER(NamespaceID.from("minecraft:flowing_water")), - - WATER(NamespaceID.from("minecraft:water")), - - FLOWING_LAVA(NamespaceID.from("minecraft:flowing_lava")), - - LAVA(NamespaceID.from("minecraft:lava")); - - private static final Fluid[] VALUES = values(); - - @NotNull - private final NamespaceID id; - - Fluid(@NotNull NamespaceID id) { - this.id = id; - FluidRegistries.fluids.put(id, this); - } - - @Override - @NotNull - public Key key() { - return this.id; - } - - public short getId() { - return (short) ordinal(); - } - - @NotNull - public NamespaceID getNamespaceID() { - return this.id; - } - - @NotNull - @Override - public String toString() { - return "[" + this.id + "]"; - } - - @Nullable - public static Fluid fromId(short id) { - if(id >= 0 && id < VALUES.length) { - return VALUES[id]; - } - return null; - } -} diff --git a/src/autogenerated/java/net/minestom/server/fluid/Fluids.java b/src/autogenerated/java/net/minestom/server/fluid/Fluids.java new file mode 100644 index 00000000000..27157009e9e --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/fluid/Fluids.java @@ -0,0 +1,17 @@ +package net.minestom.server.fluid; + +/** + * Code autogenerated, do not edit! + */ +@SuppressWarnings("unused") +interface Fluids { + Fluid EMPTY = FluidImpl.get("minecraft:empty"); + + Fluid FLOWING_WATER = FluidImpl.get("minecraft:flowing_water"); + + Fluid WATER = FluidImpl.get("minecraft:water"); + + Fluid FLOWING_LAVA = FluidImpl.get("minecraft:flowing_lava"); + + Fluid LAVA = FluidImpl.get("minecraft:lava"); +} diff --git a/src/autogenerated/java/net/minestom/server/registry/FluidRegistries.java b/src/autogenerated/java/net/minestom/server/registry/FluidRegistries.java deleted file mode 100644 index f6e23118b11..00000000000 --- a/src/autogenerated/java/net/minestom/server/registry/FluidRegistries.java +++ /dev/null @@ -1,45 +0,0 @@ -// AUTOGENERATED by net.minestom.codegen.RegistriesGenerator -package net.minestom.server.registry; - -import net.kyori.adventure.key.Key; -import net.minestom.server.fluid.Fluid; -import net.minestom.server.utils.NamespaceID; -import org.jetbrains.annotations.NotNull; - -import java.util.HashMap; - -/** - * AUTOGENERATED - */ -public final class FluidRegistries { - - /** - * Should only be used for internal code, please use the get* methods. - */ - @Deprecated - public static final HashMap fluids = new HashMap<>(); - - /** - * Returns the corresponding Fluid matching the given id. Returns 'EMPTY' if none match. - */ - @NotNull - public static Fluid getFluid(String id) { - return getFluid(NamespaceID.from(id)); - } - - /** - * Returns the corresponding Fluid matching the given id. Returns 'EMPTY' if none match. - */ - @NotNull - public static Fluid getFluid(NamespaceID id) { - return fluids.getOrDefault(id, Fluid.EMPTY); - } - - /** - * Returns the corresponding Fluid matching the given key. Returns 'EMPTY' if none match. - */ - @NotNull - public static Fluid getFluid(Key key) { - return getFluid(NamespaceID.from(key)); - } -} diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 598173d7021..d834b46270d 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -36,6 +36,7 @@ import net.minestom.server.effects.Effects; import net.minestom.server.entity.attribute.Attribute; import net.minestom.server.entity.damage.DamageType; +import net.minestom.server.entity.metadata.EntityMeta; import net.minestom.server.entity.metadata.LivingEntityMeta; import net.minestom.server.entity.metadata.PlayerMeta; import net.minestom.server.entity.vehicle.PlayerVehicleInformation; @@ -1062,6 +1063,10 @@ public void setHealth(float health) { return (PlayerMeta) super.getEntityMeta(); } + protected @NotNull EntityMeta getUnsafeEntityMeta() { + return super.getEntityMeta(); + } + /** * Gets the player additional hearts. * diff --git a/src/main/java/net/minestom/server/entity/metadata/monster/zombie/ZombieVillagerMeta.java b/src/main/java/net/minestom/server/entity/metadata/monster/zombie/ZombieVillagerMeta.java index 66023cc1212..ea04af22fb9 100644 --- a/src/main/java/net/minestom/server/entity/metadata/monster/zombie/ZombieVillagerMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/monster/zombie/ZombieVillagerMeta.java @@ -4,6 +4,8 @@ import net.minestom.server.entity.Metadata; import net.minestom.server.entity.MetadataHolder; import net.minestom.server.entity.metadata.villager.VillagerMeta; +import net.minestom.server.entity.villager.VillagerProfession; +import net.minestom.server.entity.villager.VillagerType; import org.jetbrains.annotations.NotNull; public class ZombieVillagerMeta extends ZombieMeta { @@ -25,15 +27,15 @@ public void setConverting(boolean value) { public VillagerMeta.VillagerData getVillagerData() { int[] data = super.metadata.getIndex(OFFSET + 1, null); if (data == null) { - return new VillagerMeta.VillagerData(VillagerMeta.Type.PLAINS, VillagerMeta.Profession.NONE, VillagerMeta.Level.NOVICE); + return new VillagerMeta.VillagerData(VillagerType.PLAINS, VillagerProfession.NONE, VillagerMeta.Level.NOVICE); } - return new VillagerMeta.VillagerData(VillagerMeta.Type.VALUES[data[0]], VillagerMeta.Profession.VALUES[data[1]], VillagerMeta.Level.VALUES[data[2] - 1]); + return new VillagerMeta.VillagerData(VillagerType.fromId(data[0]), VillagerProfession.fromId(data[1]), VillagerMeta.Level.VALUES[data[2] - 1]); } public void setVillagerData(VillagerMeta.VillagerData data) { super.metadata.setIndex(OFFSET + 1, Metadata.VillagerData( - data.getType().ordinal(), - data.getProfession().ordinal(), + data.getType().id(), + data.getProfession().id(), data.getLevel().ordinal() + 1 )); } diff --git a/src/main/java/net/minestom/server/entity/metadata/villager/VillagerMeta.java b/src/main/java/net/minestom/server/entity/metadata/villager/VillagerMeta.java index aa72c04c097..6fd0de565c7 100644 --- a/src/main/java/net/minestom/server/entity/metadata/villager/VillagerMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/villager/VillagerMeta.java @@ -2,6 +2,8 @@ import net.minestom.server.entity.Entity; import net.minestom.server.entity.Metadata; +import net.minestom.server.entity.villager.VillagerProfession; +import net.minestom.server.entity.villager.VillagerType; import net.minestom.server.entity.MetadataHolder; import org.jetbrains.annotations.NotNull; @@ -17,46 +19,46 @@ public VillagerMeta(@NotNull Entity entity, @NotNull MetadataHolder metadata) { public VillagerData getVillagerData() { int[] data = super.metadata.getIndex(OFFSET, null); if (data == null) { - return new VillagerData(Type.PLAINS, Profession.NONE, Level.NOVICE); + return new VillagerData(VillagerType.PLAINS, VillagerProfession.NONE, Level.NOVICE); } - return new VillagerData(Type.VALUES[data[0]], Profession.VALUES[data[1]], Level.VALUES[data[2] - 1]); + return new VillagerData(VillagerType.fromId(data[0]), VillagerProfession.fromId(data[1]), Level.VALUES[data[2] - 1]); } public void setVillagerData(@NotNull VillagerData data) { super.metadata.setIndex(OFFSET, Metadata.VillagerData( - data.type.ordinal(), - data.profession.ordinal(), + data.type.id(), + data.profession.id(), data.level.ordinal() + 1 )); } public static class VillagerData { - private Type type; - private Profession profession; + private VillagerType type; + private VillagerProfession profession; private Level level; - public VillagerData(@NotNull Type type, @NotNull Profession profession, @NotNull Level level) { + public VillagerData(@NotNull VillagerType type, @NotNull VillagerProfession profession, @NotNull Level level) { this.type = type; this.profession = profession; this.level = level; } @NotNull - public Type getType() { + public VillagerType getType() { return this.type; } - public void setType(@NotNull Type type) { + public void setType(@NotNull VillagerType type) { this.type = type; } @NotNull - public Profession getProfession() { + public VillagerProfession getProfession() { return this.profession; } - public void setProfession(@NotNull Profession profession) { + public void setProfession(@NotNull VillagerProfession profession) { this.profession = profession; } @@ -70,39 +72,6 @@ public void setLevel(@NotNull Level level) { } } - public enum Type { - DESERT, - JUNGLE, - PLAINS, - SAVANNA, - SNOW, - SWAMP, - TAIGA; - - public final static Type[] VALUES = values(); - } - - public enum Profession { - NONE, - ARMORER, - BUTCHER, - CARTOGRAPHER, - CLERIC, - FARMER, - FISHERMAN, - FLETCHER, - LEATHERWORKER, - LIBRARIAN, - NITWIT, - UNEMPLOYED, - MASON, - SHEPHERD, - TOOLSMITH, - WEAPONSMITH; - - public final static Profession[] VALUES = values(); - } - public enum Level { NOVICE, APPRENTICE, diff --git a/src/main/java/net/minestom/server/entity/pathfinding/Navigator.java b/src/main/java/net/minestom/server/entity/pathfinding/Navigator.java index 79ab7874ea3..01d3081d708 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/Navigator.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/Navigator.java @@ -43,8 +43,8 @@ public Navigator(@NotNull Entity entity) { nodeFollower = new GroundNodeFollower(entity); } - public @NotNull PPath.PathState getState() { - if (path == null && computingPath == null) return PPath.PathState.INVALID; + public @NotNull PPath.State getState() { + if (path == null && computingPath == null) return PPath.State.INVALID; if (path == null) return computingPath.getState(); return path.getState(); } @@ -62,11 +62,11 @@ public synchronized boolean setPathTo(@Nullable Point point, double minimumDista /** * Sets the path to {@code position} and ask the entity to follow the path. * - * @param point the position to find the path to, null to reset the pathfinder + * @param point the position to find the path to, null to reset the pathfinder * @param minimumDistance distance to target when completed - * @param maxDistance maximum search distance - * @param pathVariance how far to search off of the direct path. For open worlds, this can be low (around 20) and for large mazes this needs to be very high. - * @param onComplete called when the path has been completed + * @param maxDistance maximum search distance + * @param pathVariance how far to search off of the direct path. For open worlds, this can be low (around 20) and for large mazes this needs to be very high. + * @param onComplete called when the path has been completed * @return true if a path is being generated */ public synchronized boolean setPathTo(@Nullable Point point, double minimumDistance, double maxDistance, double pathVariance, @Nullable Runnable onComplete) { @@ -104,13 +104,13 @@ public synchronized boolean setPathTo(@Nullable Point point, double minimumDista return false; } - if (this.computingPath != null) this.computingPath.setState(PPath.PathState.TERMINATING); + if (this.computingPath != null) this.computingPath.setState(PPath.State.TERMINATING); this.computingPath = PathGenerator.generate(instance, - this.entity.getPosition(), - point, - minimumDistance, maxDistance, - pathVariance, + this.entity.getPosition(), + point, + minimumDistance, maxDistance, + pathVariance, this.entity.getBoundingBox(), this.entity.isOnGround(), this.nodeGenerator, @@ -123,8 +123,9 @@ public synchronized boolean setPathTo(@Nullable Point point, double minimumDista @ApiStatus.Internal public synchronized void tick() { if (goalPosition == null) return; // No path - if (entity instanceof LivingEntity && ((LivingEntity) entity).isDead()) return; // No pathfinding tick for dead entities - if (computingPath != null && (computingPath.getState() == PPath.PathState.COMPUTED || computingPath.getState() == PPath.PathState.BEST_EFFORT)) { + if (entity instanceof LivingEntity && ((LivingEntity) entity).isDead()) + return; // No pathfinding tick for dead entities + if (computingPath != null && (computingPath.getState() == PPath.State.COMPUTED || computingPath.getState() == PPath.State.BEST_EFFORT)) { path = computingPath; computingPath = null; } @@ -132,8 +133,8 @@ public synchronized void tick() { if (path == null) return; // If the path is computed start following it - if (path.getState() == PPath.PathState.COMPUTED || path.getState() == PPath.PathState.BEST_EFFORT) { - path.setState(PPath.PathState.FOLLOWING); + if (path.getState() == PPath.State.COMPUTED || path.getState() == PPath.State.BEST_EFFORT) { + path.setState(PPath.State.FOLLOWING); // Remove nodes that are too close to the start. Prevents doubling back to hit points that have already been hit for (int i = 0; i < path.getNodes().size(); i++) { if (isSameBlock(path.getNodes().get(i), entity.getPosition())) { @@ -144,7 +145,7 @@ public synchronized void tick() { } // If the state is not following, wait until it is - if (path.getState() != PPath.PathState.FOLLOWING) return; + if (path.getState() != PPath.State.FOLLOWING) return; // If we're near the entity, we're done if (this.entity.getPosition().distance(goalPosition) < minimumDistance) { @@ -158,8 +159,8 @@ public synchronized void tick() { Point nextTarget = path.getNext(); // Repath - if (currentTarget == null || path.getCurrentType() == PNode.NodeType.REPATH || path.getCurrentType() == null) { - if (computingPath != null && computingPath.getState() == PPath.PathState.CALCULATING) return; + if (currentTarget == null || path.getCurrentType() == PNode.Type.REPATH || path.getCurrentType() == null) { + if (computingPath != null && computingPath.getState() == PPath.State.CALCULATING) return; computingPath = PathGenerator.generate(entity.getInstance(), entity.getPosition(), @@ -171,7 +172,7 @@ public synchronized void tick() { } if (nextTarget == null) { - path.setState(PPath.PathState.INVALID); + path.setState(PPath.State.INVALID); return; } @@ -179,7 +180,7 @@ public synchronized void tick() { nodeFollower.moveTowards(currentTarget, nodeFollower.movementSpeed(), nextIsRepath ? currentTarget : nextTarget); if (nodeFollower.isAtPoint(currentTarget)) path.next(); - else if (path.getCurrentType() == PNode.NodeType.JUMP) nodeFollower.jump(currentTarget, nextTarget); + else if (path.getCurrentType() == PNode.Type.JUMP) nodeFollower.jump(currentTarget, nextTarget); } /** @@ -201,11 +202,11 @@ public synchronized void tick() { } public void reset() { - if (this.path != null) this.path.setState(PPath.PathState.TERMINATING); + if (this.path != null) this.path.setState(PPath.State.TERMINATING); this.goalPosition = null; this.path = null; - if (this.computingPath != null) this.computingPath.setState(PPath.PathState.TERMINATING); + if (this.computingPath != null) this.computingPath.setState(PPath.State.TERMINATING); this.computingPath = null; } @@ -234,6 +235,7 @@ public void setNodeGenerator(@NotNull Supplier nodeGenerator) { /** * Visualise path for debugging + * * @param path the path to draw */ private void drawPath(PPath path) { diff --git a/src/main/java/net/minestom/server/entity/pathfinding/PNode.java b/src/main/java/net/minestom/server/entity/pathfinding/PNode.java index d51a15f93c9..919a274ad0a 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/PNode.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/PNode.java @@ -1,13 +1,12 @@ package net.minestom.server.entity.pathfinding; import net.minestom.server.coordinate.Point; -import net.minestom.server.coordinate.Vec; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class PNode { - public enum NodeType { + public enum Type { WALK, JUMP, FALL, @@ -25,19 +24,13 @@ public enum NodeType { private double pointZ; private int hashCode; - private int cantor(int a, int b) { - int ca = a >= 0 ? 2 * a : -2 * a - 1; - int cb = b >= 0 ? 2 * b : -2 * b - 1; - return (ca + cb + 1) * (ca + cb) / 2 + cb; - } - - private NodeType type; + private Type type; public PNode(double px, double py, double pz, double g, double h, @Nullable PNode parent) { - this(px, py, pz, g, h, NodeType.WALK, parent); + this(px, py, pz, g, h, Type.WALK, parent); } - public PNode(double px, double py, double pz, double g, double h, @NotNull NodeType type, @Nullable PNode parent) { + public PNode(double px, double py, double pz, double g, double h, @NotNull PNode.Type type, @Nullable PNode parent) { this.g = g; this.h = h; this.parent = parent; @@ -48,7 +41,7 @@ public PNode(double px, double py, double pz, double g, double h, @NotNull NodeT this.hashCode = cantor((int) Math.floor(px), cantor((int) Math.floor(py), (int) Math.floor(pz))); } - public PNode(Point point, double g, double h, NodeType walk, @Nullable PNode parent) { + public PNode(Point point, double g, double h, Type walk, @Nullable PNode parent) { this(point.x(), point.y(), point.z(), g, h, walk, parent); } @@ -102,7 +95,7 @@ public int blockZ() { } @ApiStatus.Internal - @NotNull NodeType getType() { + @NotNull Type getType() { return type; } @@ -127,7 +120,7 @@ public void setH(double heuristic) { } @ApiStatus.Internal - public void setType(@NotNull NodeType newType) { + public void setType(@NotNull PNode.Type newType) { this.type = newType; } @@ -148,4 +141,10 @@ public void setPoint(double px, double py, double pz) { public void setParent(@Nullable PNode current) { this.parent = current; } + + private static int cantor(int a, int b) { + int ca = a >= 0 ? 2 * a : -2 * a - 1; + int cb = b >= 0 ? 2 * b : -2 * b - 1; + return (ca + cb + 1) * (ca + cb) / 2 + cb; + } } diff --git a/src/main/java/net/minestom/server/entity/pathfinding/PPath.java b/src/main/java/net/minestom/server/entity/pathfinding/PPath.java index d3af3a0f042..84ce07ecc58 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/PPath.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/PPath.java @@ -9,14 +9,14 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; -public class PPath { +public final class PPath { private final Runnable onComplete; private final List nodes = new ArrayList<>(); private final double pathVariance; private final double maxDistance; private int index = 0; - private final AtomicReference state = new AtomicReference<>(PathState.CALCULATING); + private final AtomicReference state = new AtomicReference<>(State.CALCULATING); public Point getNext() { if (index + 1 >= nodes.size()) return null; @@ -24,17 +24,17 @@ public Point getNext() { return new Vec(current.x(), current.y(), current.z()); } - public void setState(@NotNull PathState newState) { + public void setState(@NotNull PPath.State newState) { state.set(newState); } - public enum PathState { + public enum State { CALCULATING, FOLLOWING, TERMINATING, TERMINATED, COMPUTED, BEST_EFFORT, INVALID } - @NotNull PathState getState() { + @NotNull State getState() { return state.get(); } @@ -57,15 +57,13 @@ void runComplete() { return nodes.toString(); } - @Nullable - PNode.NodeType getCurrentType() { + @Nullable PNode.Type getCurrentType() { if (index >= nodes.size()) return null; var current = nodes.get(index); return current.getType(); } - @Nullable - Point getCurrent() { + @Nullable Point getCurrent() { if (index >= nodes.size()) return null; var current = nodes.get(index); return new Vec(current.x(), current.y(), current.z()); diff --git a/src/main/java/net/minestom/server/entity/pathfinding/PathGenerator.java b/src/main/java/net/minestom/server/entity/pathfinding/PathGenerator.java index eab43400202..b80a4211981 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/PathGenerator.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/PathGenerator.java @@ -6,38 +6,39 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.pathfinding.generators.NodeGenerator; -import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -public class PathGenerator { - private static final ExecutorService pool = Executors.newWorkStealingPool(); +public final class PathGenerator { private static final Comparator pNodeComparator = (s1, s2) -> (int) (((s1.g() + s1.h()) - (s2.g() + s2.h())) * 1000); - public static @NotNull PPath generate(@NotNull Instance instance, @NotNull Pos orgStart, @NotNull Point orgTarget, double closeDistance, double maxDistance, double pathVariance, @NotNull BoundingBox boundingBox, boolean isOnGround, @NotNull NodeGenerator generator, @Nullable Runnable onComplete) { - Point start = (!isOnGround && generator.hasGravitySnap()) - ? orgStart.withY(generator.gravitySnap(instance, orgStart.x(), orgStart.y(), orgStart.z(), boundingBox, 100).orElse(orgStart.y())) + public static @NotNull PPath generate(Block.@NotNull Getter getter, @NotNull Pos orgStart, @NotNull Point orgTarget, + double closeDistance, double maxDistance, double pathVariance, + @NotNull BoundingBox boundingBox, boolean isOnGround, @NotNull NodeGenerator generator, + @Nullable Runnable onComplete) { + final Point start = (!isOnGround && generator.hasGravitySnap()) + ? orgStart.withY(generator.gravitySnap(getter, orgStart.x(), orgStart.y(), orgStart.z(), boundingBox, 100).orElse(orgStart.y())) : orgStart; - Point target = (generator.hasGravitySnap()) - ? orgTarget.withY(generator.gravitySnap(instance, orgTarget.x(), orgTarget.y(), orgTarget.z(), boundingBox, 100).orElse(orgTarget.y())) + final Point target = (generator.hasGravitySnap()) + ? orgTarget.withY(generator.gravitySnap(getter, orgTarget.x(), orgTarget.y(), orgTarget.z(), boundingBox, 100).orElse(orgTarget.y())) : Pos.fromPoint(orgTarget); PPath path = new PPath(maxDistance, pathVariance, onComplete); - pool.submit(() -> computePath(instance, start, target, closeDistance, maxDistance, pathVariance, boundingBox, path, generator)); - + computePath(getter, start, target, closeDistance, maxDistance, pathVariance, boundingBox, path, generator); return path; } private static PNode buildRepathNode(PNode parent) { - return new PNode(0, 0, 0, 0, 0, PNode.NodeType.REPATH, parent); + return new PNode(0, 0, 0, 0, 0, PNode.Type.REPATH, parent); } - private static void computePath(Instance instance, Point start, Point target, double closeDistance, double maxDistance, double pathVariance, BoundingBox boundingBox, PPath path, NodeGenerator generator) { + private static void computePath(Block.Getter getter, Point start, Point target, + double closeDistance, double maxDistance, double pathVariance, + BoundingBox boundingBox, PPath path, NodeGenerator generator) { double closestDistance = Double.MAX_VALUE; double straightDistance = generator.heuristic(start, target); int maxSize = (int) Math.floor(maxDistance * 10); @@ -45,7 +46,7 @@ private static void computePath(Instance instance, Point start, Point target, do closeDistance = Math.max(0.8, closeDistance); List closestFoundNodes = List.of(); - PNode pStart = new PNode(start, 0, generator.heuristic(start, target), PNode.NodeType.WALK, null); + PNode pStart = new PNode(start, 0, generator.heuristic(start, target), PNode.Type.WALK, null); ObjectHeapPriorityQueue open = new ObjectHeapPriorityQueue<>(pNodeComparator); open.enqueue(pStart); @@ -53,16 +54,16 @@ private static void computePath(Instance instance, Point start, Point target, do Set closed = new ObjectOpenHashBigSet<>(maxSize); while (!open.isEmpty() && closed.size() < maxSize) { - if (path.getState() == PPath.PathState.TERMINATING) { - path.setState(PPath.PathState.TERMINATED); + if (path.getState() == PPath.State.TERMINATING) { + path.setState(PPath.State.TERMINATED); return; } PNode current = open.dequeue(); - var chunk = instance.getChunkAt(current.x(), current.z()); - if (chunk == null) continue; - if (!chunk.isLoaded()) continue; + //var chunk = instance.getChunkAt(current.x(), current.z()); + //if (chunk == null) continue; + //if (!chunk.isLoaded()) continue; if (((current.g() + current.h()) - straightDistance) > pathVariance) continue; if (!withinDistance(current, start, maxDistance)) continue; @@ -76,7 +77,7 @@ private static void computePath(Instance instance, Point start, Point target, do closestFoundNodes = List.of(current); } - Collection found = generator.getWalkable(instance, closed, current, target, boundingBox); + Collection found = generator.getWalkable(getter, closed, current, target, boundingBox); found.forEach(p -> { if (getDistanceSquared(p.x(), p.y(), p.z(), start) <= (maxDistance * maxDistance)) { open.enqueue(p); @@ -89,7 +90,7 @@ private static void computePath(Instance instance, Point start, Point target, do if (current == null || open.isEmpty() || !withinDistance(current, target, closeDistance)) { if (closestFoundNodes.isEmpty()) { - path.setState(PPath.PathState.INVALID); + path.setState(PPath.State.INVALID); return; } @@ -107,21 +108,21 @@ private static void computePath(Instance instance, Point start, Point target, do Collections.reverse(path.getNodes()); - if (path.getCurrentType() == PNode.NodeType.REPATH) { - path.setState(PPath.PathState.INVALID); + if (path.getCurrentType() == PNode.Type.REPATH) { + path.setState(PPath.State.INVALID); path.getNodes().clear(); return; } var lastNode = path.getNodes().get(path.getNodes().size() - 1); if (getDistanceSquared(lastNode.x(), lastNode.y(), lastNode.z(), target) > (closeDistance * closeDistance)) { - path.setState(PPath.PathState.BEST_EFFORT); + path.setState(PPath.State.BEST_EFFORT); return; } - PNode pEnd = new PNode(target, 0, 0, PNode.NodeType.WALK, null); + PNode pEnd = new PNode(target, 0, 0, PNode.Type.WALK, null); path.getNodes().add(pEnd); - path.setState(PPath.PathState.COMPUTED); + path.setState(PPath.State.COMPUTED); } private static boolean withinDistance(PNode point, Point target, double closeDistance) { diff --git a/src/main/java/net/minestom/server/entity/pathfinding/generators/FlyingNodeGenerator.java b/src/main/java/net/minestom/server/entity/pathfinding/generators/FlyingNodeGenerator.java index c3ecf4a81a1..54a55738168 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/generators/FlyingNodeGenerator.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/generators/FlyingNodeGenerator.java @@ -4,7 +4,7 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.pathfinding.PNode; -import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -16,7 +16,7 @@ public class FlyingNodeGenerator implements NodeGenerator { private PNode tempNode = null; @Override - public @NotNull Collection getWalkable(@NotNull Instance instance, @NotNull Set visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox) { + public @NotNull Collection getWalkable(Block.@NotNull Getter getter, @NotNull Set visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox) { Collection nearby = new ArrayList<>(); tempNode = new PNode(0, 0, 0, 0, 0, current); @@ -40,13 +40,13 @@ public class FlyingNodeGenerator implements NodeGenerator { double downPointY = current.blockY() - 1 + 0.5; double downPointZ = current.blockZ() + 0.5 + z; - var nodeWalk = createFly(instance, new Vec(currentLevelPointX, currentLevelPointY, currentLevelPointZ), boundingBox, cost, current, goal, visited); + var nodeWalk = createFly(getter, new Vec(currentLevelPointX, currentLevelPointY, currentLevelPointZ), boundingBox, cost, current, goal, visited); if (nodeWalk != null && !visited.contains(nodeWalk)) nearby.add(nodeWalk); - var nodeJump = createFly(instance, new Vec(upPointX, upPointY, upPointZ), boundingBox, cost, current, goal, visited); + var nodeJump = createFly(getter, new Vec(upPointX, upPointY, upPointZ), boundingBox, cost, current, goal, visited); if (nodeJump != null && !visited.contains(nodeJump)) nearby.add(nodeJump); - var nodeFall = createFly(instance, new Vec(downPointX, downPointY, downPointZ), boundingBox, cost, current, goal, visited); + var nodeFall = createFly(getter, new Vec(downPointX, downPointY, downPointZ), boundingBox, cost, current, goal, visited); if (nodeFall != null && !visited.contains(nodeFall)) nearby.add(nodeFall); } } @@ -56,7 +56,7 @@ public class FlyingNodeGenerator implements NodeGenerator { double upPointY = current.blockY() + 1 + 0.5; double upPointZ = current.z(); - var nodeJump = createFly(instance, new Vec(upPointX, upPointY, upPointZ), boundingBox, 2, current, goal, visited); + var nodeJump = createFly(getter, new Vec(upPointX, upPointY, upPointZ), boundingBox, 2, current, goal, visited); if (nodeJump != null && !visited.contains(nodeJump)) nearby.add(nodeJump); // Straight down @@ -64,7 +64,7 @@ public class FlyingNodeGenerator implements NodeGenerator { double downPointY = current.blockY() - 1 + 0.5; double downPointZ = current.z(); - var nodeFall = createFly(instance, new Vec(downPointX, downPointY, downPointZ), boundingBox, 2, current, goal, visited); + var nodeFall = createFly(getter, new Vec(downPointX, downPointY, downPointZ), boundingBox, 2, current, goal, visited); if (nodeFall != null && !visited.contains(nodeFall)) nearby.add(nodeFall); return nearby; @@ -75,11 +75,11 @@ public boolean hasGravitySnap() { return false; } - private PNode createFly(Instance instance, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { + private PNode createFly(Block.Getter getter, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { var n = newNode(start, cost, point, goal); if (closed.contains(n)) return null; - if (!canMoveTowards(instance, new Vec(start.x(), start.y(), start.z()), point, boundingBox)) return null; - n.setType(PNode.NodeType.FLY); + if (!canMoveTowards(getter, new Vec(start.x(), start.y(), start.z()), point, boundingBox)) return null; + n.setType(PNode.Type.FLY); return n; } @@ -89,13 +89,13 @@ private PNode newNode(PNode current, double cost, Point point, Point goal) { tempNode.setPoint(point.x(), point.y(), point.z()); var newNode = tempNode; - tempNode = new PNode(0, 0, 0, 0, 0, PNode.NodeType.WALK, current); + tempNode = new PNode(0, 0, 0, 0, 0, PNode.Type.WALK, current); return newNode; } @Override - public @NotNull OptionalDouble gravitySnap(@NotNull Instance instance, double pointX, double pointY, double pointZ, @NotNull BoundingBox boundingBox, double maxFall) { + public @NotNull OptionalDouble gravitySnap(Block.@NotNull Getter getter, double pointX, double pointY, double pointZ, @NotNull BoundingBox boundingBox, double maxFall) { return OptionalDouble.of(pointY); } } diff --git a/src/main/java/net/minestom/server/entity/pathfinding/generators/GroundNodeGenerator.java b/src/main/java/net/minestom/server/entity/pathfinding/generators/GroundNodeGenerator.java index 63f9e83a340..42eb38f07e5 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/generators/GroundNodeGenerator.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/generators/GroundNodeGenerator.java @@ -4,8 +4,6 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.pathfinding.PNode; -import net.minestom.server.instance.Chunk; -import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import org.jetbrains.annotations.NotNull; @@ -20,7 +18,7 @@ public class GroundNodeGenerator implements NodeGenerator { private final static int MAX_FALL_DISTANCE = 5; @Override - public @NotNull Collection getWalkable(@NotNull Instance instance, @NotNull Set visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox) { + public @NotNull Collection getWalkable(Block.@NotNull Getter getter, @NotNull Set visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox) { Collection nearby = new ArrayList<>(); tempNode = new PNode(0, 0, 0, 0, 0, current); @@ -36,23 +34,23 @@ public class GroundNodeGenerator implements NodeGenerator { double floorPointY = current.blockY(); double floorPointZ = current.blockZ() + 0.5 + z; - var optionalFloorPointY = gravitySnap(instance, floorPointX, floorPointY, floorPointZ, boundingBox, MAX_FALL_DISTANCE); + var optionalFloorPointY = gravitySnap(getter, floorPointX, floorPointY, floorPointZ, boundingBox, MAX_FALL_DISTANCE); if (optionalFloorPointY.isEmpty()) continue; floorPointY = optionalFloorPointY.getAsDouble(); var floorPoint = new Vec(floorPointX, floorPointY, floorPointZ); - var nodeWalk = createWalk(instance, floorPoint, boundingBox, cost, current, goal, visited); + var nodeWalk = createWalk(getter, floorPoint, boundingBox, cost, current, goal, visited); if (nodeWalk != null && !visited.contains(nodeWalk)) nearby.add(nodeWalk); for (int i = 1; i <= 1; ++i) { Point jumpPoint = new Vec(current.blockX() + 0.5 + x, current.blockY() + i, current.blockZ() + 0.5 + z); - OptionalDouble jumpPointY = gravitySnap(instance, jumpPoint.x(), jumpPoint.y(), jumpPoint.z(), boundingBox, MAX_FALL_DISTANCE); + OptionalDouble jumpPointY = gravitySnap(getter, jumpPoint.x(), jumpPoint.y(), jumpPoint.z(), boundingBox, MAX_FALL_DISTANCE); if (jumpPointY.isEmpty()) continue; jumpPoint = jumpPoint.withY(jumpPointY.getAsDouble()); if (!floorPoint.sameBlock(jumpPoint)) { - var nodeJump = createJump(instance, jumpPoint, boundingBox, cost + 0.2, current, goal, visited); + var nodeJump = createJump(getter, jumpPoint, boundingBox, cost + 0.2, current, goal, visited); if (nodeJump != null && !visited.contains(nodeJump)) nearby.add(nodeJump); } } @@ -62,26 +60,22 @@ public class GroundNodeGenerator implements NodeGenerator { return nearby; } - @Override - public boolean hasGravitySnap() { - return true; - } - - private PNode createWalk(Instance instance, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { + private PNode createWalk(Block.Getter getter, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { var n = newNode(start, cost, point, goal); if (closed.contains(n)) return null; if (Math.abs(point.y() - start.y()) > Vec.EPSILON && point.y() < start.y()) { if (start.y() - point.y() > MAX_FALL_DISTANCE) return null; - if (!canMoveTowards(instance, new Vec(start.x(), start.y(), start.z()), point.withY(start.y()), boundingBox)) return null; - n.setType(PNode.NodeType.FALL); + if (!canMoveTowards(getter, new Vec(start.x(), start.y(), start.z()), point.withY(start.y()), boundingBox)) + return null; + n.setType(PNode.Type.FALL); } else { - if (!canMoveTowards(instance, new Vec(start.x(), start.y(), start.z()), point, boundingBox)) return null; + if (!canMoveTowards(getter, new Vec(start.x(), start.y(), start.z()), point, boundingBox)) return null; } return n; } - private PNode createJump(Instance instance, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { + private PNode createJump(Block.Getter getter, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { if (Math.abs(point.y() - start.y()) < Vec.EPSILON) return null; if (point.y() - start.y() > 2) return null; if (point.blockX() != start.blockX() && point.blockZ() != start.blockZ()) return null; @@ -89,10 +83,10 @@ private PNode createJump(Instance instance, Point point, BoundingBox boundingBox var n = newNode(start, cost, point, goal); if (closed.contains(n)) return null; - if (pointInvalid(instance, point, boundingBox)) return null; - if (pointInvalid(instance, new Vec(start.x(), start.y() + 1, start.z()), boundingBox)) return null; + if (pointInvalid(getter, point, boundingBox)) return null; + if (pointInvalid(getter, new Vec(start.x(), start.y() + 1, start.z()), boundingBox)) return null; - n.setType(PNode.NodeType.JUMP); + n.setType(PNode.Type.JUMP); return n; } @@ -102,32 +96,35 @@ private PNode newNode(PNode current, double cost, Point point, Point goal) { tempNode.setPoint(point.x(), point.y(), point.z()); var newNode = tempNode; - tempNode = new PNode(0, 0, 0, 0, 0, PNode.NodeType.WALK, current); + tempNode = new PNode(0, 0, 0, 0, 0, PNode.Type.WALK, current); return newNode; } @Override - public @NotNull OptionalDouble gravitySnap(@NotNull Instance instance, double pointOrgX, double pointOrgY, double pointOrgZ, @NotNull BoundingBox boundingBox, double maxFall) { - double pointX = (int) Math.floor(pointOrgX) + 0.5; - double pointY = (int) Math.floor(pointOrgY); - double pointZ = (int) Math.floor(pointOrgZ) + 0.5; + public boolean hasGravitySnap() { + return true; + } + + @Override + public @NotNull OptionalDouble gravitySnap(Block.@NotNull Getter getter, double pointOrgX, double pointOrgY, double pointOrgZ, @NotNull BoundingBox boundingBox, double maxFall) { + final double pointX = (int) Math.floor(pointOrgX) + 0.5; + final double pointY = (int) Math.floor(pointOrgY); + final double pointZ = (int) Math.floor(pointOrgZ) + 0.5; - Chunk c = instance.getChunkAt(pointX, pointZ); - if (c == null) return OptionalDouble.of(pointY); + //Chunk c = instance.getChunkAt(pointX, pointZ); + //if (c == null) return OptionalDouble.of(pointY); for (int axis = 1; axis <= maxFall; ++axis) { pointIterator.reset(boundingBox, pointX, pointY, pointZ, BoundingBox.AxisMask.Y, -axis); while (pointIterator.hasNext()) { var block = pointIterator.next(); - - if (instance.getBlock(block.blockX(), block.blockY(), block.blockZ(), Block.Getter.Condition.TYPE).isSolid()) { + if (getter.getBlock(block.blockX(), block.blockY(), block.blockZ(), Block.Getter.Condition.TYPE).isSolid()) { return OptionalDouble.of(block.blockY() + 1); } } } - return OptionalDouble.empty(); } } diff --git a/src/main/java/net/minestom/server/entity/pathfinding/generators/NodeGenerator.java b/src/main/java/net/minestom/server/entity/pathfinding/generators/NodeGenerator.java index 247158b4a87..b54aa5cb869 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/generators/NodeGenerator.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/generators/NodeGenerator.java @@ -7,7 +7,6 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.pathfinding.PNode; -import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import org.jetbrains.annotations.NotNull; @@ -19,14 +18,15 @@ public interface NodeGenerator { /** * Gets the walkable nodes. * - * @param instance the instance + * @param getter the instance * @param visited the visited nodes * @param current the current node * @param goal the goal * @param boundingBox the bounding box * @return the walkable nodes */ - @NotNull Collection getWalkable(@NotNull Instance instance, @NotNull Set visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox); + @NotNull Collection getWalkable(Block.@NotNull Getter getter, @NotNull Set visited, + @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox); /** * @return snap start and end points to the ground @@ -35,44 +35,49 @@ public interface NodeGenerator { /** * Snap point to the ground - * @param instance the instance - * @param pointX the x coordinate - * @param pointY the y coordinate - * @param pointZ the z coordinate + * + * @param getter the block getter + * @param pointX the x coordinate + * @param pointY the y coordinate + * @param pointZ the z coordinate * @param boundingBox the bounding box - * @param maxFall the maximum fall distance + * @param maxFall the maximum fall distance * @return the snapped y coordinate. Empty if the snap point is not found */ - @NotNull OptionalDouble gravitySnap(@NotNull Instance instance, double pointX, double pointY, double pointZ, @NotNull BoundingBox boundingBox, double maxFall); + @NotNull OptionalDouble gravitySnap(Block.@NotNull Getter getter, double pointX, double pointY, double pointZ, + @NotNull BoundingBox boundingBox, double maxFall); /** * Check if we can move directly from one point to another - * @param instance + * + * @param getter * @param start * @param end * @param boundingBox * @return true if we can move directly from start to end */ - default boolean canMoveTowards(@NotNull Instance instance, @NotNull Point start, @NotNull Point end, @NotNull BoundingBox boundingBox) { - Point diff = end.sub(start); + default boolean canMoveTowards(Block.@NotNull Getter getter, @NotNull Point start, @NotNull Point end, @NotNull BoundingBox boundingBox) { + final Point diff = end.sub(start); - if (instance.getBlock(end) != Block.AIR) return false; - PhysicsResult res = CollisionUtils.handlePhysics(instance, instance.getChunkAt(start), boundingBox, Pos.fromPoint(start), Vec.fromPoint(diff), null, false); + if (getter.getBlock(end) != Block.AIR) return false; + PhysicsResult res = CollisionUtils.handlePhysics(getter, boundingBox, + Pos.fromPoint(start), Vec.fromPoint(diff), null, false); return !res.collisionZ() && !res.collisionY() && !res.collisionX(); } /** * Check if the point is invalid - * @param instance + * + * @param getter * @param point * @param boundingBox * @return true if the point is invalid */ - default boolean pointInvalid(@NotNull Instance instance, @NotNull Point point, @NotNull BoundingBox boundingBox) { + default boolean pointInvalid(Block.@NotNull Getter getter, @NotNull Point point, @NotNull BoundingBox boundingBox) { var iterator = boundingBox.getBlocks(point); while (iterator.hasNext()) { var block = iterator.next(); - if (instance.getBlock(block.blockX(), block.blockY(), block.blockZ(), Block.Getter.Condition.TYPE).isSolid()) { + if (getter.getBlock(block.blockX(), block.blockY(), block.blockZ(), Block.Getter.Condition.TYPE).isSolid()) { return true; } } @@ -82,6 +87,7 @@ default boolean pointInvalid(@NotNull Instance instance, @NotNull Point point, @ /** * Heuristic use for the distance from the node to the target + * * @param node * @param target * @return the heuristic diff --git a/src/main/java/net/minestom/server/entity/pathfinding/generators/PreciseGroundNodeGenerator.java b/src/main/java/net/minestom/server/entity/pathfinding/generators/PreciseGroundNodeGenerator.java index cec5992dc85..fee1a72a653 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/generators/PreciseGroundNodeGenerator.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/generators/PreciseGroundNodeGenerator.java @@ -7,7 +7,7 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.pathfinding.PNode; -import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -20,7 +20,7 @@ public class PreciseGroundNodeGenerator implements NodeGenerator { private final static int MAX_FALL_DISTANCE = 5; @Override - public @NotNull Collection getWalkable(@NotNull Instance instance, @NotNull Set visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox) { + public @NotNull Collection getWalkable(Block.@NotNull Getter getter, @NotNull Set visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox) { Collection nearby = new ArrayList<>(); tempNode = new PNode(0, 0, 0, 0, 0, current); @@ -36,23 +36,23 @@ public class PreciseGroundNodeGenerator implements NodeGenerator { double floorPointY = current.y(); double floorPointZ = current.blockZ() + 0.5 + z; - var optionalFloorPointY = gravitySnap(instance, floorPointX, floorPointY, floorPointZ, boundingBox, MAX_FALL_DISTANCE); + var optionalFloorPointY = gravitySnap(getter, floorPointX, floorPointY, floorPointZ, boundingBox, MAX_FALL_DISTANCE); if (optionalFloorPointY.isEmpty()) continue; floorPointY = optionalFloorPointY.getAsDouble(); var floorPoint = new Vec(floorPointX, floorPointY, floorPointZ); - var nodeWalk = createWalk(instance, floorPoint, boundingBox, cost, current, goal, visited); + var nodeWalk = createWalk(getter, floorPoint, boundingBox, cost, current, goal, visited); if (nodeWalk != null && !visited.contains(nodeWalk)) nearby.add(nodeWalk); for (int i = 1; i <= 1; ++i) { Point jumpPoint = new Vec(current.blockX() + 0.5 + x, current.y() + i, current.blockZ() + 0.5 + z); - OptionalDouble jumpPointY = gravitySnap(instance, jumpPoint.x(), jumpPoint.y(), jumpPoint.z(), boundingBox, MAX_FALL_DISTANCE); + OptionalDouble jumpPointY = gravitySnap(getter, jumpPoint.x(), jumpPoint.y(), jumpPoint.z(), boundingBox, MAX_FALL_DISTANCE); if (jumpPointY.isEmpty()) continue; jumpPoint = jumpPoint.withY(jumpPointY.getAsDouble()); if (!floorPoint.sameBlock(jumpPoint)) { - var nodeJump = createJump(instance, jumpPoint, boundingBox, cost + 0.8, current, goal, visited); + var nodeJump = createJump(getter, jumpPoint, boundingBox, cost + 0.8, current, goal, visited); if (nodeJump != null && !visited.contains(nodeJump)) nearby.add(nodeJump); } } @@ -62,13 +62,8 @@ public class PreciseGroundNodeGenerator implements NodeGenerator { return nearby; } - @Override - public boolean hasGravitySnap() { - return true; - } - - private PNode createWalk(Instance instance, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { - var snapped = gravitySnap(instance, point.x(), point.y(), point.z(), boundingBox, MAX_FALL_DISTANCE); + private PNode createWalk(Block.Getter getter, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { + var snapped = gravitySnap(getter, point.x(), point.y(), point.z(), boundingBox, MAX_FALL_DISTANCE); if (snapped.isPresent()) { var snappedPoint = new Vec(point.x(), snapped.getAsDouble(), point.z()); @@ -82,12 +77,12 @@ private PNode createWalk(Instance instance, Point point, BoundingBox boundingBox if (start.y() - snappedPoint.y() > MAX_FALL_DISTANCE) { return null; } - if (!canMoveTowards(instance, new Vec(start.x(), start.y(), start.z()), snappedPoint.withY(start.y()), boundingBox)) { + if (!canMoveTowards(getter, new Vec(start.x(), start.y(), start.z()), snappedPoint.withY(start.y()), boundingBox)) { return null; } - n.setType(PNode.NodeType.FALL); + n.setType(PNode.Type.FALL); } else { - if (!canMoveTowards(instance, new Vec(start.x(), start.y(), start.z()), snappedPoint, boundingBox)) { + if (!canMoveTowards(getter, new Vec(start.x(), start.y(), start.z()), snappedPoint, boundingBox)) { return null; } } @@ -98,7 +93,7 @@ private PNode createWalk(Instance instance, Point point, BoundingBox boundingBox } } - private PNode createJump(Instance instance, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { + private PNode createJump(Block.Getter getter, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { if (Math.abs(point.y() - start.y()) < Vec.EPSILON) return null; if (point.y() - start.y() > 2) return null; if (point.blockX() != start.blockX() && point.blockZ() != start.blockZ()) return null; @@ -106,10 +101,10 @@ private PNode createJump(Instance instance, Point point, BoundingBox boundingBox var n = newNode(start, cost, point, goal); if (closed.contains(n)) return null; - if (pointInvalid(instance, point, boundingBox)) return null; - if (pointInvalid(instance, new Vec(start.x(), start.y() + 1, start.z()), boundingBox)) return null; + if (pointInvalid(getter, point, boundingBox)) return null; + if (pointInvalid(getter, new Vec(start.x(), start.y() + 1, start.z()), boundingBox)) return null; - n.setType(PNode.NodeType.JUMP); + n.setType(PNode.Type.JUMP); return n; } @@ -119,26 +114,32 @@ private PNode newNode(PNode current, double cost, Point point, Point goal) { tempNode.setPoint(point.x(), point.y(), point.z()); var newNode = tempNode; - tempNode = new PNode(0, 0, 0, 0, 0, PNode.NodeType.WALK, current); + tempNode = new PNode(0, 0, 0, 0, 0, PNode.Type.WALK, current); return newNode; } @Override - public @NotNull OptionalDouble gravitySnap(@NotNull Instance instance, double pointOrgX, double pointOrgY, double pointOrgZ, @NotNull BoundingBox boundingBox, double maxFall) { - double pointX = (int) Math.floor(pointOrgX) + 0.5; - double pointZ = (int) Math.floor(pointOrgZ) + 0.5; - var res= CollisionUtils.handlePhysics(instance, boundingBox, new Pos(pointX, pointOrgY, pointZ), new Vec(0, -MAX_FALL_DISTANCE, 0), null, true); - return OptionalDouble.of(res.newPosition().y()); + public boolean hasGravitySnap() { + return true; } @Override - public boolean canMoveTowards(@NotNull Instance instance, @NotNull Point startOrg, @NotNull Point endOrg, @NotNull BoundingBox boundingBox) { - var end = endOrg.add(0, Vec.EPSILON, 0); - var start = startOrg.add(0, Vec.EPSILON, 0); + public @NotNull OptionalDouble gravitySnap(Block.@NotNull Getter getter, double pointOrgX, double pointOrgY, double pointOrgZ, @NotNull BoundingBox boundingBox, double maxFall) { + final double pointX = (int) Math.floor(pointOrgX) + 0.5; + final double pointZ = (int) Math.floor(pointOrgZ) + 0.5; + final PhysicsResult res = CollisionUtils.handlePhysics(getter, boundingBox, + new Pos(pointX, pointOrgY, pointZ), new Vec(0, -MAX_FALL_DISTANCE, 0), + null, true); + return OptionalDouble.of(res.newPosition().y()); + } - Point diff = end.sub(start); - PhysicsResult res = CollisionUtils.handlePhysics(instance, instance.getChunkAt(start), boundingBox, Pos.fromPoint(start), Vec.fromPoint(diff), null, false); + @Override + public boolean canMoveTowards(Block.@NotNull Getter getter, @NotNull Point startOrg, @NotNull Point endOrg, @NotNull BoundingBox boundingBox) { + final Point end = endOrg.add(0, Vec.EPSILON, 0); + final Point start = startOrg.add(0, Vec.EPSILON, 0); + final Point diff = end.sub(start); + PhysicsResult res = CollisionUtils.handlePhysics(getter, boundingBox, Pos.fromPoint(start), Vec.fromPoint(diff), null, false); return !res.collisionZ() && !res.collisionY() && !res.collisionX(); } } diff --git a/src/main/java/net/minestom/server/entity/pathfinding/generators/WaterNodeGenerator.java b/src/main/java/net/minestom/server/entity/pathfinding/generators/WaterNodeGenerator.java index 97d83eacd41..5d2fa64d271 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/generators/WaterNodeGenerator.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/generators/WaterNodeGenerator.java @@ -4,8 +4,6 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.pathfinding.PNode; -import net.minestom.server.instance.Chunk; -import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import org.jetbrains.annotations.NotNull; @@ -19,7 +17,7 @@ public class WaterNodeGenerator implements NodeGenerator { private final BoundingBox.PointIterator pointIterator = new BoundingBox.PointIterator(); @Override - public @NotNull Collection getWalkable(@NotNull Instance instance, @NotNull Set visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox) { + public @NotNull Collection getWalkable(Block.@NotNull Getter getter, @NotNull Set visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox) { Collection nearby = new ArrayList<>(); tempNode = new PNode(0, 0, 0, 0, 0, current); @@ -43,18 +41,18 @@ public class WaterNodeGenerator implements NodeGenerator { double downPointY = current.blockY() - 1 + 0.5; double downPointZ = current.blockZ() + 0.5 + z; - if (instance.getBlock((int) Math.floor(currentLevelPointX), (int) Math.floor(currentLevelPointY), (int) Math.floor(currentLevelPointZ)).compare(Block.WATER)) { - var nodeWalk = createFly(instance, new Vec(currentLevelPointX, currentLevelPointY, currentLevelPointZ), boundingBox, cost, current, goal, visited); + if (getter.getBlock((int) Math.floor(currentLevelPointX), (int) Math.floor(currentLevelPointY), (int) Math.floor(currentLevelPointZ)).compare(Block.WATER)) { + var nodeWalk = createFly(getter, new Vec(currentLevelPointX, currentLevelPointY, currentLevelPointZ), boundingBox, cost, current, goal, visited); if (nodeWalk != null && !visited.contains(nodeWalk)) nearby.add(nodeWalk); } - if (instance.getBlock((int) Math.floor(upPointX), (int) Math.floor(upPointY), (int) Math.floor(upPointZ)).compare(Block.WATER)) { - var nodeJump = createFly(instance, new Vec(upPointX, upPointY, upPointZ), boundingBox, cost, current, goal, visited); + if (getter.getBlock((int) Math.floor(upPointX), (int) Math.floor(upPointY), (int) Math.floor(upPointZ)).compare(Block.WATER)) { + var nodeJump = createFly(getter, new Vec(upPointX, upPointY, upPointZ), boundingBox, cost, current, goal, visited); if (nodeJump != null && !visited.contains(nodeJump)) nearby.add(nodeJump); } - if (instance.getBlock((int) Math.floor(downPointX), (int) Math.floor(downPointY), (int) Math.floor(downPointZ)).compare(Block.WATER)) { - var nodeFall = createFly(instance, new Vec(downPointX, downPointY, downPointZ), boundingBox, cost, current, goal, visited); + if (getter.getBlock((int) Math.floor(downPointX), (int) Math.floor(downPointY), (int) Math.floor(downPointZ)).compare(Block.WATER)) { + var nodeFall = createFly(getter, new Vec(downPointX, downPointY, downPointZ), boundingBox, cost, current, goal, visited); if (nodeFall != null && !visited.contains(nodeFall)) nearby.add(nodeFall); } } @@ -65,8 +63,8 @@ public class WaterNodeGenerator implements NodeGenerator { double upPointY = current.blockY() + 1 + 0.5; double upPointZ = current.z(); - if (instance.getBlock((int) Math.floor(upPointX), (int) Math.floor(upPointY), (int) Math.floor(upPointZ)).compare(Block.WATER)) { - var nodeJump = createFly(instance, new Vec(current.x(), current.y(), current.z()), boundingBox, 2, current, goal, visited); + if (getter.getBlock((int) Math.floor(upPointX), (int) Math.floor(upPointY), (int) Math.floor(upPointZ)).compare(Block.WATER)) { + var nodeJump = createFly(getter, new Vec(current.x(), current.y(), current.z()), boundingBox, 2, current, goal, visited); if (nodeJump != null && !visited.contains(nodeJump)) nearby.add(nodeJump); } @@ -75,24 +73,19 @@ public class WaterNodeGenerator implements NodeGenerator { double downPointY = current.blockY() - 1 + 0.5; double downPointZ = current.z(); - if (instance.getBlock((int) Math.floor(downPointX), (int) Math.floor(downPointY), (int) Math.floor(downPointZ)).compare(Block.WATER)) { - var nodeFall = createFly(instance, new Vec(downPointX, downPointY, downPointZ), boundingBox, 2, current, goal, visited); + if (getter.getBlock((int) Math.floor(downPointX), (int) Math.floor(downPointY), (int) Math.floor(downPointZ)).compare(Block.WATER)) { + var nodeFall = createFly(getter, new Vec(downPointX, downPointY, downPointZ), boundingBox, 2, current, goal, visited); if (nodeFall != null && !visited.contains(nodeFall)) nearby.add(nodeFall); } return nearby; } - @Override - public boolean hasGravitySnap() { - return false; - } - - private PNode createFly(Instance instance, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { + private PNode createFly(Block.Getter getter, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set closed) { var n = newNode(start, cost, point, goal); if (closed.contains(n)) return null; - if (!canMoveTowards(instance, new Vec(start.x(), start.y(), start.z()), point, boundingBox)) return null; - n.setType(PNode.NodeType.FLY); + if (!canMoveTowards(getter, new Vec(start.x(), start.y(), start.z()), point, boundingBox)) return null; + n.setType(PNode.Type.FLY); return n; } @@ -102,33 +95,18 @@ private PNode newNode(PNode current, double cost, Point point, Point goal) { tempNode.setPoint(point.x(), point.y(), point.z()); var newNode = tempNode; - tempNode = new PNode(0, 0, 0, 0, 0, PNode.NodeType.WALK, current); + tempNode = new PNode(0, 0, 0, 0, 0, PNode.Type.WALK, current); return newNode; } - public @NotNull OptionalDouble gravitySnap(@NotNull Instance instance, double pointOrgX, double pointOrgY, double pointOrgZ, @NotNull BoundingBox boundingBox, double maxFall) { - double pointX = (int) Math.floor(pointOrgX) + 0.5; - double pointY = (int) Math.floor(pointOrgY); - double pointZ = (int) Math.floor(pointOrgZ) + 0.5; - - Chunk c = instance.getChunkAt(pointX, pointZ); - if (c == null) return OptionalDouble.of(pointY); - - for (int axis = 1; axis <= maxFall; ++axis) { - pointIterator.reset(boundingBox, pointX, pointY, pointZ, BoundingBox.AxisMask.Y, -axis); - - while (pointIterator.hasNext()) { - var block = pointIterator.next(); - - var foundBlock = instance.getBlock(block.blockX(), block.blockY(), block.blockZ(), Block.Getter.Condition.TYPE); - // Stop falling when water is hit - if (foundBlock.isSolid() || foundBlock.compare(Block.WATER)) { - return OptionalDouble.of(block.blockY() + 1); - } - } - } + @Override + public boolean hasGravitySnap() { + return false; + } - return OptionalDouble.empty(); + @Override + public @NotNull OptionalDouble gravitySnap(Block.@NotNull Getter getter, double pointX, double pointY, double pointZ, @NotNull BoundingBox boundingBox, double maxFall) { + return OptionalDouble.of(pointY); } } diff --git a/src/main/java/net/minestom/server/entity/villager/VillagerProfession.java b/src/main/java/net/minestom/server/entity/villager/VillagerProfession.java new file mode 100644 index 00000000000..faf65662f88 --- /dev/null +++ b/src/main/java/net/minestom/server/entity/villager/VillagerProfession.java @@ -0,0 +1,42 @@ +package net.minestom.server.entity.villager; + +import net.kyori.adventure.key.Key; +import net.minestom.server.registry.Registry; +import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +public interface VillagerProfession extends StaticProtocolObject, VillagerProfessions { + static @NotNull Collection<@NotNull VillagerProfession> values() { + return VillagerProfessionImpl.values(); + } + + static @Nullable VillagerProfession fromNamespaceId(@NotNull String namespaceID) { + return VillagerProfessionImpl.getSafe(namespaceID); + } + + static @Nullable VillagerProfession fromNamespaceId(@NotNull NamespaceID namespaceID) { + return fromNamespaceId(namespaceID.asString()); + } + + static @Nullable VillagerProfession fromId(int id) { + return VillagerProfessionImpl.getId(id); + } + + @Override + default @NotNull Key key() { + return StaticProtocolObject.super.key(); + } + + @Contract(pure = true) + Registry.VillagerProfession registry(); + + @Override + default @NotNull NamespaceID namespace() { + return registry().namespace(); + } +} diff --git a/src/main/java/net/minestom/server/entity/villager/VillagerProfessionImpl.java b/src/main/java/net/minestom/server/entity/villager/VillagerProfessionImpl.java new file mode 100644 index 00000000000..338cbb39e3f --- /dev/null +++ b/src/main/java/net/minestom/server/entity/villager/VillagerProfessionImpl.java @@ -0,0 +1,39 @@ +package net.minestom.server.entity.villager; + +import net.minestom.server.registry.Registry; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +public record VillagerProfessionImpl(Registry.VillagerProfession registry, int id) implements VillagerProfession { + private static final Registry.Container CONTAINER = Registry.createStaticContainer(Registry.Resource.VILLAGER_PROFESSION, VillagerProfessionImpl::createImpl); + + public VillagerProfessionImpl(Registry.VillagerProfession registry) { + this(registry, registry.id()); + } + + private static VillagerProfession createImpl(String namespace, Registry.Properties properties) { + return new VillagerProfessionImpl(Registry.villagerProfession(namespace, properties)); + } + + static VillagerProfession get(@NotNull String namespace) { + return CONTAINER.get(namespace); + } + + static VillagerProfession getSafe(@NotNull String namespace) { + return CONTAINER.getSafe(namespace); + } + + static VillagerProfession getId(int id) { + return CONTAINER.getId(id); + } + + static Collection values() { + return CONTAINER.values(); + } + + @Override + public String toString() { + return name(); + } +} diff --git a/src/main/java/net/minestom/server/entity/villager/VillagerType.java b/src/main/java/net/minestom/server/entity/villager/VillagerType.java new file mode 100644 index 00000000000..ac8fcfd4f21 --- /dev/null +++ b/src/main/java/net/minestom/server/entity/villager/VillagerType.java @@ -0,0 +1,43 @@ +package net.minestom.server.entity.villager; + +import net.kyori.adventure.key.Key; +import net.minestom.server.registry.Registry; +import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +public sealed interface VillagerType extends StaticProtocolObject, VillagerTypes permits VillagerTypeImpl { + + static @NotNull Collection<@NotNull VillagerType> values() { + return VillagerTypeImpl.values(); + } + + static @Nullable VillagerType fromNamespaceId(@NotNull String namespaceID) { + return VillagerTypeImpl.getSafe(namespaceID); + } + + static @Nullable VillagerType fromNamespaceId(@NotNull NamespaceID namespaceID) { + return fromNamespaceId(namespaceID.asString()); + } + + static @Nullable VillagerType fromId(int id) { + return VillagerTypeImpl.getId(id); + } + + @Override + default @NotNull Key key() { + return StaticProtocolObject.super.key(); + } + + @Contract(pure = true) + Registry.VillagerType registry(); + + @Override + default @NotNull NamespaceID namespace() { + return registry().namespace(); + } +} diff --git a/src/main/java/net/minestom/server/entity/villager/VillagerTypeImpl.java b/src/main/java/net/minestom/server/entity/villager/VillagerTypeImpl.java new file mode 100644 index 00000000000..ec8af984f09 --- /dev/null +++ b/src/main/java/net/minestom/server/entity/villager/VillagerTypeImpl.java @@ -0,0 +1,39 @@ +package net.minestom.server.entity.villager; + +import net.minestom.server.registry.Registry; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +public record VillagerTypeImpl(Registry.VillagerType registry, int id) implements VillagerType { + private static final Registry.Container CONTAINER = Registry.createStaticContainer(Registry.Resource.VILLAGER_TYPES, VillagerTypeImpl::createImpl); + + public VillagerTypeImpl(Registry.VillagerType registry) { + this(registry, registry.id()); + } + + private static VillagerType createImpl(String namespace, Registry.Properties properties) { + return new VillagerTypeImpl(Registry.villagerType(namespace, properties)); + } + + static VillagerType get(@NotNull String namespace) { + return CONTAINER.get(namespace); + } + + static VillagerType getSafe(@NotNull String namespace) { + return CONTAINER.getSafe(namespace); + } + + static VillagerType getId(int id) { + return CONTAINER.getId(id); + } + + static Collection values() { + return CONTAINER.values(); + } + + @Override + public String toString() { + return name(); + } +} diff --git a/src/main/java/net/minestom/server/event/entity/EntityTeleportEvent.java b/src/main/java/net/minestom/server/event/entity/EntityTeleportEvent.java new file mode 100644 index 00000000000..d9b4eb58c74 --- /dev/null +++ b/src/main/java/net/minestom/server/event/entity/EntityTeleportEvent.java @@ -0,0 +1,56 @@ +package net.minestom.server.event.entity; + +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.RelativeFlags; +import net.minestom.server.event.trait.EntityEvent; +import net.minestom.server.utils.position.PositionUtils; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; + +/** + * Called with {@link Entity#teleport(Pos)} and its overloads. + */ +public class EntityTeleportEvent implements EntityEvent { + + private final Entity entity; + private final Pos teleportPosition; + private final int relativeFlags; + + public EntityTeleportEvent(@NotNull Entity entity, @NotNull Pos teleportPosition, @MagicConstant(flagsFromClass = RelativeFlags.class) int relativeFlags) { + this.entity = entity; + this.teleportPosition = teleportPosition; + this.relativeFlags = relativeFlags; + } + + /** + * @return The {@link Entity} that teleported. + */ + @NotNull + @Override + public Entity getEntity() { + return entity; + } + + /** + * @return The position that the {@link Entity} is about to teleport to. This is an absolute position. + */ + public @NotNull Pos getNewPosition() { + return PositionUtils.getPositionWithRelativeFlags(this.getEntity().getPosition(), getTeleportPosition(), relativeFlags); + } + + /** + * @return The position that the {@link Entity} is about to teleport to. This may be (partially) relative depending on the flags. + */ + public @NotNull Pos getTeleportPosition() { + return teleportPosition; + } + + /** + * @return The flags that determine which fields of the position are relative. + */ + @MagicConstant(flagsFromClass = RelativeFlags.class) + public int getRelativeFlags() { + return relativeFlags; + } +} diff --git a/src/main/java/net/minestom/server/event/player/PlayerAnvilInputEvent.java b/src/main/java/net/minestom/server/event/player/PlayerAnvilInputEvent.java index 5307d3d5321..9f6b2c22725 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerAnvilInputEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerAnvilInputEvent.java @@ -1,7 +1,9 @@ package net.minestom.server.event.player; import net.minestom.server.entity.Player; +import net.minestom.server.event.trait.InventoryEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; +import net.minestom.server.inventory.Inventory; import net.minestom.server.network.packet.client.play.ClientNameItemPacket; import org.jetbrains.annotations.NotNull; @@ -10,13 +12,15 @@ * * @see ClientNameItemPacket */ -public class PlayerAnvilInputEvent implements PlayerInstanceEvent { +public class PlayerAnvilInputEvent implements PlayerInstanceEvent, InventoryEvent { private final Player player; + private final Inventory inventory; private final String input; - public PlayerAnvilInputEvent(@NotNull Player player, @NotNull String input) { + public PlayerAnvilInputEvent(@NotNull Player player, @NotNull Inventory inventory, @NotNull String input) { this.player = player; + this.inventory = inventory; this.input = input; } @@ -28,4 +32,10 @@ public PlayerAnvilInputEvent(@NotNull Player player, @NotNull String input) { public @NotNull String getInput() { return input; } + + @Override + public @NotNull Inventory getInventory() { + return inventory; + } + } diff --git a/src/main/java/net/minestom/server/fluid/Fluid.java b/src/main/java/net/minestom/server/fluid/Fluid.java new file mode 100644 index 00000000000..c9e6bedf370 --- /dev/null +++ b/src/main/java/net/minestom/server/fluid/Fluid.java @@ -0,0 +1,37 @@ +package net.minestom.server.fluid; + +import net.minestom.server.registry.Registry; +import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +public sealed interface Fluid extends StaticProtocolObject, Fluids permits FluidImpl { + /** + * Returns the entity registry. + * + * @return the entity registry or null if it was created with a builder + */ + @Contract(pure = true) + @Nullable + Registry.FluidEntry registry(); + + @Override + @NotNull + NamespaceID namespace(); + + static @NotNull Collection<@NotNull Fluid> values() { + return FluidImpl.values(); + } + + static @Nullable Fluid fromNamespaceId(@NotNull String namespaceID) { + return FluidImpl.getSafe(namespaceID); + } + + static @Nullable Fluid fromNamespaceId(@NotNull NamespaceID namespaceID) { + return fromNamespaceId(namespaceID.asString()); + } +} diff --git a/src/main/java/net/minestom/server/fluid/FluidImpl.java b/src/main/java/net/minestom/server/fluid/FluidImpl.java new file mode 100644 index 00000000000..330108fefc3 --- /dev/null +++ b/src/main/java/net/minestom/server/fluid/FluidImpl.java @@ -0,0 +1,34 @@ +package net.minestom.server.fluid; + +import net.minestom.server.registry.Registry; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.concurrent.atomic.AtomicInteger; + +public record FluidImpl(Registry.FluidEntry registry, NamespaceID namespace, int id) implements Fluid { + + private static final AtomicInteger INDEX = new AtomicInteger(); + private static final Registry.Container CONTAINER = Registry.createStaticContainer(Registry.Resource.FLUIDS, FluidImpl::createImpl); + + private static FluidImpl createImpl(String namespace, Registry.Properties properties) { + return new FluidImpl(Registry.fluidEntry(namespace, properties)); + } + + private FluidImpl(Registry.FluidEntry registry) { + this(registry, registry.namespace(), INDEX.getAndIncrement()); + } + + static Collection values() { + return CONTAINER.values(); + } + + public static Fluid get(@NotNull String namespace) { + return CONTAINER.get(namespace); + } + + static Fluid getSafe(@NotNull String namespace) { + return CONTAINER.getSafe(namespace); + } +} diff --git a/src/main/java/net/minestom/server/gamedata/tags/Tag.java b/src/main/java/net/minestom/server/gamedata/tags/Tag.java index 663f9a1299d..32c73a947db 100644 --- a/src/main/java/net/minestom/server/gamedata/tags/Tag.java +++ b/src/main/java/net/minestom/server/gamedata/tags/Tag.java @@ -4,10 +4,10 @@ import net.kyori.adventure.key.Keyed; import net.minestom.server.MinecraftServer; import net.minestom.server.entity.EntityType; +import net.minestom.server.fluid.Fluid; import net.minestom.server.instance.block.Block; import net.minestom.server.item.Material; import net.minestom.server.registry.DynamicRegistry; -import net.minestom.server.registry.FluidRegistries; import net.minestom.server.registry.ProtocolObject; import net.minestom.server.registry.Registry; import net.minestom.server.utils.NamespaceID; @@ -93,11 +93,11 @@ public enum BasicType { ITEMS("minecraft:item", Registry.Resource.ITEM_TAGS, name -> Objects.requireNonNull(Material.fromNamespaceId(name)).id()), FLUIDS("minecraft:fluid", Registry.Resource.FLUID_TAGS, - name -> FluidRegistries.getFluid(name).ordinal()), + name -> Objects.requireNonNull(Fluid.fromNamespaceId(name)).id()), ENTITY_TYPES("minecraft:entity_type", Registry.Resource.ENTITY_TYPE_TAGS, name -> Objects.requireNonNull(EntityType.fromNamespaceId(name)).id()), - GAME_EVENTS("minecraft:game_event", Registry.Resource.GAMEPLAY_TAGS, - name -> FluidRegistries.getFluid(name).ordinal()), + /*GAME_EVENTS("minecraft:game_event", Registry.Resource.GAMEPLAY_TAGS, + name -> Objects.requireNonNull(Fluid.fromNamespaceId(name)).id());*/ SOUND_EVENTS("minecraft:sound_event", null, null), // Seems not to be included in server data POTION_EFFECTS("minecraft:sound_event", null, null), // Seems not to be included in server data diff --git a/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java b/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java index adccffd15ad..47730cbd0c9 100644 --- a/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java +++ b/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java @@ -468,7 +468,7 @@ private void saveSectionData(@NotNull Chunk chunk, @NotNull CompoundBinaryTag.Bu blockStates.put("palette", ListBinaryTag.listBinaryTag(BinaryTagTypes.COMPOUND, blockPaletteEntries)); if (blockPaletteEntries.size() > 1) { // If there is only one entry we do not need to write the packed indices - var bitsPerEntry = (int) Math.max(1, Math.ceil(Math.log(blockPaletteEntries.size()) / Math.log(2))); + var bitsPerEntry = (int) Math.max(4, Math.ceil(Math.log(blockPaletteEntries.size()) / Math.log(2))); blockStates.putLongArray("data", ArrayUtils.pack(blockIndices, bitsPerEntry)); } sectionData.put("block_states", blockStates.build()); diff --git a/src/main/java/net/minestom/server/instance/block/Block.java b/src/main/java/net/minestom/server/instance/block/Block.java index 492dab1cc7a..5fe94a8231d 100644 --- a/src/main/java/net/minestom/server/instance/block/Block.java +++ b/src/main/java/net/minestom/server/instance/block/Block.java @@ -92,6 +92,15 @@ public sealed interface Block extends StaticProtocolObject, TagReadable, Blocks @Contract(pure = true) @Nullable CompoundBinaryTag nbt(); + /** + * Returns an unmodifiable view of the block nbt or an empty compound. + * + * @return the block nbt or an empty compound if not present + */ + default @NotNull CompoundBinaryTag nbtOrEmpty() { + return Objects.requireNonNullElse(nbt(), CompoundBinaryTag.empty()); + } + @Contract(pure = true) default boolean hasNbt() { return nbt() != null; diff --git a/src/main/java/net/minestom/server/instance/block/BlockHandler.java b/src/main/java/net/minestom/server/instance/block/BlockHandler.java index b539a4d1274..b5cf80e74d8 100644 --- a/src/main/java/net/minestom/server/instance/block/BlockHandler.java +++ b/src/main/java/net/minestom/server/instance/block/BlockHandler.java @@ -199,15 +199,17 @@ public PlayerDestroy(Block block, Instance instance, Point blockPosition, Player final class Interaction { private final Block block; private final Instance instance; + private final BlockFace blockFace; private final Point blockPosition; private final Point cursorPosition; private final Player player; private final Player.Hand hand; @ApiStatus.Internal - public Interaction(Block block, Instance instance, Point blockPosition, Point cursorPosition, Player player, Player.Hand hand) { + public Interaction(Block block, Instance instance, BlockFace blockFace, Point blockPosition, Point cursorPosition, Player player, Player.Hand hand) { this.block = block; this.instance = instance; + this.blockFace = blockFace; this.blockPosition = blockPosition; this.cursorPosition = cursorPosition; this.player = player; @@ -222,6 +224,10 @@ public Interaction(Block block, Instance instance, Point blockPosition, Point cu return instance; } + public @NotNull BlockFace getBlockFace() { + return blockFace; + } + public @NotNull Point getBlockPosition() { return blockPosition; } diff --git a/src/main/java/net/minestom/server/instance/block/BlockImpl.java b/src/main/java/net/minestom/server/instance/block/BlockImpl.java index 672dd6c7adc..f2e5568bbfa 100644 --- a/src/main/java/net/minestom/server/instance/block/BlockImpl.java +++ b/src/main/java/net/minestom/server/instance/block/BlockImpl.java @@ -1,6 +1,6 @@ package net.minestom.server.instance.block; -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; import net.kyori.adventure.nbt.CompoundBinaryTag; @@ -20,7 +20,7 @@ import java.util.Objects; record BlockImpl(@NotNull Registry.BlockEntry registry, - int propertiesArray, + long propertiesArray, @Nullable CompoundBinaryTag nbt, @Nullable BlockHandler handler) implements Block { /** @@ -28,74 +28,18 @@ record BlockImpl(@NotNull Registry.BlockEntry registry, *

* Block states are all stored within a single number. */ - private static final int BITS_PER_INDEX = 4; + private static final int BITS_PER_INDEX = 5; - private static final int MAX_STATES = Integer.SIZE / BITS_PER_INDEX; + private static final int MAX_STATES = Long.SIZE / BITS_PER_INDEX; + private static final int MAX_VALUES = 1 << BITS_PER_INDEX; // Block state -> block object private static final ObjectArray BLOCK_STATE_MAP = ObjectArray.singleThread(); // Block id -> valid property keys (order is important for lookup) private static final ObjectArray PROPERTIES_TYPE = ObjectArray.singleThread(); - // Block id -> Map - private static final ObjectArray> POSSIBLE_STATES = ObjectArray.singleThread(); - private static final Registry.Container CONTAINER = Registry.createStaticContainer(Registry.Resource.BLOCKS, - (namespace, properties) -> { - final int blockId = properties.getInt("id"); - final Registry.Properties stateObject = properties.section("states"); - - // Retrieve properties - PropertyType[] propertyTypes; - { - Registry.Properties stateProperties = properties.section("properties"); - if (stateProperties != null) { - final int stateCount = stateProperties.size(); - if (stateCount > MAX_STATES) { - throw new IllegalStateException("Too many properties for block " + namespace); - } - propertyTypes = new PropertyType[stateCount]; - int i = 0; - for (var entry : stateProperties) { - final var k = entry.getKey(); - final var v = (List) entry.getValue(); - propertyTypes[i++] = new PropertyType(k, v); - } - } else { - propertyTypes = new PropertyType[0]; - } - } - PROPERTIES_TYPE.set(blockId, propertyTypes); - - // Retrieve block states - { - final int propertiesCount = stateObject.size(); - int[] propertiesKeys = new int[propertiesCount]; - BlockImpl[] blocksValues = new BlockImpl[propertiesCount]; - int propertiesOffset = 0; - for (var stateEntry : stateObject) { - final String query = stateEntry.getKey(); - final var stateOverride = (Map) stateEntry.getValue(); - final var propertyMap = BlockUtils.parseProperties(query); - assert propertyTypes.length == propertyMap.size(); - int propertiesValue = 0; - for (Map.Entry entry : propertyMap.entrySet()) { - final byte keyIndex = findKeyIndex(propertyTypes, entry.getKey(), null); - final byte valueIndex = findValueIndex(propertyTypes[keyIndex], entry.getValue(), null); - propertiesValue = updateIndex(propertiesValue, keyIndex, valueIndex); - } - - var mainProperties = Registry.Properties.fromMap(new MergedMap<>(stateOverride, properties.asMap())); - final BlockImpl block = new BlockImpl(Registry.block(namespace, mainProperties), - propertiesValue, null, null); - BLOCK_STATE_MAP.set(block.stateId(), block); - propertiesKeys[propertiesOffset] = propertiesValue; - blocksValues[propertiesOffset++] = block; - } - POSSIBLE_STATES.set(blockId, new Int2ObjectArrayMap<>(propertiesKeys, blocksValues, propertiesOffset)); - } - // Register default state - final int defaultState = properties.getInt("defaultStateId"); - return getState(defaultState); - }); + // Block id -> Map + private static final ObjectArray> POSSIBLE_STATES = ObjectArray.singleThread(); + private static final Registry.Container CONTAINER = Registry.createStaticContainer(Registry.Resource.BLOCKS, BlockImpl::createImpl); static { PROPERTIES_TYPE.trim(); @@ -129,7 +73,7 @@ static Collection values() { assert propertyTypes != null; final byte keyIndex = findKeyIndex(propertyTypes, property, this); final byte valueIndex = findValueIndex(propertyTypes[keyIndex], value, this); - final int updatedProperties = updateIndex(propertiesArray, keyIndex, valueIndex); + final long updatedProperties = updateIndex(propertiesArray, keyIndex, valueIndex); return compute(updatedProperties); } @@ -138,7 +82,7 @@ static Collection values() { if (properties.isEmpty()) return this; final PropertyType[] propertyTypes = PROPERTIES_TYPE.get(id()); assert propertyTypes != null; - int updatedProperties = this.propertiesArray; + long updatedProperties = this.propertiesArray; for (Map.Entry entry : properties.entrySet()) { final byte keyIndex = findKeyIndex(propertyTypes, entry.getKey(), this); final byte valueIndex = findValueIndex(propertyTypes[keyIndex], entry.getValue(), this); @@ -178,8 +122,8 @@ static Collection values() { for (int i = 0; i < length; i++) { PropertyType property = propertyTypes[i]; keys[i] = property.key(); - final int index = extractIndex(propertiesArray, i); - values[i] = property.values().get(index); + final long index = extractIndex(propertiesArray, i); + values[i] = property.values().get((int) index); } return Object2ObjectMaps.unmodifiable(new Object2ObjectArrayMap<>(keys, values, length)); } @@ -199,7 +143,7 @@ static Collection values() { return tag.read(Objects.requireNonNullElse(nbt, CompoundBinaryTag.empty())); } - private Int2ObjectArrayMap possibleProperties() { + private Long2ObjectArrayMap possibleProperties() { return POSSIBLE_STATES.get(id()); } @@ -220,7 +164,7 @@ public int hashCode() { return Objects.hash(stateId(), nbt, handler); } - private Block compute(int updatedProperties) { + private Block compute(long updatedProperties) { if (updatedProperties == this.propertiesArray) return this; final BlockImpl block = possibleProperties().get(updatedProperties); assert block != null; @@ -230,6 +174,65 @@ private Block compute(int updatedProperties) { return new BlockImpl(block.registry(), block.propertiesArray, nbt, handler); } + private static Block createImpl(String namespace, Registry.Properties properties) { + final int blockId = properties.getInt("id"); + final Registry.Properties stateObject = properties.section("states"); + + // Retrieve properties + PropertyType[] propertyTypes; + { + Registry.Properties stateProperties = properties.section("properties"); + if (stateProperties != null) { + final int stateCount = stateProperties.size(); + if (stateCount > MAX_STATES) { + throw new IllegalStateException("Too many properties for block " + namespace); + } + propertyTypes = new PropertyType[stateCount]; + int i = 0; + for (var entry : stateProperties) { + final var k = entry.getKey(); + final var v = (List) entry.getValue(); + assert v.size() < MAX_VALUES; + propertyTypes[i++] = new PropertyType(k, v); + } + } else { + propertyTypes = new PropertyType[0]; + } + } + PROPERTIES_TYPE.set(blockId, propertyTypes); + + // Retrieve block states + { + final int propertiesCount = stateObject.size(); + long[] propertiesKeys = new long[propertiesCount]; + BlockImpl[] blocksValues = new BlockImpl[propertiesCount]; + int propertiesOffset = 0; + for (var stateEntry : stateObject) { + final String query = stateEntry.getKey(); + final var stateOverride = (Map) stateEntry.getValue(); + final var propertyMap = BlockUtils.parseProperties(query); + assert propertyTypes.length == propertyMap.size(); + long propertiesValue = 0; + for (Map.Entry entry : propertyMap.entrySet()) { + final byte keyIndex = findKeyIndex(propertyTypes, entry.getKey(), null); + final byte valueIndex = findValueIndex(propertyTypes[keyIndex], entry.getValue(), null); + propertiesValue = updateIndex(propertiesValue, keyIndex, valueIndex); + } + + var mainProperties = Registry.Properties.fromMap(new MergedMap<>(stateOverride, properties.asMap())); + final BlockImpl block = new BlockImpl(Registry.block(namespace, mainProperties), + propertiesValue, null, null); + BLOCK_STATE_MAP.set(block.stateId(), block); + propertiesKeys[propertiesOffset] = propertiesValue; + blocksValues[propertiesOffset++] = block; + } + POSSIBLE_STATES.set(blockId, new Long2ObjectArrayMap<>(propertiesKeys, blocksValues, propertiesOffset)); + } + // Register default state + final int defaultState = properties.getInt("defaultStateId"); + return getState(defaultState); + } + private static byte findKeyIndex(PropertyType[] properties, String key, BlockImpl block) { for (byte i = 0; i < properties.length; i++) { if (properties[i].key().equals(key)) return i; @@ -255,15 +258,15 @@ private static byte findValueIndex(PropertyType propertyType, String value, Bloc private record PropertyType(String key, List values) { } - static int updateIndex(int value, int index, byte newValue) { + static long updateIndex(long value, int index, byte newValue) { final int position = index * BITS_PER_INDEX; final int mask = (1 << BITS_PER_INDEX) - 1; - value &= ~(mask << position); // Clear the bits at the specified position - value |= (newValue & mask) << position; // Set the new bits + value &= ~((long) mask << position); // Clear the bits at the specified position + value |= (long) (newValue & mask) << position; // Set the new bits return value; } - static int extractIndex(int value, int index) { + static long extractIndex(long value, int index) { final int position = index * BITS_PER_INDEX; final int mask = (1 << BITS_PER_INDEX) - 1; return ((value >> position) & mask); diff --git a/src/main/java/net/minestom/server/item/component/Food.java b/src/main/java/net/minestom/server/item/component/Food.java index bc978adcfee..e737f628979 100644 --- a/src/main/java/net/minestom/server/item/component/Food.java +++ b/src/main/java/net/minestom/server/item/component/Food.java @@ -74,7 +74,8 @@ public record EffectChance(@NotNull CustomPotionEffect effect, float probability public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, EffectChance value) { - + CustomPotionEffect.NETWORK_TYPE.write(buffer, value.effect); + buffer.write(NetworkBuffer.FLOAT, value.probability); } @Override diff --git a/src/main/java/net/minestom/server/listener/AnvilListener.java b/src/main/java/net/minestom/server/listener/AnvilListener.java index de04d8b2247..be0be4474f3 100644 --- a/src/main/java/net/minestom/server/listener/AnvilListener.java +++ b/src/main/java/net/minestom/server/listener/AnvilListener.java @@ -16,7 +16,7 @@ public static void nameItemListener(@NotNull ClientNameItemPacket packet, @NotNu if (openInventory.getInventoryType() != InventoryType.ANVIL) return; - EventDispatcher.call(new PlayerAnvilInputEvent(player, packet.itemName())); + EventDispatcher.call(new PlayerAnvilInputEvent(player, openInventory, packet.itemName())); } private AnvilListener() { diff --git a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java index e80f545bdff..561f562fe63 100644 --- a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java +++ b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java @@ -65,7 +65,7 @@ public static void listener(ClientPlayerBlockPlacementPacket packet, Player play if (!playerBlockInteractEvent.isCancelled()) { final var handler = interactedBlock.handler(); if (handler != null) { - blockUse |= !handler.onInteract(new BlockHandler.Interaction(interactedBlock, instance, blockPosition, cursorPosition, player, hand)); + blockUse |= !handler.onInteract(new BlockHandler.Interaction(interactedBlock, instance, blockFace, blockPosition, cursorPosition, player, hand)); } } if (blockUse) { diff --git a/src/main/java/net/minestom/server/listener/WindowListener.java b/src/main/java/net/minestom/server/listener/WindowListener.java index dcf3ef91b6c..dad46cfb94a 100644 --- a/src/main/java/net/minestom/server/listener/WindowListener.java +++ b/src/main/java/net/minestom/server/listener/WindowListener.java @@ -51,6 +51,7 @@ public static void clickWindowListener(ClientClickWindowPacket packet, Player pl } else if (clickType == ClientClickWindowPacket.ClickType.QUICK_MOVE) { successful = inventory.shiftClick(player, slot, button); // Microtus } else if (clickType == ClientClickWindowPacket.ClickType.SWAP) { + if (slot < 0 || button < 0) return; successful = inventory.changeHeld(player, slot, button); } else if (clickType == ClientClickWindowPacket.ClickType.CLONE) { successful = player.getGameMode() == GameMode.CREATIVE; diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java index 7e7822ff8bb..8a790a79a22 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java @@ -269,7 +269,7 @@ public void write(@NotNull NetworkBuffer buffer, byte[] value) { public byte[] read(@NotNull NetworkBuffer buffer) { final int limit = buffer.nioBuffer.limit(); final int length = limit - buffer.readIndex(); - assert length > 0 : "Invalid remaining: " + length; + assert length >= 0 : "Invalid remaining: " + length; final byte[] bytes = new byte[length]; buffer.nioBuffer.get(buffer.readIndex(), bytes); buffer.readIndex += length; diff --git a/src/main/java/net/minestom/server/network/player/PlayerConnection.java b/src/main/java/net/minestom/server/network/player/PlayerConnection.java index 408e47ee89b..06cdd5da91b 100644 --- a/src/main/java/net/minestom/server/network/player/PlayerConnection.java +++ b/src/main/java/net/minestom/server/network/player/PlayerConnection.java @@ -4,6 +4,8 @@ import net.minestom.server.crypto.PlayerPublicKey; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; +import net.minestom.server.event.EventDispatcher; +import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.common.CookieRequestPacket; @@ -119,8 +121,12 @@ public void disconnect() { this.online = false; MinecraftServer.getConnectionManager().removePlayer(this); final Player player = getPlayer(); - if (player != null && !player.isRemoved()) { - player.scheduleNextTick(Entity::remove); + if (player != null) { + if (connectionState == ConnectionState.PLAY && !player.isRemoved()) + player.scheduleNextTick(Entity::remove); + else { + EventDispatcher.call(new PlayerDisconnectEvent(player)); + } } } diff --git a/src/main/java/net/minestom/server/registry/Registry.java b/src/main/java/net/minestom/server/registry/Registry.java index 8093e7a87ee..249ff3d8a7a 100644 --- a/src/main/java/net/minestom/server/registry/Registry.java +++ b/src/main/java/net/minestom/server/registry/Registry.java @@ -130,6 +130,21 @@ public static JukeboxSongEntry jukeboxSong(String namespace, @NotNull Properties return new JukeboxSongEntry(namespace, main, null); } + @ApiStatus.Internal + public static FluidEntry fluidEntry(String namespace, @NotNull Properties main) { + return new FluidEntry(namespace, main, null); + } + + @ApiStatus.Internal + public static VillagerProfession villagerProfession(String namespace, @NotNull Properties main) { + return new VillagerProfession(namespace, main, null); + } + + @ApiStatus.Internal + public static VillagerType villagerType(String namespace, @NotNull Properties main) { + return new VillagerType(namespace, main, null); + } + @ApiStatus.Internal public static Map> load(Resource resource) { Map> map = new HashMap<>(); @@ -236,7 +251,11 @@ public enum Resource { CHAT_TYPES("chat_types.json"), ENCHANTMENTS("enchantments.snbt"), PAINTING_VARIANTS("painting_variants.json"), - JUKEBOX_SONGS("jukebox_songs.json"); + JUKEBOX_SONGS("jukebox_songs.json"), + VILLAGER_PROFESSION("villager_professions.json"), + VILLAGER_TYPES("villager_types.json"), + FLUIDS("fluids.json"), + ; private final String name; @@ -249,6 +268,20 @@ public enum Resource { } } + public record FluidEntry( + @NotNull NamespaceID namespace, + @NotNull NamespaceID bucketId, + @Nullable Properties custom + ) implements Entry { + + public FluidEntry(String namespace, Properties main, Properties custom) { + this(NamespaceID.from(namespace), + NamespaceID.from(main.getString("bucketId")), + custom + ); + } + } + public static final class BlockEntry implements Entry { private final NamespaceID namespace; private final int id; @@ -779,6 +812,25 @@ public TrimPatternEntry(@NotNull String namespace, @NotNull Properties main, Pro } } + public record VillagerProfession(NamespaceID namespace, int id, SoundEvent soundEvent, Properties custom) implements Entry { + public VillagerProfession(String namespace, + Properties main, + Properties custom) { + this(NamespaceID.from(namespace), + main.getInt("id"), + SoundEvent.fromNamespaceId(main.getString("workSound")), + custom); + } + } + + public record VillagerType(NamespaceID namespace, int id, Properties custom) implements Entry { + public VillagerType(String namespace, Properties main, Properties custom) { + this(NamespaceID.from(namespace), + main.getInt("id"), + custom); + } + } + public record PotionEffectEntry(NamespaceID namespace, int id, String translationKey, int color, diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 597eb81ed39..1983982642e 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -314,7 +314,17 @@ public int hashCode() { public static @NotNull Tag View(@NotNull Class type) { return View(TagRecord.serializer(type)); } - + + /** + * Creates a transient tag with the specified key. This tag does not get serialized + * to NBT (Named Binary Tag) format and is not sent to the client. Unlike other tags, + * which are serialized, transient tags are used for temporary data + * that only needs to exist on the server side. + * + * @param The type of the tag's value. + * @param key The key. + * @return A transient tag with the key. + */ public static @NotNull Tag Transient(@NotNull String key) { //noinspection unchecked return (Tag) tag(key, Serializers.EMPTY); diff --git a/src/main/java/net/minestom/server/thread/TickSchedulerThread.java b/src/main/java/net/minestom/server/thread/TickSchedulerThread.java index e82a79bf847..19e66b853e1 100644 --- a/src/main/java/net/minestom/server/thread/TickSchedulerThread.java +++ b/src/main/java/net/minestom/server/thread/TickSchedulerThread.java @@ -27,7 +27,7 @@ public void run() { final long tickStart = System.nanoTime(); try { serverProcess.ticker().tick(tickStart); - } catch (Exception e) { + } catch (Throwable e) { serverProcess.exception().handleException(e); } diff --git a/src/test/java/net/minestom/server/InsideTest.java b/src/test/java/net/minestom/server/InsideTest.java index 9adbea2e1e7..ee7564c2a56 100644 --- a/src/test/java/net/minestom/server/InsideTest.java +++ b/src/test/java/net/minestom/server/InsideTest.java @@ -4,9 +4,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue; -public class InsideTest { +class InsideTest { @Test - public void inside() { + void inside() { assertTrue(ServerFlag.INSIDE_TEST); } } diff --git a/src/test/java/net/minestom/server/collision/EntityBlockPhysicsIntegrationTest.java b/src/test/java/net/minestom/server/collision/EntityBlockPhysicsIntegrationTest.java index e544834d331..13f9f76be86 100644 --- a/src/test/java/net/minestom/server/collision/EntityBlockPhysicsIntegrationTest.java +++ b/src/test/java/net/minestom/server/collision/EntityBlockPhysicsIntegrationTest.java @@ -49,7 +49,7 @@ private static void assertPossiblePoints(List expected, Point actual) { } @Test - public void entityPhysicsCheckCollision(Env env) { + void entityPhysicsCheckCollision(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 43, 1, Block.STONE); @@ -77,7 +77,7 @@ public void entityPhysicsCheckShortDiagonal(Env env) { } @Test - public void entityPhysicsCheckSlab(Env env) { + void entityPhysicsCheckSlab(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) @@ -95,7 +95,7 @@ public void entityPhysicsCheckSlab(Env env) { } @Test - public void entityPhysicsCheckShallowAngle(Env env) { + void entityPhysicsCheckShallowAngle(Env env) { var instance = env.createFlatInstance(); instance.setBlock(13, 99, 16, Block.STONE); @@ -110,7 +110,7 @@ public void entityPhysicsCheckShallowAngle(Env env) { } @Test - public void entityPhysicsCheckFallFence(Env env) { + void entityPhysicsCheckFallFence(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 0, Block.OAK_FENCE); @@ -123,7 +123,7 @@ public void entityPhysicsCheckFallFence(Env env) { } @Test - public void entityPhysicsCheckFallHitCarpet(Env env) { + void entityPhysicsCheckFallHitCarpet(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) @@ -142,7 +142,7 @@ public void entityPhysicsCheckFallHitCarpet(Env env) { } @Test - public void entityPhysicsCheckFallHitFence(Env env) { + void entityPhysicsCheckFallHitFence(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 0, Block.OAK_FENCE); instance.setBlock(0, 43, 0, Block.BROWN_CARPET); @@ -156,7 +156,7 @@ public void entityPhysicsCheckFallHitFence(Env env) { } @Test - public void entityPhysicsCheckHorizontalFence(Env env) { + void entityPhysicsCheckHorizontalFence(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 42, 0, Block.OAK_FENCE); @@ -169,7 +169,7 @@ public void entityPhysicsCheckHorizontalFence(Env env) { } @Test - public void entityPhysicsCheckMultipleBlocksPassFirst(Env env) { + void entityPhysicsCheckMultipleBlocksPassFirst(Env env) { var instance = env.createFlatInstance(); instance.setBlock(4, 40, -1, Block.SANDSTONE_STAIRS); instance.setBlock(16, 40, 0, Block.STONE); @@ -183,7 +183,7 @@ public void entityPhysicsCheckMultipleBlocksPassFirst(Env env) { } @Test - public void entityPhysicsCheckMultipleBlocksHitFirst(Env env) { + void entityPhysicsCheckMultipleBlocksHitFirst(Env env) { var instance = env.createFlatInstance(); instance.setBlock(4, 40, 0, Block.GRASS_BLOCK); instance.setBlock(16, 40, 0, Block.STONE); @@ -200,7 +200,7 @@ public void entityPhysicsCheckMultipleBlocksHitFirst(Env env) { } @Test - public void entityPhysicsCheckHorizontalCarpetedFence(Env env) { + void entityPhysicsCheckHorizontalCarpetedFence(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 42, 0, Block.OAK_FENCE); instance.setBlock(1, 43, 0, Block.BROWN_CARPET); @@ -214,7 +214,7 @@ public void entityPhysicsCheckHorizontalCarpetedFence(Env env) { } @Test - public void entityPhysicsCheckDiagonalCarpetedFenceX(Env env) { + void entityPhysicsCheckDiagonalCarpetedFenceX(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) @@ -233,7 +233,7 @@ public void entityPhysicsCheckDiagonalCarpetedFenceX(Env env) { } @Test - public void entityPhysicsCheckDiagonalCarpetedFenceZ(Env env) { + void entityPhysicsCheckDiagonalCarpetedFenceZ(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) @@ -252,7 +252,7 @@ public void entityPhysicsCheckDiagonalCarpetedFenceZ(Env env) { } @Test - public void entityPhysicsCheckDiagonalCarpetedFenceXZ(Env env) { + void entityPhysicsCheckDiagonalCarpetedFenceXZ(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) @@ -283,7 +283,7 @@ public void entityPhysicsCheckDiagonalCarpetedFenceXZ(Env env) { } @Test - public void entityPhysicsCheckFallHitFenceLongMove(Env env) { + void entityPhysicsCheckFallHitFenceLongMove(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 0, Block.OAK_FENCE); instance.setBlock(0, 43, 0, Block.BROWN_CARPET); @@ -297,7 +297,7 @@ public void entityPhysicsCheckFallHitFenceLongMove(Env env) { } @Test - public void entityPhysicsCheckFenceAboveHead(Env env) { + void entityPhysicsCheckFenceAboveHead(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 45, 0, Block.OAK_FENCE); @@ -311,7 +311,7 @@ public void entityPhysicsCheckFenceAboveHead(Env env) { } @Test - public void entityPhysicsCheckDiagonal(Env env) { + void entityPhysicsCheckDiagonal(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 43, 1, Block.STONE); instance.setBlock(1, 43, 2, Block.STONE); @@ -327,7 +327,7 @@ public void entityPhysicsCheckDiagonal(Env env) { } @Test - public void entityPhysicsCheckDirectSlide(Env env) { + void entityPhysicsCheckDirectSlide(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 43, 1, Block.STONE); instance.setBlock(1, 43, 2, Block.STONE); @@ -341,7 +341,7 @@ public void entityPhysicsCheckDirectSlide(Env env) { } @Test - public void entityPhysicsCheckCorner(Env env) { + void entityPhysicsCheckCorner(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) for (int j = -2; j <= 2; ++j) @@ -360,7 +360,7 @@ public void entityPhysicsCheckCorner(Env env) { } @Test - public void entityPhysicsCheckEnclosedHit(Env env) { + void entityPhysicsCheckEnclosedHit(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) for (int j = -2; j <= 2; ++j) @@ -382,7 +382,7 @@ public void entityPhysicsCheckEnclosedHit(Env env) { } @Test - public void entityPhysicsCheckEnclosedHitSubBlock(Env env) { + void entityPhysicsCheckEnclosedHitSubBlock(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) for (int j = -2; j <= 2; ++j) @@ -404,7 +404,7 @@ public void entityPhysicsCheckEnclosedHitSubBlock(Env env) { } @Test - public void entityPhysicsCheckEnclosedMiss(Env env) { + void entityPhysicsCheckEnclosedMiss(Env env) { var instance = env.createFlatInstance(); instance.setBlock(11, 43, 11, Block.STONE); @@ -421,7 +421,7 @@ public void entityPhysicsCheckEnclosedMiss(Env env) { } @Test - public void entityPhysicsCheckEntityHit(Env env) { + void entityPhysicsCheckEntityHit() { Point z1 = new Pos(0, 0, 0); Point z2 = new Pos(15, 0, 0); Point z3 = new Pos(11, 0, 0); @@ -439,7 +439,7 @@ public void entityPhysicsCheckEntityHit(Env env) { } @Test - public void entityPhysicsCheckEdgeClip(Env env) { + void entityPhysicsCheckEdgeClip(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 43, 1, Block.STONE); @@ -452,7 +452,7 @@ public void entityPhysicsCheckEdgeClip(Env env) { } @Test - public void entityPhysicsCheckEdgeClipSmall(Env env) { + void entityPhysicsCheckEdgeClipSmall(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 42, 1, Block.STONE); @@ -466,7 +466,7 @@ public void entityPhysicsCheckEdgeClipSmall(Env env) { } @Test - public void entityPhysicsCheckDoorSubBlockNorth(Env env) { + void entityPhysicsCheckDoorSubBlockNorth(Env env) { var instance = env.createFlatInstance(); Block b = Block.ACACIA_TRAPDOOR.withProperties(Map.of("facing", "north", "open", "true")); @@ -481,7 +481,7 @@ public void entityPhysicsCheckDoorSubBlockNorth(Env env) { } @Test - public void entityPhysicsCheckDoorSubBlockSouth(Env env) { + void entityPhysicsCheckDoorSubBlockSouth(Env env) { var instance = env.createFlatInstance(); Block b = Block.ACACIA_TRAPDOOR.withProperties(Map.of("facing", "south", "open", "true")); @@ -496,7 +496,7 @@ public void entityPhysicsCheckDoorSubBlockSouth(Env env) { } @Test - public void entityPhysicsCheckDoorSubBlockWest(Env env) { + void entityPhysicsCheckDoorSubBlockWest(Env env) { var instance = env.createFlatInstance(); Block b = Block.ACACIA_TRAPDOOR.withProperties(Map.of("facing", "west", "open", "true")); @@ -511,7 +511,7 @@ public void entityPhysicsCheckDoorSubBlockWest(Env env) { } @Test - public void entityPhysicsCheckDoorSubBlockEast(Env env) { + void entityPhysicsCheckDoorSubBlockEast(Env env) { var instance = env.createFlatInstance(); Block b = Block.ACACIA_TRAPDOOR.withProperties(Map.of("facing", "east", "open", "true")); @@ -526,7 +526,7 @@ public void entityPhysicsCheckDoorSubBlockEast(Env env) { } @Test - public void entityPhysicsCheckDoorSubBlockUp(Env env) { + void entityPhysicsCheckDoorSubBlockUp(Env env) { var instance = env.createFlatInstance(); Block b = Block.ACACIA_TRAPDOOR.withProperties(Map.of("half", "top")); @@ -541,7 +541,7 @@ public void entityPhysicsCheckDoorSubBlockUp(Env env) { } @Test - public void entityPhysicsCheckDoorSubBlockDown(Env env) { + void entityPhysicsCheckDoorSubBlockDown(Env env) { var instance = env.createFlatInstance(); Block b = Block.ACACIA_TRAPDOOR; @@ -556,7 +556,7 @@ public void entityPhysicsCheckDoorSubBlockDown(Env env) { } @Test - public void entityPhysicsCheckOnGround(Env env) { + void entityPhysicsCheckOnGround(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 40, 0, Block.STONE); @@ -569,7 +569,7 @@ public void entityPhysicsCheckOnGround(Env env) { } @Test - public void entityPhysicsCheckStairTop(Env env) { + void entityPhysicsCheckStairTop(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 0, Block.ACACIA_STAIRS); @@ -582,7 +582,7 @@ public void entityPhysicsCheckStairTop(Env env) { } @Test - public void entityPhysicsCheckStairTopSmall(Env env) { + void entityPhysicsCheckStairTopSmall(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 0, Block.ACACIA_STAIRS); @@ -595,7 +595,7 @@ public void entityPhysicsCheckStairTopSmall(Env env) { } @Test - public void entityPhysicsCheckNotOnGround(Env env) { + void entityPhysicsCheckNotOnGround(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) @@ -611,7 +611,7 @@ public void entityPhysicsCheckNotOnGround(Env env) { } @Test - public void entityPhysicsCheckNotOnGroundHitUp(Env env) { + void entityPhysicsCheckNotOnGroundHitUp(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 60, 0, Block.STONE); @@ -624,7 +624,7 @@ public void entityPhysicsCheckNotOnGroundHitUp(Env env) { } @Test - public void entityPhysicsCheckSlide(Env env) { + void entityPhysicsCheckSlide(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 43, 1, Block.STONE); instance.setBlock(1, 43, 2, Block.STONE); @@ -639,7 +639,7 @@ public void entityPhysicsCheckSlide(Env env) { } @Test - public void entityPhysicsSmallMoveCollide(Env env) { + void entityPhysicsSmallMoveCollide(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 43, 0, Block.STONE); @@ -660,7 +660,7 @@ public void tmp(Env env) { // Checks C include all checks for crossing one intermediate block (3 block checks) @Test - public void entityPhysicsSmallMoveC0(Env env) { + void entityPhysicsSmallMoveC0(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 42, 0, Block.STONE); @@ -675,7 +675,7 @@ public void entityPhysicsSmallMoveC0(Env env) { } @Test - public void entityPhysicsSmallMoveC1(Env env) { + void entityPhysicsSmallMoveC1(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 1, Block.STONE); @@ -690,7 +690,7 @@ public void entityPhysicsSmallMoveC1(Env env) { } @Test - public void entityPhysicsSmallMoveC2(Env env) { + void entityPhysicsSmallMoveC2(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 42, 1, Block.STONE); @@ -705,7 +705,7 @@ public void entityPhysicsSmallMoveC2(Env env) { } @Test - public void entityPhysicsSmallMoveC3(Env env) { + void entityPhysicsSmallMoveC3(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 0, Block.STONE); @@ -720,7 +720,7 @@ public void entityPhysicsSmallMoveC3(Env env) { } @Test - public void entityPhysicsSmallMoveC4(Env env) { + void entityPhysicsSmallMoveC4(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 1, Block.STONE); @@ -735,7 +735,7 @@ public void entityPhysicsSmallMoveC4(Env env) { } @Test - public void entityPhysicsSmallMoveC5(Env env) { + void entityPhysicsSmallMoveC5(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 42, 0, Block.STONE); @@ -750,7 +750,7 @@ public void entityPhysicsSmallMoveC5(Env env) { } @Test - public void entityPhysicsSmallMoveC6(Env env) { + void entityPhysicsSmallMoveC6(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 0, Block.STONE); @@ -765,7 +765,7 @@ public void entityPhysicsSmallMoveC6(Env env) { } @Test - public void entityPhysicsSmallMoveC7(Env env) { + void entityPhysicsSmallMoveC7(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 42, 1, Block.STONE); @@ -781,7 +781,7 @@ public void entityPhysicsSmallMoveC7(Env env) { // Checks CE include checks for crossing two intermediate block (4 block checks) @Test - public void entityPhysicsSmallMoveC0E(Env env) { + void entityPhysicsSmallMoveC0E(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 43, 0, Block.STONE); @@ -796,7 +796,7 @@ public void entityPhysicsSmallMoveC0E(Env env) { } @Test - public void entityPhysicsSmallMoveC1E(Env env) { + void entityPhysicsSmallMoveC1E(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 43, 1, Block.STONE); @@ -811,7 +811,7 @@ public void entityPhysicsSmallMoveC1E(Env env) { } @Test - public void entityPhysicsSmallMoveC2E(Env env) { + void entityPhysicsSmallMoveC2E(Env env) { var instance = env.createFlatInstance(); instance.setBlock(1, 43, 1, Block.STONE); @@ -827,7 +827,7 @@ public void entityPhysicsSmallMoveC2E(Env env) { } @Test - public void entityPhysicsCheckNoCollision(Env env) { + void entityPhysicsCheckNoCollision(Env env) { var instance = env.createFlatInstance(); for (int i = -2; i <= 2; ++i) @@ -843,7 +843,7 @@ public void entityPhysicsCheckNoCollision(Env env) { } @Test - public void entityPhysicsCheckBlockMiss(Env env) { + void entityPhysicsCheckBlockMiss(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 43, 2, Block.STONE); instance.setBlock(2, 43, 0, Block.STONE); @@ -857,7 +857,7 @@ public void entityPhysicsCheckBlockMiss(Env env) { } @Test - public void entityPhysicsCheckBlockDirections(Env env) { + void entityPhysicsCheckBlockDirections(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 43, 1, Block.STONE); @@ -891,7 +891,7 @@ public void entityPhysicsCheckBlockDirections(Env env) { } @Test - public void entityPhysicsCheckLargeVelocityMiss(Env env) { + void entityPhysicsCheckLargeVelocityMiss(Env env) { var instance = env.createFlatInstance(); var entity = new Entity(EntityType.ZOMBIE); @@ -906,7 +906,7 @@ public void entityPhysicsCheckLargeVelocityMiss(Env env) { } @Test - public void entityPhysicsCheckLargeVelocityHit(Env env) { + void entityPhysicsCheckLargeVelocityHit(Env env) { var instance = env.createFlatInstance(); var entity = new Entity(EntityType.ZOMBIE); @@ -923,7 +923,7 @@ public void entityPhysicsCheckLargeVelocityHit(Env env) { } @Test - public void entityPhysicsCheckNoMove(Env env) { + void entityPhysicsCheckNoMove(Env env) { var instance = env.createFlatInstance(); var entity = new Entity(EntityType.ZOMBIE); @@ -935,7 +935,7 @@ public void entityPhysicsCheckNoMove(Env env) { } @Test - public void entityPhysicsRepeatedCollision(Env env) { + void entityPhysicsRepeatedCollision(Env env) { var instance = env.createFlatInstance(); PhysicsResult previousResult = null; @@ -967,7 +967,7 @@ public void entityPhysicsRepeatedCollision(Env env) { } @Test - public void entityPhysicsCheckNoMoveCache(Env env) { + void entityPhysicsCheckNoMoveCache(Env env) { var instance = env.createFlatInstance(); var entity = new Entity(EntityType.ZOMBIE); @@ -981,7 +981,7 @@ public void entityPhysicsCheckNoMoveCache(Env env) { } @Test - public void entityPhysicsCheckNoMoveLargeVelocityHit(Env env) { + void entityPhysicsCheckNoMoveLargeVelocityHit(Env env) { var instance = env.createFlatInstance(); var entity = new Entity(EntityType.ZOMBIE); @@ -1000,7 +1000,7 @@ public void entityPhysicsCheckNoMoveLargeVelocityHit(Env env) { } @Test - public void entityPhysicsCheckLargeVelocityHitNoMove(Env env) { + void entityPhysicsCheckLargeVelocityHitNoMove(Env env) { var instance = env.createFlatInstance(); var entity = new Entity(EntityType.ZOMBIE); @@ -1019,7 +1019,7 @@ public void entityPhysicsCheckLargeVelocityHitNoMove(Env env) { } @Test - public void entityPhysicsCheckDoorSubBlockSouthRepeat(Env env) { + void entityPhysicsCheckDoorSubBlockSouthRepeat(Env env) { var instance = env.createFlatInstance(); Block b = Block.ACACIA_TRAPDOOR.withProperties(Map.of("facing", "south", "open", "true")); @@ -1037,7 +1037,7 @@ public void entityPhysicsCheckDoorSubBlockSouthRepeat(Env env) { } @Test - public void entityPhysicsCheckCollisionDownCache(Env env) { + void entityPhysicsCheckCollisionDownCache(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 43, 1, Block.STONE); @@ -1057,7 +1057,7 @@ public void entityPhysicsCheckCollisionDownCache(Env env) { } @Test - public void entityPhysicsCheckGravityCached(Env env) { + void entityPhysicsCheckGravityCached(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 43, 1, Block.STONE); @@ -1088,7 +1088,7 @@ public void entityPhysicsCheckGravityCached(Env env) { } @Test - public void entityBlockPositionTestSlightlyAbove(Env env) { + void entityBlockPositionTestSlightlyAbove(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 0, Block.STONE); @@ -1103,7 +1103,7 @@ public void entityBlockPositionTestSlightlyAbove(Env env) { } @Test - public void entityBlockPositionTestFarAbove(Env env) { + void entityBlockPositionTestFarAbove(Env env) { var instance = env.createFlatInstance(); instance.setBlock(0, 42, 0, Block.STONE); diff --git a/src/test/java/net/minestom/server/command/ArgumentTypeTest.java b/src/test/java/net/minestom/server/command/ArgumentTypeTest.java index 7bbdfa6b345..b7450a6f89d 100644 --- a/src/test/java/net/minestom/server/command/ArgumentTypeTest.java +++ b/src/test/java/net/minestom/server/command/ArgumentTypeTest.java @@ -35,14 +35,14 @@ import static org.junit.jupiter.api.Assertions.*; -public class ArgumentTypeTest { +class ArgumentTypeTest { static { MinecraftServer.init(); } @Test - public void testArgumentEntityType() { + void testArgumentEntityType() { var arg = ArgumentType.EntityType("entity_type"); assertInvalidArg(arg, "minecraft:invalid_entity_type"); assertArg(arg, EntityType.ARMOR_STAND, EntityType.ARMOR_STAND.name()); @@ -50,7 +50,7 @@ public void testArgumentEntityType() { } @Test - public void testArgumentParticle() { + void testArgumentParticle() { var arg = ArgumentType.Particle("particle"); assertInvalidArg(arg, "minecraft:invalid_particle"); assertArg(arg, Particle.BLOCK, Particle.BLOCK.name()); @@ -58,7 +58,7 @@ public void testArgumentParticle() { } @Test - public void testArgumentBlockState() { + void testArgumentBlockState() { var arg = ArgumentType.BlockState("block_state"); assertInvalidArg(arg, "minecraft:invalid_block[invalid_property=invalid_key]"); assertInvalidArg(arg, "minecraft:stone[invalid_property=invalid_key]"); @@ -69,7 +69,7 @@ public void testArgumentBlockState() { } @Test - public void testArgumentColor() { + void testArgumentColor() { var arg = ArgumentType.Color("color"); assertInvalidArg(arg, "invalid_color"); assertArg(arg, Style.style(NamedTextColor.DARK_PURPLE), "dark_purple"); @@ -77,7 +77,7 @@ public void testArgumentColor() { } @Test - public void testArgumentComponent() { + void testArgumentComponent() { var arg = ArgumentType.Component("component"); var component1 = Component.text("Example text", NamedTextColor.DARK_AQUA); var component2 = Component.text("Other example text", Style.style(TextDecoration.OBFUSCATED)); @@ -90,7 +90,7 @@ public void testArgumentComponent() { } @Test - public void testArgumentEntity() { + void testArgumentEntity() { var arg = ArgumentType.Entity("entity"); assertValidArg(arg, "@a"); @@ -127,7 +127,7 @@ public void testArgumentEntity() { } @Test - public void testArgumentFloatRange() { + void testArgumentFloatRange() { var arg = ArgumentType.FloatRange("float_range"); assertArg(arg, new FloatRange(0f, 50f), "0..50"); assertArg(arg, new FloatRange(0f, 0f), "0..0"); @@ -142,7 +142,7 @@ public void testArgumentFloatRange() { } @Test - public void testArgumentIntRange() { + void testArgumentIntRange() { var arg = ArgumentType.IntRange("int_range"); assertArg(arg, new IntRange(0, 50), "0..50"); @@ -161,7 +161,7 @@ public void testArgumentIntRange() { } @Test - public void testArgumentItemStack() { + void testArgumentItemStack() { var arg = ArgumentType.ItemStack("item_stack"); assertArg(arg, ItemStack.AIR, "air"); assertArg(arg, ItemStack.of(Material.GLASS_PANE).withTag(Tag.String("tag"), "value"), "glass_pane{tag:value}"); @@ -172,7 +172,7 @@ public void testArgumentItemStack() { } @Test - public void testArgumentNbtCompoundTag() { + void testArgumentNbtCompoundTag() { var arg = ArgumentType.NbtCompound("nbt_compound"); assertArg(arg, CompoundBinaryTag.builder().putLongArray("long_array", new long[]{12, 49, 119}).build(), "{\"long_array\":[L;12L,49L,119L]}"); @@ -186,7 +186,7 @@ public void testArgumentNbtCompoundTag() { } @Test - public void testArgumentNbtTag() { + void testArgumentNbtTag() { var arg = ArgumentType.NBT("nbt"); assertArg(arg, StringBinaryTag.stringBinaryTag("string"), "string"); assertArg(arg, StringBinaryTag.stringBinaryTag("string"), "\"string\""); @@ -202,14 +202,14 @@ public void testArgumentNbtTag() { } @Test - public void testArgumentResource() { + void testArgumentResource() { var arg = ArgumentType.Resource("resource", "minecraft:block"); assertArg(arg, "minecraft:resource_example", "minecraft:resource_example"); assertInvalidArg(arg, "minecraft:invalid resource"); } @Test - public void testArgumentResourceLocation() { + void testArgumentResourceLocation() { var arg = ArgumentType.ResourceLocation("resource_location"); assertArg(arg, "minecraft:resource_location_example", "minecraft:resource_location_example"); assertInvalidArg(arg, "minecraft:invalid resource location"); @@ -217,14 +217,14 @@ public void testArgumentResourceLocation() { } @Test - public void testArgumentResourceOrTag() { + void testArgumentResourceOrTag() { var arg = ArgumentType.ResourceOrTag("resource_or_tag", "data/minecraft/tags/blocks"); assertArg(arg, "minecraft:resource_or_tag_example", "minecraft:resource_or_tag_example"); assertInvalidArg(arg, "minecraft:invalid resource or tag"); } @Test - public void testArgumentTime() { + void testArgumentTime() { var arg = ArgumentType.Time("time"); assertArg(arg, Duration.of(20, TimeUnit.SERVER_TICK), "20"); assertArg(arg, Duration.of(40, TimeUnit.SERVER_TICK), "40t"); @@ -236,14 +236,14 @@ public void testArgumentTime() { } @Test - public void testArgumentUUID() { + void testArgumentUUID() { var arg = ArgumentType.UUID("uuid"); assertInvalidArg(arg, "invalid_uuid"); assertArg(arg, UUID.fromString("10515090-26f2-49fa-b2ba-9594d4d0451f"), "10515090-26f2-49fa-b2ba-9594d4d0451f"); } @Test - public void testArgumentDouble() { + void testArgumentDouble() { var arg = ArgumentType.Double("double"); assertArg(arg, 2564d, "2564"); assertArg(arg, -591.981d, "-591.981"); @@ -252,7 +252,7 @@ public void testArgumentDouble() { } @Test - public void testArgumentFloat() { + void testArgumentFloat() { var arg = ArgumentType.Float("float"); assertArg(arg, 2564f, "2564"); assertArg(arg, -591.981f, "-591.981"); @@ -261,7 +261,7 @@ public void testArgumentFloat() { } @Test - public void testArgumentInteger() { + void testArgumentInteger() { var arg = ArgumentType.Integer("integer"); assertArg(arg, 2564, "2564"); assertInvalidArg(arg, "256.4"); @@ -269,15 +269,15 @@ public void testArgumentInteger() { } @Test - public void testArgumentLong() { + void testArgumentLong() { var arg = ArgumentType.Long("long"); - assertArg(arg, 2564l, "2564"); + assertArg(arg, 2564L, "2564"); assertInvalidArg(arg, "256.4"); assertInvalidArg(arg, "9223372036854775808"); } @Test - public void testArgumentRelativeBlockPosition() { + void testArgumentRelativeBlockPosition() { var arg = ArgumentType.RelativeBlockPosition("relative_block_position"); var vec = new Vec(-3, 14, 255); @@ -301,7 +301,7 @@ public void testArgumentRelativeBlockPosition() { } @Test - public void testArgumentRelativeVec2() { + void testArgumentRelativeVec2() { var arg = ArgumentType.RelativeVec2("relative_vec_2"); var vec = new Vec(-3, 14.25); @@ -322,7 +322,7 @@ public void testArgumentRelativeVec2() { } @Test - public void testArgumentRelativeVec3() { + void testArgumentRelativeVec3() { var arg = ArgumentType.RelativeVec3("relative_vec_3"); var vec = new Vec(-3, 14.25, 255); @@ -343,7 +343,7 @@ public void testArgumentRelativeVec3() { } @Test - public void testArgumentBoolean() { + void testArgumentBoolean() { var arg = ArgumentType.Boolean("boolean"); assertArg(arg, true, "true"); assertArg(arg, false, "false"); @@ -351,7 +351,7 @@ public void testArgumentBoolean() { } @Test - public void testArgumentEnum() { + void testArgumentEnum() { enum ExampleEnum {FIRST, SECOND, Third, fourth} var arg = ArgumentType.Enum("enum", ExampleEnum.class); @@ -379,7 +379,7 @@ enum ExampleEnum {FIRST, SECOND, Third, fourth} } @Test - public void testArgumentGroup() { + void testArgumentGroup() { var arg = ArgumentType.Group("group", ArgumentType.Integer("integer"), ArgumentType.String("string"), ArgumentType.Double("double")); // Test normal input @@ -405,7 +405,7 @@ public void testArgumentGroup() { } @Test - public void testArgumentLiteral() { + void testArgumentLiteral() { var arg = ArgumentType.Literal("literal"); assertArg(arg, "literal", "literal"); assertInvalidArg(arg, "not_literal"); @@ -413,7 +413,7 @@ public void testArgumentLiteral() { } @Test - public void testArgumentLoop() { + void testArgumentLoop() { var arg = ArgumentType.Loop("loop", ArgumentType.String("string"), ArgumentType.String("string2").map(s -> { throw new IllegalArgumentException("This argument should never be triggered"); })); @@ -423,7 +423,7 @@ public void testArgumentLoop() { } @Test - public void testArgumentString() { + void testArgumentString() { var arg = ArgumentType.String("string"); assertArg(arg, "text", "text"); assertArg(arg, "more text", "\"more text\""); @@ -433,7 +433,7 @@ public void testArgumentString() { } @Test - public void testArgumentStringArray() { + void testArgumentStringArray() { var arg = ArgumentType.StringArray("string_array"); assertArrayArg(arg, new String[]{"example", "text"}, "example text"); assertArrayArg(arg, new String[]{"some", "more", "placeholder", "text"}, "some more placeholder text"); @@ -443,7 +443,7 @@ public void testArgumentStringArray() { } @Test - public void testArgumentWord() { + void testArgumentWord() { var arg = ArgumentType.Word("word").from("word1", "word2", "word3"); assertArg(arg, "word1", "word1"); @@ -455,7 +455,7 @@ public void testArgumentWord() { } @Test - public void testArgumentMapWithSender() { + void testArgumentMapWithSender() { var serverSender = new ServerSender(); var arg = ArgumentType.Word("word").from("word1", "word2", "word3") diff --git a/src/test/java/net/minestom/server/entity/pathfinding/PathfinderIntegrationTest.java b/src/test/java/net/minestom/server/entity/pathfinding/PathfinderIntegrationTest.java index 4c64fa61f16..e47c277af3c 100644 --- a/src/test/java/net/minestom/server/entity/pathfinding/PathfinderIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/pathfinding/PathfinderIntegrationTest.java @@ -25,6 +25,7 @@ public class PathfinderIntegrationTest { /** * Validate that the path is valid * Currently only checks to make sure path is not null, and that nodes are not inside blocks + * * @param nodes the nodes to validate * @return true if the path is valid */ @@ -57,9 +58,10 @@ public void testTall(Env env) { Navigator nav = new Navigator(zombie); nav.setPathTo(new Pos(0, 40, 10)); - while (nav.getState() == PPath.PathState.CALCULATING) {} + while (nav.getState() == PPath.State.CALCULATING) { + } - assert(nav.getNodes() != null); + assert (nav.getNodes() != null); validateNodes(nav.getNodes(), i); } @@ -76,9 +78,10 @@ public void testStraightLine(Env env) { Navigator nav = new Navigator(zombie); nav.setPathTo(new Pos(0, 40, 10)); - while (nav.getState() == PPath.PathState.CALCULATING) {} + while (nav.getState() == PPath.State.CALCULATING) { + } - assert(nav.getNodes() != null); + assert (nav.getNodes() != null); validateNodes(nav.getNodes(), i); } @@ -96,9 +99,10 @@ public void testShort(Env env) { Navigator nav = new Navigator(zombie); nav.setPathTo(new Pos(2, 40, 2)); - while (nav.getState() == PPath.PathState.CALCULATING) {} + while (nav.getState() == PPath.State.CALCULATING) { + } - assert(nav.getNodes() != null); + assert (nav.getNodes() != null); validateNodes(nav.getNodes(), i); } @@ -119,17 +123,18 @@ public void testBug(Env env) { Navigator nav = new Navigator(zombie); nav.setPathTo(new Pos(43.5, 40, -41.5)); - while (nav.getState() == PPath.PathState.CALCULATING) {} + while (nav.getState() == PPath.State.CALCULATING) { + } - assert(nav.getNodes() != null); + assert (nav.getNodes() != null); validateNodes(nav.getNodes(), i); } @Test public void testPFNodeEqual(Env env) { - PNode node1 = new PNode(new Pos(0.777, 0, 0), 2, 0, PNode.NodeType.WALK, null); - PNode node2 = new PNode(new Pos(0.777, 0, 0), 0, 3, PNode.NodeType.WALK, node1); + PNode node1 = new PNode(new Pos(0.777, 0, 0), 2, 0, PNode.Type.WALK, null); + PNode node2 = new PNode(new Pos(0.777, 0, 0), 0, 3, PNode.Type.WALK, node1); Set nodes = new HashSet<>(); nodes.add(node1); @@ -183,9 +188,10 @@ public void testStraightLineBlocked(Env env) { Navigator nav = new Navigator(zombie); nav.setPathTo(new Pos(0, 40, 10)); - while (nav.getState() == PPath.PathState.CALCULATING) {} + while (nav.getState() == PPath.State.CALCULATING) { + } - assert(nav.getNodes() != null); + assert (nav.getNodes() != null); validateNodes(nav.getNodes(), i); } diff --git a/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java index 691c3113f54..90ef13af8f7 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java @@ -25,11 +25,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; @ExtendWith(MicrotusExtension.class) -public class PlayerBlockPlacementIntegrationTest { +class PlayerBlockPlacementIntegrationTest { @ParameterizedTest @MethodSource("placeBlockFromAdventureModeParams") - public void placeBlockFromAdventureMode(Block baseBlock, BlockPredicates canPlaceOn, Env env) { + void placeBlockFromAdventureMode(Block baseBlock, BlockPredicates canPlaceOn, Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); var player = connection.connect(instance, new Pos(0, 42, 0)).join(); diff --git a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java index 60fc66c523b..747b75ddc65 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java @@ -23,6 +23,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CompletableFuture; diff --git a/src/test/java/net/minestom/server/instance/BlockTest.java b/src/test/java/net/minestom/server/instance/BlockTest.java index eadc2e82192..085ca6db8c9 100644 --- a/src/test/java/net/minestom/server/instance/BlockTest.java +++ b/src/test/java/net/minestom/server/instance/BlockTest.java @@ -7,10 +7,12 @@ import net.minestom.server.tag.Tag; import org.junit.jupiter.api.Test; +import java.util.HashSet; import java.util.Map; import java.util.Objects; import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class BlockTest { @@ -84,4 +86,23 @@ public void testShape() { assertEquals(start, new Vec(0.3125, 0, 0.3125)); assertEquals(end, new Vec(0.6875, 0.5625, 0.6875)); } + + @Test + public void testDuplicateProperties() { + HashSet assignedStates = new HashSet<>(); + for (Block block : Block.values()) { + for (Block blockWithState : block.possibleStates()) { + assertTrue(assignedStates.add(blockWithState.stateId())); + } + } + } + + @Test + public void testStateIdConversion() { + for (Block block : Block.values()) { + for (Block blockWithState : block.possibleStates()) { + assertEquals(blockWithState, Block.fromStateId(blockWithState.stateId())); + } + } + } } diff --git a/src/test/java/net/minestom/server/instance/WorldBorderIntegrationTest.java b/src/test/java/net/minestom/server/instance/WorldBorderIntegrationTest.java index 6433c97bf23..78c33cc903d 100644 --- a/src/test/java/net/minestom/server/instance/WorldBorderIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/WorldBorderIntegrationTest.java @@ -9,7 +9,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @ExtendWith(MicrotusExtension.class) -public class WorldBorderIntegrationTest { +class WorldBorderIntegrationTest { @Test public void setWorldborderSize(Env env) { diff --git a/src/test/java/net/minestom/server/instance/light/LightParityIntegrationTest.java b/src/test/java/net/minestom/server/instance/light/LightParityIntegrationTest.java index 7a9389cfee0..92d2fe1bc52 100644 --- a/src/test/java/net/minestom/server/instance/light/LightParityIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/light/LightParityIntegrationTest.java @@ -28,7 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; @ExtendWith(MicrotusExtension.class) -public class LightParityIntegrationTest { +class LightParityIntegrationTest { private static final int REGION_SIZE = 3; @Test diff --git a/src/test/java/net/minestom/server/inventory/InventoryIntegrationTest.java b/src/test/java/net/minestom/server/inventory/InventoryIntegrationTest.java index 85af77e4d53..8d2290e3286 100644 --- a/src/test/java/net/minestom/server/inventory/InventoryIntegrationTest.java +++ b/src/test/java/net/minestom/server/inventory/InventoryIntegrationTest.java @@ -1,6 +1,8 @@ package net.minestom.server.inventory; import net.kyori.adventure.text.Component; +import net.minestom.server.utils.inventory.PlayerInventoryUtils; +import net.minestom.testing.Env; import net.minestom.server.coordinate.Pos; import net.minestom.server.event.item.ItemDropEvent; import net.minestom.server.item.ItemStack; @@ -8,8 +10,6 @@ import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.WindowItemsPacket; -import net.minestom.server.utils.inventory.PlayerInventoryUtils; -import net.minestom.testing.Env; import net.minestom.testing.extension.MicrotusExtension; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -17,12 +17,13 @@ import static org.junit.jupiter.api.Assertions.*; @ExtendWith(MicrotusExtension.class) -public class InventoryIntegrationTest { +class InventoryIntegrationTest { + private static final Component TITLE = Component.text("title"); private static final ItemStack MAGIC_STACK = ItemStack.of(Material.DIAMOND, 3); @Test - public void setSlotDuplicateTest(Env env) { + void setSlotDuplicateTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); var player = connection.connect(instance, new Pos(0, 42, 0)).join(); @@ -46,7 +47,7 @@ public void setSlotDuplicateTest(Env env) { } @Test - public void setCursorItemDuplicateTest(Env env) { + void setCursorItemDuplicateTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); var player = connection.connect(instance, new Pos(0, 42, 0)).join(); @@ -70,7 +71,7 @@ public void setCursorItemDuplicateTest(Env env) { } @Test - public void clearInventoryTest(Env env) { + void clearInventoryTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); var player = connection.connect(instance, new Pos(0, 42, 0)).join(); @@ -146,11 +147,11 @@ public void clearingPlayerInventoryClearsCursorTest(Env env) { } @Test - public void closeInventoryTest(Env env) { + void closeInventoryTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); var player = connection.connect(instance, new Pos(0, 42, 0)).join(); - final var inventory = new Inventory(InventoryType.CHEST_1_ROW, Component.text("title")); + final var inventory = new Inventory(InventoryType.CHEST_1_ROW, TITLE); player.openInventory(inventory); assertSame(inventory, player.getOpenInventory()); player.closeInventory(); @@ -158,12 +159,12 @@ public void closeInventoryTest(Env env) { } @Test - public void openInventoryOnItemDropFromInventoryClosingTest(Env env) { + void openInventoryOnItemDropFromInventoryClosingTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); var player = connection.connect(instance, new Pos(0, 42, 0)).join(); var listener = env.listen(ItemDropEvent.class); - final var firstInventory = new Inventory(InventoryType.CHEST_1_ROW, Component.text("title")); + final var firstInventory = new Inventory(InventoryType.CHEST_1_ROW, TITLE); player.openInventory(firstInventory); assertSame(firstInventory, player.getOpenInventory()); player.getInventory().setCursorItem(ItemStack.of(Material.STONE)); @@ -173,15 +174,15 @@ public void openInventoryOnItemDropFromInventoryClosingTest(Env env) { assertNull(player.getOpenInventory()); player.openInventory(firstInventory); - player.getInventory().setCursorItem(ItemStack.of(Material.STONE)); - final var secondInventory = new Inventory(InventoryType.CHEST_1_ROW, Component.text("title")); + firstInventory.setCursorItem(player, ItemStack.of(Material.STONE)); + final var secondInventory = new Inventory(InventoryType.CHEST_1_ROW, TITLE); listener.followup(event -> event.getPlayer().openInventory(secondInventory)); player.closeInventory(); assertSame(secondInventory, player.getOpenInventory()); } @Test - public void testInnerInventorySlotSending(Env env) { + void testInnerInventorySlotSending(Env env) { // Inner inventory changes are sent along with the open inventory // Otherwise, they are sent separately diff --git a/src/test/java/net/minestom/server/network/packet/ClientPluginMessagePacketTest.java b/src/test/java/net/minestom/server/network/packet/ClientPluginMessagePacketTest.java new file mode 100644 index 00000000000..d017b4a42e2 --- /dev/null +++ b/src/test/java/net/minestom/server/network/packet/ClientPluginMessagePacketTest.java @@ -0,0 +1,29 @@ +package net.minestom.server.network.packet; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.client.common.ClientPluginMessagePacket; +import org.junit.jupiter.api.Test; + +import java.nio.ByteBuffer; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ClientPluginMessagePacketTest { + + @Test + void testClientPluginMessagePacket() { + ByteBuffer buf = ByteBuffer.allocateDirect(1024); // The default from NetworkBuffer + NetworkBuffer networkBuffer = new NetworkBuffer(buf); + ClientPluginMessagePacket clientPluginMessagePacket = new ClientPluginMessagePacket("channel", new byte[0]); + + clientPluginMessagePacket.write(networkBuffer); + buf.limit(networkBuffer.writeIndex()); // Must set limit so that RAW_BYTES in plugin message packet has a len. + + var packet = new ClientPluginMessagePacket(networkBuffer); + + assertEquals("channel", packet.channel()); + assertArrayEquals(new byte[0], packet.data()); + } + +}