diff --git a/build.gradle b/build.gradle
index 9392dc647..986c6a9c4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -164,7 +164,7 @@ dependencies {
}
api "com.github.Minestom:DependencyGetter:v1.0.1"
- implementation 'com.github.Minestom:MinestomDataGenerator:b13c934eba'
+ implementation 'com.github.Minestom:MinestomDataGenerator:7636d5d473'
// Adventure, for user-interface
api "net.kyori:adventure-api:$adventureVersion"
diff --git a/code-generators/build.gradle b/code-generators/build.gradle
index 675f41670..ec6adec11 100644
--- a/code-generators/build.gradle
+++ b/code-generators/build.gradle
@@ -25,7 +25,7 @@ dependencies {
// SLF4J is the base logger for most libraries, therefore we can hook it into log4j2.
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.14.1'
// Contains the json files
- implementation 'com.github.Minestom:MinestomDataGenerator:b13c934eba'
+ implementation 'com.github.Minestom:MinestomDataGenerator:7636d5d473'
}
diff --git a/src/main/java/net/minestom/server/MinecraftServer.java b/src/main/java/net/minestom/server/MinecraftServer.java
index f23b5dd38..a2981821b 100644
--- a/src/main/java/net/minestom/server/MinecraftServer.java
+++ b/src/main/java/net/minestom/server/MinecraftServer.java
@@ -28,7 +28,6 @@ import net.minestom.server.network.packet.server.play.ServerDifficultyPacket;
import net.minestom.server.network.packet.server.play.UpdateViewDistancePacket;
import net.minestom.server.ping.ResponseDataConsumer;
import net.minestom.server.recipe.RecipeManager;
-import net.minestom.server.registry.ResourceGatherer;
import net.minestom.server.scoreboard.TeamManager;
import net.minestom.server.storage.StorageLocation;
import net.minestom.server.storage.StorageManager;
@@ -46,8 +45,6 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-
/**
* The main server class used to start the server and retrieve all the managers.
*
@@ -176,13 +173,6 @@ public final class MinecraftServer {
nettyServer = new NettyServer(packetProcessor);
- // Registry
- try {
- ResourceGatherer.ensureResourcesArePresent(VERSION_NAME);
- } catch (IOException e) {
- LOGGER.error("An error happened during resource gathering. Minestom will attempt to load anyway, but things may not work, and crashes can happen.", e);
- }
-
initialized = true;
minecraftServer = new MinecraftServer();
diff --git a/src/main/java/net/minestom/server/gamedata/loottables/LootTableManager.java b/src/main/java/net/minestom/server/gamedata/loottables/LootTableManager.java
index c96d10384..5a160f454 100644
--- a/src/main/java/net/minestom/server/gamedata/loottables/LootTableManager.java
+++ b/src/main/java/net/minestom/server/gamedata/loottables/LootTableManager.java
@@ -5,17 +5,17 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import net.minestom.server.MinecraftServer;
import net.minestom.server.gamedata.Condition;
-import net.minestom.server.registry.ResourceGatherer;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.NamespaceIDHashMap;
-import java.io.*;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.Reader;
/**
* Handles loading and configuration of loot tables
*/
public final class LootTableManager {
-
private NamespaceIDHashMap> conditionDeserializers = new NamespaceIDHashMap<>();
private NamespaceIDHashMap tableTypes = new NamespaceIDHashMap<>();
private NamespaceIDHashMap entryTypes = new NamespaceIDHashMap<>();
@@ -71,7 +71,8 @@ public final class LootTableManager {
}
public LootTable load(NamespaceID name) throws FileNotFoundException {
- return load(name, new FileReader(new File(ResourceGatherer.DATA_FOLDER, "data/" + name.getDomain() + "/loot_tables/" + name.getPath() + ".json")));
+ return null; // FIXME
+ //return load(name, new FileReader(new File(ResourceGatherer.DATA_FOLDER, "data/" + name.getDomain() + "/loot_tables/" + name.getPath() + ".json")));
}
/**
diff --git a/src/main/java/net/minestom/server/gamedata/loottables/entries/TagType.java b/src/main/java/net/minestom/server/gamedata/loottables/entries/TagType.java
index 6aad1f812..b804af71f 100644
--- a/src/main/java/net/minestom/server/gamedata/loottables/entries/TagType.java
+++ b/src/main/java/net/minestom/server/gamedata/loottables/entries/TagType.java
@@ -6,9 +6,8 @@ import net.minestom.server.gamedata.loottables.LootTable;
import net.minestom.server.gamedata.loottables.LootTableEntryType;
import net.minestom.server.gamedata.loottables.LootTableFunction;
import net.minestom.server.gamedata.loottables.LootTableManager;
-import net.minestom.server.utils.NamespaceID;
+import net.minestom.server.gamedata.tags.Tag;
-import java.io.FileNotFoundException;
import java.util.List;
/**
@@ -17,11 +16,6 @@ import java.util.List;
public class TagType implements LootTableEntryType {
@Override
public LootTable.Entry create(LootTableManager lootTableManager, String name, List conditions, List children, boolean expand, List functions, int weight, int quality) {
- try {
- return new TagEntry(this, MinecraftServer.getTagManager().load(NamespaceID.from(name), "items"), expand, weight, quality, conditions);
- } catch (FileNotFoundException e) {
- MinecraftServer.getExceptionManager().handleException(e);
- return null;
- }
+ return new TagEntry(this, MinecraftServer.getTagManager().getTag(Tag.BasicType.ITEMS, name), expand, weight, quality, conditions);
}
}
diff --git a/src/main/java/net/minestom/server/gamedata/tags/RequiredTag.java b/src/main/java/net/minestom/server/gamedata/tags/RequiredTag.java
deleted file mode 100644
index 2bc2dcd24..000000000
--- a/src/main/java/net/minestom/server/gamedata/tags/RequiredTag.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package net.minestom.server.gamedata.tags;
-
-import net.minestom.server.utils.NamespaceID;
-
-public class RequiredTag {
- private final Tag.BasicTypes type;
- private final NamespaceID name;
-
- public RequiredTag(Tag.BasicTypes type, NamespaceID name) {
- this.type = type;
- this.name = name;
- }
-
- public NamespaceID getName() {
- return name;
- }
-
- public Tag.BasicTypes getType() {
- return type;
- }
-}
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 7649f7309..884e25bf9 100644
--- a/src/main/java/net/minestom/server/gamedata/tags/Tag.java
+++ b/src/main/java/net/minestom/server/gamedata/tags/Tag.java
@@ -1,32 +1,34 @@
package net.minestom.server.gamedata.tags;
+import net.minestom.server.entity.EntityType;
+import net.minestom.server.instance.block.Block;
+import net.minestom.server.item.Material;
+import net.minestom.server.registry.Registries;
+import net.minestom.server.registry.Registry;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.io.FileNotFoundException;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
+import java.util.function.Function;
/**
* Represents a group of items, blocks, fluids, entity types or function.
* Immutable by design
*/
-public class Tag {
-
- public static final Tag EMPTY = new Tag(NamespaceID.from("minestom:empty"));
+public final class Tag {
private final NamespaceID name;
-
- private Set values;
+ private final Set values;
/**
* Creates a new empty tag. This does not cache the tag.
*/
public Tag(NamespaceID name) {
this.name = name;
- values = new HashSet<>();
- lockValues();
+ this.values = new HashSet<>();
}
/**
@@ -35,42 +37,10 @@ public class Tag {
public Tag(NamespaceID name, Set values) {
this.name = name;
this.values = new HashSet<>(values);
- lockValues();
}
/**
- * Creates a new tag with the contents of the container
- *
- * @param manager Used to load tag contents (as tags are valid values inside 'values')
- * @param lowerPriority Tag contents from lower priority data packs. If 'replace' is false in 'container',
- * appends the contents of that pack to the one being constructed
- * @param container
- */
- public Tag(TagManager manager, NamespaceID name, String type, Tag lowerPriority, TagContainer container) throws FileNotFoundException {
- this.name = name;
- values = new HashSet<>();
- if (!container.replace) {
- values.addAll(lowerPriority.values);
- }
- Objects.requireNonNull(container.values, "Attempted to load from a TagContainer with no 'values' array");
- for (String line : container.values) {
- if (line.startsWith("#")) { // pull contents from a tag
- Tag subtag = manager.load(NamespaceID.from(line.substring(1)), type);
- values.addAll(subtag.values);
- } else {
- values.add(NamespaceID.from(line));
- }
- }
-
- lockValues();
- }
-
- private void lockValues() {
- values = Set.copyOf(values);
- }
-
- /**
- * Checks whether the given id in inside this tag
+ * Checks whether the given id in inside this tag.
*
* @param id the id to check against
* @return 'true' iif this tag contains the given id
@@ -85,40 +55,55 @@ public class Tag {
* @return immutable set of values present in this tag
*/
public Set getValues() {
- return values;
+ return Collections.unmodifiableSet(values);
}
/**
* Returns the name of this tag
- *
- * @return
*/
public NamespaceID getName() {
return name;
}
- public enum BasicTypes {
- BLOCKS("minecraft:block"),
- ITEMS("minecraft:item"),
- FLUIDS("minecraft:fluid"),
- ENTITY_TYPES("minecraft:entity_type"),
- GAME_EVENTS("minecraft:game_event");
+ public enum BasicType {
+ BLOCKS("minecraft:block", Registry.Resource.BLOCK_TAGS,
+ name -> Objects.requireNonNull(Block.fromNamespaceId(name)).id()),
+ ITEMS("minecraft:item", Registry.Resource.ITEM_TAGS,
+ name -> Objects.requireNonNull(Material.fromNamespaceId(name)).id()),
+ FLUIDS("minecraft:fluid", Registry.Resource.FLUID_TAGS,
+ name -> 1), // TODO
+ 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 -> Registries.getFluid(name).ordinal());
- private final static BasicTypes[] VALUES = values();
+ private final static BasicType[] VALUES = values();
private final String identifier;
+ private final Registry.Resource resource;
+ private final Function function;
- BasicTypes(@NotNull String identifier) {
+ BasicType(@NotNull String identifier,
+ @NotNull Registry.Resource resource,
+ @NotNull Function function) {
this.identifier = identifier;
+ this.resource = resource;
+ this.function = function;
}
- @NotNull
- public String getIdentifier() {
+ public @NotNull String getIdentifier() {
return identifier;
}
- @Nullable
- public static BasicTypes fromIdentifer(@NotNull String identifier) {
- for (BasicTypes value : VALUES) {
+ public Registry.Resource getResource() {
+ return resource;
+ }
+
+ public Function getFunction() {
+ return function;
+ }
+
+ public static @Nullable Tag.BasicType fromIdentifer(@NotNull String identifier) {
+ for (BasicType value : VALUES) {
if (value.identifier.equals(identifier)) {
return value;
}
diff --git a/src/main/java/net/minestom/server/gamedata/tags/TagContainer.java b/src/main/java/net/minestom/server/gamedata/tags/TagContainer.java
deleted file mode 100644
index 7f181851a..000000000
--- a/src/main/java/net/minestom/server/gamedata/tags/TagContainer.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.minestom.server.gamedata.tags;
-
-/**
- * Meant only for parsing tag JSON
- */
-public class TagContainer {
- boolean replace;
- String[] values;
-}
diff --git a/src/main/java/net/minestom/server/gamedata/tags/TagManager.java b/src/main/java/net/minestom/server/gamedata/tags/TagManager.java
index 30e46a0c9..c8805f8c3 100644
--- a/src/main/java/net/minestom/server/gamedata/tags/TagManager.java
+++ b/src/main/java/net/minestom/server/gamedata/tags/TagManager.java
@@ -1,340 +1,57 @@
package net.minestom.server.gamedata.tags;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import net.minestom.server.MinecraftServer;
-import net.minestom.server.network.packet.server.play.TagsPacket;
-import net.minestom.server.registry.ResourceGatherer;
+import com.google.gson.JsonObject;
+import net.minestom.server.registry.Registry;
import net.minestom.server.utils.NamespaceID;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.jetbrains.annotations.Nullable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* Handles loading and caching of tags.
*/
-public class TagManager {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(TagManager.class);
- private final Gson gson;
- private final Map cache = new ConcurrentHashMap<>();
- private final List requiredTags = new LinkedList<>();
+public final class TagManager {
+ private final Map> tagMap = new ConcurrentHashMap<>();
public TagManager() {
- gson = new GsonBuilder()
- .create();
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("acacia_logs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("anvil"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("bamboo_plantable_on"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("banners"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("base_stone_nether"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("base_stone_overworld"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("beacon_base_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("beds"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("beehives"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("bee_growables"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("birch_logs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("buttons"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("campfires"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("candles"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("candle_cakes"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("carpets"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("cauldrons"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("cave_vines"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("climbable"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("coal_ores"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("copper_ores"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("corals"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("coral_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("coral_plants"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("crimson_stems"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("crops"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("crystal_sound_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("dark_oak_logs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("deepslate_ore_replaceables"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("diamond_ores"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("dirt"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("doors"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("dragon_immune"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("dripstone_replaceable_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("emerald_ores"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("enderman_holdable"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("features_cannot_replace"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("fences"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("fence_gates"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("fire"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("flowers"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("flower_pots"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("geode_invalid_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("gold_ores"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("guarded_by_piglins"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("hoglin_repellents"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("ice"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("impermeable"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("infiniburn_end"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("infiniburn_nether"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("infiniburn_overworld"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("inside_step_sound_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("iron_ores"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("jungle_logs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("lapis_ores"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("lava_pool_stone_replaceables"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("leaves"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("logs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("logs_that_burn"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("lush_ground_replaceable"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("moss_replaceable"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("mushroom_grow_block"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("needs_diamond_tool"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("needs_iron_tool"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("needs_stone_tool"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("non_flammable_wood"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("nylium"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("oak_logs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("occludes_vibration_signals"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("piglin_repellents"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("planks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("portals"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("pressure_plates"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("prevent_mob_spawning_inside"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("rails"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("redstone_ores"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("sand"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("saplings"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("shulker_boxes"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("signs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("slabs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("small_dripleaf_placeable"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("small_flowers"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("snow"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("soul_fire_base_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("soul_speed_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("spruce_logs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("stairs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("standing_signs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("stone_bricks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("stone_ore_replaceables"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("stone_pressure_plates"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("strider_warm_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("tall_flowers"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("trapdoors"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("underwater_bonemeals"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("unstable_bottom_center"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("valid_spawn"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("walls"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wall_corals"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wall_post_override"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wall_signs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("warped_stems"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wart_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wither_immune"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wither_summon_base_blocks"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wooden_buttons"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wooden_doors"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wooden_fences"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wooden_pressure_plates"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wooden_slabs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wooden_stairs"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wooden_trapdoors"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("wool"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("mineable/axe"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("mineable/hoe"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("mineable/pickaxe"));
- addRequiredTag(Tag.BasicTypes.BLOCKS, NamespaceID.from("mineable/shovel"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("arrows"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("axolotl_always_hostiles"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("axolotl_hunt_targets"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("beehive_inhabitors"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("freeze_hurts_extra_types"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("freeze_immune_entity_types"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("impact_projectiles"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("powder_snow_walkable_mobs"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("raiders"));
- addRequiredTag(Tag.BasicTypes.ENTITY_TYPES, NamespaceID.from("skeletons"));
- addRequiredTag(Tag.BasicTypes.FLUIDS, NamespaceID.from("lava"));
- addRequiredTag(Tag.BasicTypes.FLUIDS, NamespaceID.from("water"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("acacia_logs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("anvil"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("arrows"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("axolotl_tempt_items"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("banners"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("beacon_payment_items"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("beds"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("birch_logs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("boats"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("buttons"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("candles"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("carpets"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("cluster_max_harvestables"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("coals"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("coal_ores"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("copper_ores"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("creeper_drop_music_discs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("crimson_stems"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("dark_oak_logs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("diamond_ores"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("doors"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("emerald_ores"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("fences"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("fishes"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("flowers"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("fox_food"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("freeze_immune_wearables"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("gold_ores"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("ignored_by_piglin_babies"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("iron_ores"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("jungle_logs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("lapis_ores"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("leaves"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("lectern_books"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("logs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("logs_that_burn"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("music_discs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("non_flammable_wood"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("oak_logs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("occludes_vibration_signals"));;
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("piglin_food"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("piglin_loved"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("piglin_repellents"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("planks"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("rails"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("redstone_ores"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("sand"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("saplings"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("signs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("slabs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("small_flowers"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("soul_fire_base_blocks"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("spruce_logs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("stairs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("stone_bricks"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("stone_crafting_materials"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("stone_tool_materials"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("tall_flowers"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("trapdoors"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("walls"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("warped_stems"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("wooden_buttons"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("wooden_doors"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("wooden_fences"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("wooden_pressure_plates"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("wooden_slabs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("wooden_stairs"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("wooden_trapdoors"));
- addRequiredTag(Tag.BasicTypes.ITEMS, NamespaceID.from("wool"));
- addRequiredTag(Tag.BasicTypes.GAME_EVENTS, NamespaceID.from("ignore_vibrations_sneaking"));
- addRequiredTag(Tag.BasicTypes.GAME_EVENTS, NamespaceID.from("vibrations"));
+ // Load required tags from files
+ for (var type : Tag.BasicType.values()) {
+ final var json = Registry.load(type.getResource());
+ final var tagIdentifierMap = tagMap.computeIfAbsent(type, s -> new CopyOnWriteArrayList<>());
+ json.keySet().forEach(tagName -> {
+ final var tag = new Tag(NamespaceID.from(tagName), getValues(json, tagName));
+ tagIdentifierMap.add(tag);
+ });
+ }
}
- /**
- * Loads a tag with the given name. This method attempts to read from "data/<name.domain>/tags/<tagType>/<name.path>.json" if the given name is not already present in cache
- *
- * @param name
- * @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
- * @return
- * @throws FileNotFoundException if the file does not exist
- */
- public Tag load(NamespaceID name, String tagType) throws FileNotFoundException {
- return load(name, tagType, () -> new FileReader(new File(ResourceGatherer.DATA_FOLDER, "data/" + name.getDomain() + "/tags/" + tagType + "/" + name.getPath() + ".json")));
+ public @Nullable Tag getTag(Tag.BasicType type, String namespace) {
+ final var tags = tagMap.get(type);
+ for (var tag : tags) {
+ if (tag.getName().asString().equals(namespace))
+ return tag;
+ }
+ return null;
}
- /**
- * Loads a tag with the given name. This method attempts to read from 'reader' if the given name is not already present in cache
- *
- * @param name
- * @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
- * @param reader
- * @return
- */
- public Tag load(NamespaceID name, String tagType, Reader reader) throws FileNotFoundException {
- return load(name, tagType, () -> reader);
+ public Map> getTagMap() {
+ return Collections.unmodifiableMap(tagMap);
}
- /**
- * Loads a tag with the given name. This method reads from 'reader'. This will override the previous tag
- *
- * @param name
- * @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
- * @param readerSupplier
- * @return
- */
- public Tag forceLoad(NamespaceID name, String tagType, ReaderSupplierWithFileNotFound readerSupplier) throws FileNotFoundException {
- Tag prev = cache.getOrDefault(name, Tag.EMPTY);
- Tag result = create(prev, name, tagType, readerSupplier);
- cache.put(name, result);
+ private Set getValues(JsonObject main, String value) {
+ JsonObject tagObject = main.getAsJsonObject(value);
+ final var tagValues = tagObject.getAsJsonArray("values");
+ Set result = new HashSet<>(tagValues.size());
+ tagValues.forEach(jsonElement -> {
+ final String tagString = jsonElement.getAsString();
+ if (tagString.startsWith("#")) {
+ result.addAll(getValues(main, tagString.substring(1)));
+ } else {
+ result.add(NamespaceID.from(tagString));
+ }
+ });
return result;
}
-
- /**
- * Loads a tag with the given name. This method attempts to read from 'reader' if the given name is not already present in cache
- *
- * @param name
- * @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
- * @param readerSupplier
- * @return
- */
- public Tag load(NamespaceID name, String tagType, ReaderSupplierWithFileNotFound readerSupplier) throws FileNotFoundException {
- Tag prev = cache.getOrDefault(name, Tag.EMPTY);
- Tag result = cache.get(name);
- if (result == null) {
- result = create(prev, name, tagType, readerSupplier);
- cache.put(name, result);
- }
- return result;
- }
-
- private Tag create(Tag prev, NamespaceID name, String tagType, ReaderSupplierWithFileNotFound reader) throws FileNotFoundException {
- TagContainer container = gson.fromJson(reader.get(), TagContainer.class);
- try {
- return new Tag(this, name, tagType, prev, container);
- } catch (FileNotFoundException e) {
- LOGGER.error("Failed to load tag due to error", e);
- return Tag.EMPTY;
- }
- }
-
- /**
- * Adds the required tags for the game to function correctly
- *
- * @param tagsPacket the packet to add the tags to
- */
- public void addRequiredTagsToPacket(TagsPacket tagsPacket) {
- for (RequiredTag requiredTag : requiredTags) {
- final Tag tag = silentLoad(requiredTag.getName(), requiredTag.getType().name().toLowerCase());
- var map = tagsPacket.tagsMap.computeIfAbsent(requiredTag.getType(), s -> new ArrayList<>());
- map.add(tag);
- }
- }
-
- /**
- * Adds a required tag to send to players when they connect
- *
- * @param type type of tag to send. Required so the client knows its use
- * @param name the name of the tag to load
- */
- public void addRequiredTag(Tag.BasicTypes type, NamespaceID name) {
- requiredTags.add(new RequiredTag(type, name));
- }
-
- private Tag silentLoad(NamespaceID name, String type) {
- try {
- return load(name, type);
- } catch (FileNotFoundException e) {
- MinecraftServer.getExceptionManager().handleException(e);
- return Tag.EMPTY;
- }
- }
-
- public interface ReaderSupplierWithFileNotFound {
- Reader get() throws FileNotFoundException;
- }
}
diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TagsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TagsPacket.java
index 14b9bb6a3..823eccf2a 100644
--- a/src/main/java/net/minestom/server/network/packet/server/play/TagsPacket.java
+++ b/src/main/java/net/minestom/server/network/packet/server/play/TagsPacket.java
@@ -1,34 +1,28 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.MinecraftServer;
-import net.minestom.server.entity.EntityType;
import net.minestom.server.gamedata.tags.Tag;
-import net.minestom.server.instance.block.Block;
-import net.minestom.server.item.Material;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
-import net.minestom.server.registry.Registries;
-import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
public class TagsPacket implements ServerPacket {
+ private static final TagsPacket REQUIRED_TAGS_PACKET = new TagsPacket(MinecraftServer.getTagManager().getTagMap());
- private static final TagsPacket REQUIRED_TAGS_PACKET = new TagsPacket();
+ public Map> tagsMap;
- static {
- MinecraftServer.getTagManager().addRequiredTagsToPacket(REQUIRED_TAGS_PACKET);
+ public TagsPacket(Map> tagsMap) {
+ this.tagsMap = tagsMap;
}
- public Map> tagsMap = new HashMap<>();
-
- /**
- * Default constructor, required for reflection operations.
- */
public TagsPacket() {
+ this(new HashMap<>());
}
@Override
@@ -37,105 +31,14 @@ public class TagsPacket implements ServerPacket {
for (var entry : tagsMap.entrySet()) {
final var type = entry.getKey();
final var tags = entry.getValue();
- // Tag type
writer.writeSizedString(type.getIdentifier());
- switch (type) {
- case BLOCKS: {
- // Number of tags
- writer.writeVarInt(tags.size());
- for (Tag tag : tags) {
- // name
- writer.writeSizedString(tag.getName().toString());
- final Set values = tag.getValues();
- // count
- writer.writeVarInt(values.size());
- // entries
- for (NamespaceID name : values) {
- Block b = Block.fromNamespaceId(name);
- if (b == null) {
- writer.writeVarInt(-1);
- continue;
- }
- writer.writeVarInt(b.id());
- }
- }
- break;
- }
- case ENTITY_TYPES: {
- // Number of tags
- writer.writeVarInt(tags.size());
- for (Tag tag : tags) {
- // name
- writer.writeSizedString(tag.getName().toString());
-
- final Set values = tag.getValues();
- // count
- writer.writeVarInt(values.size());
- // entries
- for (NamespaceID name : values) {
- EntityType et = EntityType.fromNamespaceId(name);
- if (et == null) {
- writer.writeVarInt(-1);
- } else {
- writer.writeVarInt(et.id());
- }
- }
- }
- break;
- }
- case FLUIDS: {
- // Number of tags
- writer.writeVarInt(tags.size());
- for (Tag tag : tags) {
- // name
- writer.writeSizedString(tag.getName().toString());
-
- final Set values = tag.getValues();
- // count
- writer.writeVarInt(values.size());
- // entries
- for (NamespaceID name : values) {
- writer.writeVarInt(Registries.getFluid(name).ordinal());
- }
- }
- break;
- }
- case GAME_EVENTS: {
- // Number of tags
- writer.writeVarInt(tags.size());
- for (Tag tag : tags) {
- // name
- writer.writeSizedString(tag.getName().toString());
-
- final Set values = tag.getValues();
- // count
- writer.writeVarInt(values.size());
- // entries
- for (NamespaceID name : values) {
- // TODO: GameEvents
- writer.writeVarInt(-1);
- }
- }
- break;
- }
- case ITEMS: {
- // Number of tags
- writer.writeVarInt(tags.size());
- for (Tag tag : tags) {
- // name
- writer.writeSizedString(tag.getName().toString());
-
- final Set values = tag.getValues();
- // count
- writer.writeVarInt(values.size());
- // entries
- for (NamespaceID name : values) {
- // FIXME: invalid namespace
- final var material = Objects.requireNonNullElse(Material.fromNamespaceId(name), Material.AIR);
- writer.writeVarInt(material.id());
- }
- }
- break;
+ writer.writeVarInt(tags.size());
+ for (var tag : tags) {
+ writer.writeSizedString(tag.getName().asString());
+ final var values = tag.getValues();
+ writer.writeVarInt(values.size());
+ for (var name : values) {
+ writer.writeVarInt(type.getFunction().apply(name.asString()));
}
}
}
@@ -148,7 +51,7 @@ public class TagsPacket implements ServerPacket {
final int typeCount = reader.readVarInt();
for (int i = 0; i < typeCount; i++) {
// Read tag type
- final Tag.BasicTypes tagType = Tag.BasicTypes.fromIdentifer(reader.readSizedString());
+ final Tag.BasicType tagType = Tag.BasicType.fromIdentifer(reader.readSizedString());
if (tagType == null) {
throw new IllegalArgumentException("Tag type could not be resolved");
}
@@ -173,8 +76,7 @@ public class TagsPacket implements ServerPacket {
*
* @return the default tags packet
*/
- @NotNull
- public static TagsPacket getRequiredTagsPacket() {
+ public static @NotNull TagsPacket getRequiredTagsPacket() {
return REQUIRED_TAGS_PACKET;
}
}
diff --git a/src/main/java/net/minestom/server/registry/Registry.java b/src/main/java/net/minestom/server/registry/Registry.java
index 2fc18266e..488ad880a 100644
--- a/src/main/java/net/minestom/server/registry/Registry.java
+++ b/src/main/java/net/minestom/server/registry/Registry.java
@@ -56,7 +56,13 @@ public class Registry {
STATISTICS("custom_statistics"),
POTION_EFFECTS("potion_effects"),
POTION_TYPES("potions"),
- PARTICLES("particles");
+ PARTICLES("particles"),
+
+ BLOCK_TAGS("tags/block_tags"),
+ ENTITY_TYPE_TAGS("tags/entity_type_tags"),
+ FLUID_TAGS("tags/fluid_tags"),
+ GAMEPLAY_TAGS("tags/gameplay_tags"),
+ ITEM_TAGS("tags/item_tags");
private final String name;
diff --git a/src/main/java/net/minestom/server/registry/ResourceGatherer.java b/src/main/java/net/minestom/server/registry/ResourceGatherer.java
deleted file mode 100644
index 307cd0ce7..000000000
--- a/src/main/java/net/minestom/server/registry/ResourceGatherer.java
+++ /dev/null
@@ -1,216 +0,0 @@
-package net.minestom.server.registry;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
-import net.minestom.server.utils.StringUtils;
-import org.jetbrains.annotations.NotNull;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-/**
- * Responsible for making sure Minestom has the necessary files to run (notably registry files)
- */
-public class ResourceGatherer {
- public static final File DATA_FOLDER = new File("./minecraft_data/");
- private static final Gson GSON = new Gson();
- private static final Logger LOGGER = LoggerFactory.getLogger(ResourceGatherer.class);
- private static final File TMP_FOLDER = new File("./.minestom_tmp/");
-
- /**
- * Checks if registry/ folder is present
- * If it is not, download the minecraft server jar, run the data generator and extract the wanted files
- * If it is already present, directly return
- */
- public static void ensureResourcesArePresent(String version) throws IOException {
- if (DATA_FOLDER.exists()) {
- return;
- }
- LOGGER.info("{} folder does not exist. Minestom will now generate the necessary files.", DATA_FOLDER);
-
- if (!TMP_FOLDER.exists() && !TMP_FOLDER.mkdirs()) {
- throw new IOException("Failed to create tmp folder.");
- }
-
- LOGGER.info("Starting download of Minecraft server jar for version {} from Mojang servers...", version);
- File serverJar = downloadServerJar(version);
- LOGGER.info("Download complete.");
-
- runDataGenerator(serverJar);
-
- moveAndCleanup(version);
- LOGGER.info("Resource gathering done!");
- }
-
- private static void moveAndCleanup(String version) throws IOException {
- Path dataFolderPath = DATA_FOLDER.toPath();
- Path tmpFolderPath = TMP_FOLDER.toPath();
- Path generatedFolder = tmpFolderPath.resolve("generated");
- LOGGER.info("Data generator successful, removing server jar");
- Files.delete(tmpFolderPath.resolve("server_" + version + ".jar"));
- LOGGER.info("Removal successful, now moving data to {}", DATA_FOLDER);
- Files.walkFileTree(tmpFolderPath, new SimpleFileVisitor<>() {
-
- @Override
- public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
- Path relativePath = generatedFolder.relativize(dir);
- if (dir.startsWith(generatedFolder)) { // don't copy logs
- Path resolvedPath = dataFolderPath.resolve(relativePath);
- LOGGER.info("> Creating sub-folder {}", resolvedPath);
- Files.createDirectories(resolvedPath);
- }
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
- LOGGER.info("> Deleting folder {}", dir);
- Files.delete(dir);
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- Path relativePath = generatedFolder.relativize(file);
- if (file.startsWith(generatedFolder)) { // don't copy logs
- Path resolvedPath = dataFolderPath.resolve(relativePath);
- LOGGER.info("> Moving {}", relativePath);
- Files.move(file, resolvedPath);
- } else {
- LOGGER.info("> Deleting {}", relativePath);
- Files.delete(file);
- }
- return FileVisitResult.CONTINUE;
- }
- });
- }
-
- private static void runDataGenerator(File serverJar) throws IOException {
- final String javaExecutable = System.getProperty("java.home") + "/bin/java";
- ProcessBuilder dataGenerator = new ProcessBuilder(javaExecutable, "-cp", serverJar.getName(), "net.minecraft.data.Main", "--all", "--server", "--dev");
- dataGenerator.directory(TMP_FOLDER);
- LOGGER.info("Now running data generator with options '--dev', '--server', '--all'");
- LOGGER.info("Executing: {}", String.join(StringUtils.SPACE, dataGenerator.command()));
- LOGGER.info("Minestom will now wait for it to finish, here's its output:");
- LOGGER.info("");
- Process dataGeneratorProcess = dataGenerator.start();
- new BufferedReader(
- new InputStreamReader(dataGeneratorProcess.getInputStream())
- ).lines().forEach(LOGGER::info);
- new BufferedReader(
- new InputStreamReader(dataGeneratorProcess.getErrorStream())
- ).lines().forEach(LOGGER::error);
- LOGGER.info("");
-
- try {
- int resultCode = dataGeneratorProcess.waitFor();
- if (resultCode != 0) {
- throw new IOException("Data generator finished with non-zero return code " + resultCode + " verify that you have 'java' cli");
- }
- } catch (InterruptedException e) {
- throw new IOException("Data generator was interrupted.", e);
- }
- }
-
- private static File downloadServerJar(String version) throws IOException {
- // Mojang's version manifest is located at https://launchermeta.mojang.com/mc/game/version_manifest.json
- // If we query this (it's a json object), we can then search for the id we want.
- InputStream versionManifestStream = new URL("https://launchermeta.mojang.com/mc/game/version_manifest.json").openStream();
- LOGGER.debug("Successfully queried Mojang's version_manifest.json.");
-
- JsonObject versionManifestJson = GSON.fromJson(new InputStreamReader(versionManifestStream), JsonObject.class);
- LOGGER.debug("Successfully read Mojang's version_manifest.json into a json object.");
-
- JsonArray versionArray = versionManifestJson.getAsJsonArray("versions");
- LOGGER.debug("Iterating over the version manifest to find a version with the id {}.", version);
-
- JsonObject versionEntry = null;
- for (JsonElement element : versionArray) {
- if (element.isJsonObject()) {
- JsonObject entry = element.getAsJsonObject();
- if (entry.get("id").getAsString().equals(version)) {
- LOGGER.debug("Successfully found a version with the id {}.", version);
- versionEntry = entry;
- break;
- }
- }
- }
- if (versionEntry == null) {
- throw new IOException("Could not find " + version + " in Mojang's official list of minecraft versions.");
- }
- // We now have the entry we want and it gives us access to the json file containing the downloads.
- String versionUrl = versionEntry.get("url").getAsString();
- InputStream versionStream = new URL(versionUrl).openStream();
- LOGGER.debug("Successfully queried {}.json.", version);
-
- JsonObject versionJson = GSON.fromJson(new InputStreamReader(versionStream), JsonObject.class);
- LOGGER.debug("Successfully read {}.json into a json object.", version);
-
- // Now we need to navigate to "downloads.client.url" and "downloads.server.url" }
- JsonObject downloadsJson = versionJson.getAsJsonObject("downloads");
-
- // Designated spot if we ever need the client.
-
- // Server
- {
- JsonObject serverJson = downloadsJson.getAsJsonObject("server");
- final String jarURL = serverJson.get("url").getAsString();
- final String sha1 = serverJson.get("sha1").getAsString();
-
- LOGGER.debug("Found all information required to download the server JAR file.");
- LOGGER.debug("Attempting download.");
- return download(version, jarURL, sha1);
- }
- }
-
- private static File download(@NotNull String version, @NotNull String url, @NotNull String sha1Source) throws IOException {
- File target = new File(TMP_FOLDER, "server_" + version + ".jar");
- // Download
- try (FastBufferedInputStream in = new FastBufferedInputStream(new URL(url).openStream())) {
- Files.copy(in, target.toPath(), StandardCopyOption.REPLACE_EXISTING);
- } catch (IOException e) {
- throw new IOException("Failed to download Minecraft server jar.", e);
- }
- // Verify checksum
- try (FileInputStream fis = new FileInputStream(target)) {
- MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
- messageDigest.reset();
- messageDigest.update(fis.readAllBytes());
- byte[] digest = messageDigest.digest();
- StringBuffer sb = new StringBuffer();
- for (byte b : digest) {
- sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
- }
- // This just converts the sha1 back into a readable string.
- String sha1Target = sb.toString();
- if (!sha1Target.equals(sha1Source)) {
- LOGGER.error("The checksum test failed after downloading the Minecraft server jar.");
- LOGGER.error("The expected checksum was: {}.", sha1Source);
- LOGGER.error("The calculated checksum was: {}.", sha1Target);
- throw new IOException("Failed to download Minecraft server jar.");
- }
- } catch (NoSuchAlgorithmException e) {
- LOGGER.error("Failed to find SHA-1 hashing algorithm in Java Environment.");
- throw new IOException("Failed to download Minecraft server jar.");
- }
- return target;
- }
-}
diff --git a/src/test/java/loottables/TestLootTables.java b/src/test/java/loottables/TestLootTables.java
index 45bc350e9..d84a8f714 100644
--- a/src/test/java/loottables/TestLootTables.java
+++ b/src/test/java/loottables/TestLootTables.java
@@ -1,6 +1,5 @@
package loottables;
-import net.minestom.server.MinecraftServer;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataImpl;
import net.minestom.server.gamedata.conditions.SurvivesExplosionCondition;
@@ -11,14 +10,12 @@ import net.minestom.server.gamedata.loottables.entries.ItemType;
import net.minestom.server.gamedata.loottables.tabletypes.BlockType;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
-import net.minestom.server.registry.ResourceGatherer;
import net.minestom.server.utils.NamespaceID;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.FileNotFoundException;
-import java.io.IOException;
import java.io.StringReader;
import java.util.List;
@@ -28,12 +25,6 @@ public class TestLootTables {
@BeforeEach
public void init() {
- try {
- ResourceGatherer.ensureResourcesArePresent(MinecraftServer.VERSION_NAME);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
tableManager = new LootTableManager();
tableManager.registerConditionDeserializer(NamespaceID.from("minecraft:survives_explosion"), new SurvivesExplosionCondition.Deserializer());
tableManager.registerTableType(NamespaceID.from("minecraft:block"), new BlockType());
diff --git a/src/test/java/tags/TestTags.java b/src/test/java/tags/TestTags.java
deleted file mode 100644
index 94da727cb..000000000
--- a/src/test/java/tags/TestTags.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package tags;
-
-import net.minestom.server.gamedata.tags.Tag;
-import net.minestom.server.gamedata.tags.TagManager;
-import net.minestom.server.utils.NamespaceID;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import java.io.FileNotFoundException;
-import java.io.StringReader;
-
-public class TestTags {
-
- private TagManager tags;
-
- @BeforeEach
- public void init() {
- tags = new TagManager();
- }
-
- @Test
- public void testSubTag() throws FileNotFoundException {
- String tag1 = "{\n" +
- "\t\"replace\": false,\n" +
- "\t\"values\": [\n" +
- "\t\t\"minestom:an_item\"\n" +
- "\t]\n" +
- "}";
-
- String tag2 = "{\n" +
- "\t\"replace\": false,\n" +
- "\t\"values\": [\n" +
- "\t\t\"#minestom:test_sub\",\n" +
- "\t\t\"minestom:some_other_item\"\n" +
- "\t]\n" +
- "}";
- Assertions.assertNotEquals(Tag.EMPTY, tags.load(NamespaceID.from("minestom:test_sub"), "any", new StringReader(tag1)));
- Tag loaded = tags.load(NamespaceID.from("minestom:test"), "any", new StringReader(tag2));
- NamespaceID[] values = loaded.getValues().toArray(new NamespaceID[0]);
- Assertions.assertEquals(2, values.length);
- Assertions.assertTrue(loaded.contains(NamespaceID.from("minestom:an_item")));
- Assertions.assertTrue(loaded.contains(NamespaceID.from("minestom:some_other_item")));
- Assertions.assertFalse(loaded.contains(NamespaceID.from("minestom:some_other_item_that_is_not_in_the_tag")));
- }
-
- /**
- * A value of 'true' in 'replace' should replace previous contents
- */
- @Test
- public void testReplacement() throws FileNotFoundException {
- String tag1 = "{\n" +
- "\t\"replace\": false,\n" +
- "\t\"values\": [\n" +
- "\t\t\"minestom:an_item\"\n" +
- "\t]\n" +
- "}";
-
- String tag2 = "{\n" +
- "\t\"replace\": true,\n" +
- "\t\"values\": [\n" +
- "\t\t\"minestom:some_other_item\"\n" +
- "\t]\n" +
- "}";
- Assertions.assertNotEquals(Tag.EMPTY, tags.load(NamespaceID.from("minestom:test"), "any", new StringReader(tag1)));
- Tag loaded = tags.forceLoad(NamespaceID.from("minestom:test"), "any", () -> new StringReader(tag2));
- Assertions.assertNotEquals(Tag.EMPTY, loaded);
- Assertions.assertEquals(1, loaded.getValues().size());
- Assertions.assertTrue(loaded.contains(NamespaceID.from("minestom:some_other_item")));
- Assertions.assertFalse(loaded.contains(NamespaceID.from("minestom:an_item")));
- }
-
- /**
- * A value of 'false' in 'replace' should append to previous contents
- */
- @Test
- public void testAppend() throws FileNotFoundException {
- String tag1 = "{\n" +
- "\t\"replace\": false,\n" +
- "\t\"values\": [\n" +
- "\t\t\"minestom:an_item\"\n" +
- "\t]\n" +
- "}";
-
- String tag2 = "{\n" +
- "\t\"replace\": false,\n" +
- "\t\"values\": [\n" +
- "\t\t\"minestom:some_other_item\"\n" +
- "\t]\n" +
- "}";
- Assertions.assertNotEquals(Tag.EMPTY, tags.load(NamespaceID.from("minestom:test"), "any", new StringReader(tag1)));
- Tag loaded = tags.forceLoad(NamespaceID.from("minestom:test"), "any", () -> new StringReader(tag2));
- Assertions.assertNotEquals(Tag.EMPTY, loaded);
- Assertions.assertEquals(2, loaded.getValues().size());
- Assertions.assertTrue(loaded.contains(NamespaceID.from("minestom:some_other_item")));
- Assertions.assertTrue(loaded.contains(NamespaceID.from("minestom:an_item")));
- }
-
- @AfterEach
- public void cleanup() {
- tags = null;
- }
-}