Added support for trim registries (#128)

* trim_material and trim_pattern registries are now generated, loaded and sent to the clients

* fixed override_armor_materials

* allowing TrimMaterial and TrimPattern to be created dynamically

* cleanup and formatting

(cherry picked from commit 70e4355ca1)
This commit is contained in:
Kil'jaeden 2024-02-03 15:58:21 +03:30 committed by Matt Worzala
parent a14dbf5cdd
commit 12da0c7e4a
14 changed files with 502 additions and 2 deletions

View File

@ -34,6 +34,9 @@ public class Generators {
generator.generate(resource("sounds.json"), "net.minestom.server.sound", "SoundEvent", "SoundEventImpl", "SoundEvents");
generator.generate(resource("custom_statistics.json"), "net.minestom.server.statistic", "StatisticType", "StatisticTypeImpl", "StatisticTypes");
generator.generate(resource("damage_types.json"), "net.minestom.server.entity.damage", "DamageType", "DamageTypeImpl", "DamageTypes");
generator.generate(resource("trim_materials.json"), "net.minestom.server.item.armor", "TrimMaterial", "TrimMaterialImpl", "TrimMaterials");
generator.generate(resource("trim_patterns.json"), "net.minestom.server.item.armor", "TrimPattern", "TrimPatternImpl", "TrimPatterns");
// Generate fluids
new FluidGenerator(resource("fluids.json"), outputFolder).generate();

View File

@ -3,7 +3,7 @@ metadata.format.version = "1.1"
[versions]
# Important dependencies
data = "1.20.4-rv1"
data = "1.20.4-rv2"
adventure = "4.15.0"
kotlin = "1.7.22"
dependencyGetter = "v1.0.1"

View File

@ -0,0 +1,27 @@
package net.minestom.server.item.armor;
/**
* Code autogenerated, do not edit!
*/
@SuppressWarnings("unused")
interface TrimMaterials {
TrimMaterial LAPIS = TrimMaterialImpl.get("minecraft:lapis");
TrimMaterial IRON = TrimMaterialImpl.get("minecraft:iron");
TrimMaterial DIAMOND = TrimMaterialImpl.get("minecraft:diamond");
TrimMaterial AMETHYST = TrimMaterialImpl.get("minecraft:amethyst");
TrimMaterial COPPER = TrimMaterialImpl.get("minecraft:copper");
TrimMaterial QUARTZ = TrimMaterialImpl.get("minecraft:quartz");
TrimMaterial EMERALD = TrimMaterialImpl.get("minecraft:emerald");
TrimMaterial REDSTONE = TrimMaterialImpl.get("minecraft:redstone");
TrimMaterial GOLD = TrimMaterialImpl.get("minecraft:gold");
TrimMaterial NETHERITE = TrimMaterialImpl.get("minecraft:netherite");
}

View File

@ -0,0 +1,39 @@
package net.minestom.server.item.armor;
/**
* Code autogenerated, do not edit!
*/
@SuppressWarnings("unused")
interface TrimPatterns {
TrimPattern TIDE = TrimPatternImpl.get("minecraft:tide");
TrimPattern RIB = TrimPatternImpl.get("minecraft:rib");
TrimPattern HOST = TrimPatternImpl.get("minecraft:host");
TrimPattern SILENCE = TrimPatternImpl.get("minecraft:silence");
TrimPattern WILD = TrimPatternImpl.get("minecraft:wild");
TrimPattern WAYFINDER = TrimPatternImpl.get("minecraft:wayfinder");
TrimPattern DUNE = TrimPatternImpl.get("minecraft:dune");
TrimPattern RAISER = TrimPatternImpl.get("minecraft:raiser");
TrimPattern SNOUT = TrimPatternImpl.get("minecraft:snout");
TrimPattern VEX = TrimPatternImpl.get("minecraft:vex");
TrimPattern SPIRE = TrimPatternImpl.get("minecraft:spire");
TrimPattern SENTRY = TrimPatternImpl.get("minecraft:sentry");
TrimPattern EYE = TrimPatternImpl.get("minecraft:eye");
TrimPattern WARD = TrimPatternImpl.get("minecraft:ward");
TrimPattern COAST = TrimPatternImpl.get("minecraft:coast");
TrimPattern SHAPER = TrimPatternImpl.get("minecraft:shaper");
}

View File

@ -10,6 +10,7 @@ import net.minestom.server.extensions.ExtensionManager;
import net.minestom.server.gamedata.tags.TagManager;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.item.armor.TrimManager;
import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.monitoring.BenchmarkManager;
import net.minestom.server.network.ConnectionManager;
@ -262,6 +263,10 @@ public final class MinecraftServer {
return serverProcess.tag();
}
public static TrimManager getTrimManager() {
return serverProcess.trim();
}
public static Server getServer() {
return serverProcess.server();
}

View File

@ -11,6 +11,7 @@ import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.rule.BlockPlacementRule;
import net.minestom.server.item.armor.TrimManager;
import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.monitoring.BenchmarkManager;
import net.minestom.server.network.ConnectionManager;
@ -107,6 +108,8 @@ public interface ServerProcess extends Snapshotable {
*/
@NotNull TagManager tag();
@NotNull TrimManager trim();
/**
* Handles all thrown exceptions from the server.
*/

View File

@ -15,6 +15,7 @@ import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.item.armor.TrimManager;
import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.monitoring.BenchmarkManager;
import net.minestom.server.monitoring.TickMonitor;
@ -67,6 +68,7 @@ final class ServerProcessImpl implements ServerProcess {
private final AdvancementManager advancement;
private final BossBarManager bossBar;
private final TagManager tag;
private final TrimManager trim;
private final Server server;
private final ThreadDispatcher<Chunk> dispatcher;
@ -94,6 +96,7 @@ final class ServerProcessImpl implements ServerProcess {
this.advancement = new AdvancementManager();
this.bossBar = new BossBarManager();
this.tag = new TagManager();
this.trim = new TrimManager();
this.server = new Server(packetProcessor);
this.dispatcher = ThreadDispatcher.singleThread();
@ -175,6 +178,11 @@ final class ServerProcessImpl implements ServerProcess {
return tag;
}
@Override
public @NotNull TrimManager trim() {
return trim;
}
@Override
public @NotNull ExceptionManager exception() {
return exception;

View File

@ -0,0 +1,107 @@
package net.minestom.server.item.armor;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class TrimManager {
private final Set<TrimMaterial> trimMaterials;
private final Set<TrimPattern> trimPatterns;
private NBTCompound trimMaterialCache = null;
private NBTCompound trimPatternCache = null;
public TrimManager() {
this.trimMaterials = new HashSet<>();
this.trimPatterns = new HashSet<>();
}
public @Nullable TrimMaterial fromIngredient(Material ingredient) {
return this.trimMaterials.stream().filter(trimMaterial -> trimMaterial.ingredient().equals(ingredient)).findFirst().orElse(null);
}
public @Nullable TrimPattern fromTemplate(Material material) {
return this.trimPatterns.stream().filter(trimPattern -> trimPattern.template().equals(material)).findFirst().orElse(null);
}
public NBTCompound getTrimMaterialNBT() {
if (trimMaterialCache == null) {
var trimMaterials = this.trimMaterials.stream()
.map((trimMaterial) -> NBT.Compound(Map.of(
"id", NBT.Int(trimMaterial.id()),
"name", NBT.String(trimMaterial.name()),
"element", trimMaterial.asNBT()
)))
.toList();
trimMaterialCache = NBT.Compound(Map.of(
"type", NBT.String("minecraft:trim_material"),
"value", NBT.List(NBTType.TAG_Compound, trimMaterials)
));
}
return trimMaterialCache;
}
public NBTCompound getTrimPatternNBT() {
if (trimPatternCache == null) {
var trimPatterns = this.trimPatterns.stream()
.map((trimPattern) -> NBT.Compound(Map.of(
"id", NBT.Int(trimPattern.id()),
"name", NBT.String(trimPattern.name()),
"element", trimPattern.asNBT()
)))
.toList();
trimPatternCache = NBT.Compound(Map.of(
"type", NBT.String("minecraft:trim_pattern"),
"value", NBT.List(NBTType.TAG_Compound, trimPatterns)
));
}
return trimPatternCache;
}
public Set<TrimMaterial> getTrimMaterials() {
return Set.copyOf(this.trimMaterials);
}
public Set<TrimPattern> getTrimPatterns() {
return Set.copyOf(trimPatterns);
}
public void addDefaultTrimMaterials() {
this.trimMaterialCache = null;
this.trimMaterials.addAll(TrimMaterial.values());
}
public void addDefaultTrimPatterns() {
this.trimMaterialCache = null;
this.trimPatterns.addAll(TrimPattern.values());
}
public boolean addTrimMaterial(TrimMaterial trimMaterial) {
this.trimMaterialCache = null;
return this.trimMaterials.add(trimMaterial);
}
public boolean removeTrimMaterial(TrimMaterial trimMaterial) {
this.trimMaterialCache = null;
return this.trimMaterials.remove(trimMaterial);
}
public boolean addTrimPattern(TrimPattern trimPattern) {
this.trimMaterialCache = null;
return this.trimPatterns.add(trimPattern);
}
public boolean removeTrimPattern(TrimPattern trimPattern) {
this.trimMaterialCache = null;
return this.trimPatterns.remove(trimPattern);
}
}

View File

@ -0,0 +1,89 @@
package net.minestom.server.item.armor;
import net.kyori.adventure.text.Component;
import net.minestom.server.item.Material;
import net.minestom.server.registry.ProtocolObject;
import net.minestom.server.registry.Registry;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection;
import java.util.Map;
public interface TrimMaterial extends ProtocolObject {
static @NotNull TrimMaterial create(@NotNull NamespaceID namespace,
@NotNull String assetName,
@NotNull Material ingredient,
float itemModelIndex,
@NotNull Map<String, String> overrideArmorMaterials,
@NotNull Component description,
Registry.Properties custom) {
return new TrimMaterialImpl(
new Registry.TrimMaterialEntry(
namespace,
assetName,
ingredient,
itemModelIndex,
overrideArmorMaterials,
description,
custom
)
);
}
static @NotNull TrimMaterial create(@NotNull NamespaceID namespace,
@NotNull String assetName,
@NotNull Material ingredient,
float itemModelIndex,
@NotNull Map<String, String> overrideArmorMaterials,
@NotNull Component description) {
return new TrimMaterialImpl(
new Registry.TrimMaterialEntry(
namespace,
assetName,
ingredient,
itemModelIndex,
overrideArmorMaterials,
description,
null
)
);
}
static Collection<TrimMaterial> values() {
return TrimMaterialImpl.values();
}
@Contract(pure = true)
@NotNull Registry.TrimMaterialEntry registry();
@Override
default @NotNull NamespaceID namespace() {
return registry().namespace();
}
default @NotNull String assetName() {
return registry().assetName();
}
default @NotNull Material ingredient() {
return registry().ingredient();
}
default float itemModelIndex() {
return registry().itemModelIndex();
}
default @NotNull Map<String, String> overrideArmorMaterials() {
return registry().overrideArmorMaterials();
}
default @NotNull Component description() {
return registry().description();
}
NBTCompound asNBT();
}

View File

@ -0,0 +1,49 @@
package net.minestom.server.item.armor;
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
import net.minestom.server.registry.Registry;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
record TrimMaterialImpl(Registry.TrimMaterialEntry registry, int id) implements TrimMaterial {
static final AtomicInteger i = new AtomicInteger();
private static final Registry.Container<TrimMaterial> CONTAINER;
static {
CONTAINER = Registry.createContainer(Registry.Resource.TRIM_MATERIALS,
(namespace, properties) -> new TrimMaterialImpl(Registry.trimMaterial(namespace, properties)));
}
public TrimMaterialImpl(Registry.TrimMaterialEntry registry) {
this(registry, i.getAndIncrement());
}
public static TrimMaterial get(String namespace) {
return CONTAINER.get(namespace);
}
static Collection<TrimMaterial> values() {
return CONTAINER.values();
}
public NBTCompound asNBT() {
return NBT.Compound(nbt -> {
nbt.setString("asset_name", assetName());
nbt.setString("ingredient", ingredient().namespace().asString());
nbt.setFloat("item_model_index", itemModelIndex());
nbt.set("override_armor_materials", NBT.Compound(overrideArmorMaterials().entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> NBT.String(entry.getValue())
))
));
nbt.set("description", NbtComponentSerializer.nbt().serialize(description()));
});
}
}

View File

@ -0,0 +1,66 @@
package net.minestom.server.item.armor;
import net.kyori.adventure.text.Component;
import net.minestom.server.item.Material;
import net.minestom.server.registry.ProtocolObject;
import net.minestom.server.registry.Registry;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection;
public interface TrimPattern extends ProtocolObject {
static @NotNull TrimPattern create(@NotNull NamespaceID namespace,
@NotNull NamespaceID assetID,
@NotNull Material template,
@NotNull Component description,
boolean decal,
@NotNull Registry.Properties custom) {
return new TrimPatternImpl(
new Registry.TrimPatternEntry(namespace, assetID, template, description, decal, custom)
);
}
static @NotNull TrimPattern create(@NotNull NamespaceID namespace,
@NotNull NamespaceID assetID,
@NotNull Material template,
@NotNull Component description,
boolean decal) {
return new TrimPatternImpl(
new Registry.TrimPatternEntry(namespace, assetID, template, description, decal, null)
);
}
static Collection<TrimPattern> values() {
return TrimPatternImpl.values();
}
@Contract(pure = true)
@NotNull Registry.TrimPatternEntry registry();
@Override
default @NotNull NamespaceID namespace() {
return registry().namespace();
}
default @NotNull NamespaceID assetID() {
return registry().assetID();
}
default @NotNull Material template() {
return registry().template();
}
default @NotNull Component description() {
return registry().description();
}
default boolean decal() {
return registry().decal();
}
NBTCompound asNBT();
}

View File

@ -0,0 +1,41 @@
package net.minestom.server.item.armor;
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
import net.minestom.server.registry.Registry;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
record TrimPatternImpl(Registry.TrimPatternEntry registry, int id) implements TrimPattern {
static final AtomicInteger i = new AtomicInteger();
private static final Registry.Container<TrimPattern> CONTAINER;
static {
CONTAINER = Registry.createContainer(Registry.Resource.TRIM_PATTERNS,
(namespace, properties) -> new TrimPatternImpl(Registry.trimPattern(namespace, properties)));
}
public TrimPatternImpl(Registry.TrimPatternEntry registry) {
this(registry, i.getAndIncrement());
}
public static TrimPattern get(String namespace) {
return CONTAINER.get(namespace);
}
static Collection<TrimPattern> values() {
return CONTAINER.values();
}
public NBTCompound asNBT() {
return NBT.Compound(nbt -> {
nbt.setString("asset_id", assetID().asString());
nbt.setString("template_item", template().namespace().asString());
nbt.set("description", NbtComponentSerializer.nbt().serialize(description()));
nbt.setByte("decal", (byte) (decal() ? 1 : 0));
});
}
}

View File

@ -278,6 +278,8 @@ public final class ConnectionManager {
registry.put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT());
registry.put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT());
registry.put("minecraft:damage_type", DamageType.getNBT());
registry.put("minecraft:trim_material", MinecraftServer.getTrimManager().getTrimMaterialNBT());
registry.put("minecraft:trim_pattern", MinecraftServer.getTrimManager().getTrimPatternNBT());
player.sendPacket(new RegistryDataPacket(NBT.Compound(registry)));
player.sendPacket(TagsPacket.DEFAULT_TAGS);

View File

@ -2,6 +2,8 @@ package net.minestom.server.registry;
import com.google.gson.ToNumberPolicy;
import com.google.gson.stream.JsonReader;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.json.JSONComponentSerializer;
import net.minestom.server.MinecraftServer;
import net.minestom.server.collision.BoundingBox;
import net.minestom.server.collision.CollisionUtils;
@ -21,7 +23,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* Handles registry data, used by {@link ProtocolObject} implementations and is strictly internal.
@ -58,6 +62,16 @@ public final class Registry {
return new DamageTypeEntry(namespace, main, null);
}
@ApiStatus.Internal
public static TrimMaterialEntry trimMaterial(String namespace, @NotNull Properties main) {
return new TrimMaterialEntry(namespace, main, null);
}
@ApiStatus.Internal
public static TrimPatternEntry trimPattern(String namespace, @NotNull Properties main) {
return new TrimPatternEntry(namespace, main, null);
}
@ApiStatus.Internal
public static Map<String, Map<String, Object>> load(Resource resource) {
Map<String, Map<String, Object>> map = new HashMap<>();
@ -148,7 +162,8 @@ public final class Registry {
POTION_TYPES("potions.json"),
PARTICLES("particles.json"),
DAMAGE_TYPES("damage_types.json"),
TRIM_MATERIALS("trim_materials.json"),
TRIM_PATTERNS("trim_patterns.json"),
BLOCK_TAGS("tags/block_tags.json"),
ENTITY_TYPE_TAGS("tags/entity_type_tags.json"),
FLUID_TAGS("tags/fluid_tags.json"),
@ -430,6 +445,44 @@ public final class Registry {
custom);
}
}
public record TrimMaterialEntry(@NotNull NamespaceID namespace,
@NotNull String assetName,
@NotNull Material ingredient,
float itemModelIndex,
@NotNull Map<String,String> overrideArmorMaterials,
@NotNull Component description,
Properties custom) implements Entry {
public TrimMaterialEntry(@NotNull String namespace, @NotNull Properties main, Properties custom) {
this(
NamespaceID.from(namespace),
main.getString("asset_name"),
Objects.requireNonNull(Material.fromNamespaceId(main.getString("ingredient"))),
(float) main.getDouble("item_model_index"),
Objects.requireNonNullElse(main.section("override_armor_materials"),new PropertiesMap(Map.of()))
.asMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> (String) entry.getValue())),
JSONComponentSerializer.json().deserialize(main.section("description").toString()),
custom
);
}
}
public record TrimPatternEntry(@NotNull NamespaceID namespace,
@NotNull NamespaceID assetID,
@NotNull Material template,
@NotNull Component description,
boolean decal,
Properties custom) implements Entry {
public TrimPatternEntry(@NotNull String namespace, @NotNull Properties main, Properties custom) {
this(
NamespaceID.from(namespace),
NamespaceID.from(main.getString("asset_id")),
Objects.requireNonNull(Material.fromNamespaceId(main.getString("template_item"))),
JSONComponentSerializer.json().deserialize(main.section("description").toString()),
main.getBoolean("decal"),
custom
);
}
}
public record EnchantmentEntry(NamespaceID namespace, int id,
String translationKey,
@ -556,6 +609,14 @@ public final class Registry {
//noinspection unchecked
return (T) map.get(name);
}
@Override
public String toString() {
AtomicReference<String> string = new AtomicReference<>("{ ");
this.map.forEach((s, object) -> string.set(string.get() + " , " + "\"" + s + "\"" + " : " + "\"" + object.toString() + "\""));
return string.updateAndGet(s -> s.replaceFirst(" , ","") + "}");
}
}
public interface Properties extends Iterable<Map.Entry<String, Object>> {