feat: new packets, new registries except stubbed out enchantments, other minor changes

This commit is contained in:
mworzala 2024-05-30 20:13:46 -04:00 committed by Matt Worzala
parent e4bec393dc
commit 141a251c1b
44 changed files with 1204 additions and 443 deletions

View File

@ -8,6 +8,7 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Modifier;
import java.io.File;
import java.io.IOException;
@ -90,10 +91,13 @@ public class CodeGenerator {
// Use data
json.keySet().forEach(namespace -> {
final String constantName = namespace
String constantName = namespace
.replace("minecraft:", "")
.replace(".", "_")
.toUpperCase(Locale.ROOT);
if (!SourceVersion.isName(constantName)) {
constantName = "_" + constantName;
}
blockConstantsClass.addField(
FieldSpec.builder(typedRegistryKeyClass, constantName)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)

View File

@ -0,0 +1,82 @@
package net.minestom.codegen;
import com.google.gson.JsonObject;
import com.squareup.javapoet.*;
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;
public class ConstantsGenerator extends MinestomCodeGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(ConstantsGenerator.class);
private final InputStream constantsFile;
private final File outputFolder;
public ConstantsGenerator(@Nullable InputStream constantsFile, @NotNull File outputFolder) {
this.constantsFile = constantsFile;
this.outputFolder = outputFolder;
}
@Override
public void generate() {
if (constantsFile == null) {
LOGGER.error("Failed to find constants.json.");
LOGGER.error("Stopped code generation for recipe 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
JsonObject constants = GSON.fromJson(new InputStreamReader(constantsFile), JsonObject.class);
ClassName minecraftConstantsCN = ClassName.get("net.minestom.server", "MinecraftConstants");
TypeSpec.Builder constantsInterface = TypeSpec.interfaceBuilder(minecraftConstantsCN)
.addJavadoc("AUTOGENERATED by " + getClass().getSimpleName());
constantsInterface.addField(FieldSpec.builder(String.class, "VERSION_NAME")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$S", constants.get("name").getAsString())
.build()
);
constantsInterface.addField(FieldSpec.builder(TypeName.INT, "PROTOCOL_VERSION")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$L", constants.get("protocol").getAsInt())
.build()
);
constantsInterface.addField(FieldSpec.builder(TypeName.INT, "DATA_VERSION")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$L", constants.get("world").getAsInt())
.build()
);
constantsInterface.addField(FieldSpec.builder(TypeName.INT, "RESOURCE_PACK_VERSION")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$L", constants.get("resourcepack").getAsInt())
.build()
);
constantsInterface.addField(FieldSpec.builder(TypeName.INT, "DATA_PACK_VERSION")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$L", constants.get("datapack").getAsInt())
.build()
);
// Write files to outputFolder
writeFiles(
List.of(
JavaFile.builder("net.minestom.server", constantsInterface.build())
.indent(" ")
.skipJavaLangImports(true)
.build()
),
outputFolder
);
}
}

View File

@ -24,6 +24,7 @@ public class Generators {
new DyeColorGenerator(resource("dye_colors.json"), outputFolder).generate();
new RecipeTypeGenerator(resource("recipe_types.json"), outputFolder).generate();
new ParticleGenerator(resource("particles.json"), outputFolder).generate();
new ConstantsGenerator(resource("constants.json"), outputFolder).generate();
var generator = new CodeGenerator(outputFolder);
@ -31,7 +32,6 @@ public class Generators {
generator.generate(resource("blocks.json"), "net.minestom.server.instance.block", "Block", "BlockImpl", "Blocks");
generator.generate(resource("items.json"), "net.minestom.server.item", "Material", "MaterialImpl", "Materials");
generator.generate(resource("entities.json"), "net.minestom.server.entity", "EntityType", "EntityTypeImpl", "EntityTypes");
generator.generate(resource("enchantments.json"), "net.minestom.server.item.enchant", "Enchantment", "EnchantmentImpl", "Enchantments");
generator.generate(resource("potion_effects.json"), "net.minestom.server.potion", "PotionEffect", "PotionEffectImpl", "PotionEffects");
generator.generate(resource("potions.json"), "net.minestom.server.potion", "PotionType", "PotionTypeImpl", "PotionTypes");
generator.generate(resource("sounds.json"), "net.minestom.server.sound", "SoundEvent", "BuiltinSoundEvent", "SoundEvents");
@ -47,6 +47,9 @@ public class Generators {
generator.generateKeys(resource("trim_patterns.json"), "net.minestom.server.item.armor", "TrimPattern", "TrimPatterns");
generator.generateKeys(resource("banner_patterns.json"), "net.minestom.server.instance.block.banner", "BannerPattern", "BannerPatterns");
generator.generateKeys(resource("wolf_variants.json"), "net.minestom.server.entity.metadata.animal.tameable", "WolfMeta.Variant", "WolfVariants");
generator.generateKeys(resource("enchantments.json"), "net.minestom.server.item.enchant", "Enchantment", "Enchantments");
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();

View File

@ -39,6 +39,8 @@ import net.minestom.server.item.component.ItemBlockState;
import net.minestom.server.item.component.PotionContents;
import net.minestom.server.monitoring.BenchmarkManager;
import net.minestom.server.monitoring.TickMonitor;
import net.minestom.server.network.packet.server.common.CustomReportDetailsPacket;
import net.minestom.server.network.packet.server.common.ServerLinksPacket;
import net.minestom.server.potion.CustomPotionEffect;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.sound.SoundEvent;
@ -114,6 +116,16 @@ public class PlayerInit {
.build();
player.getInventory().addItemStack(itemStack);
player.sendPacket(new CustomReportDetailsPacket(Map.of(
"hello", "world"
)));
player.sendPacket(new ServerLinksPacket(
new ServerLinksPacket.Entry(ServerLinksPacket.KnownLinkType.NEWS, "https://minestom.net"),
new ServerLinksPacket.Entry(ServerLinksPacket.KnownLinkType.BUG_REPORT, "https://minestom.net"),
new ServerLinksPacket.Entry(Component.text("Hello world!"), "https://minestom.net")
));
ItemStack bundle = ItemStack.builder(Material.BUNDLE)
.set(ItemComponent.BUNDLE_CONTENTS, List.of(
ItemStack.of(Material.DIAMOND, 5),
@ -136,6 +148,7 @@ public class PlayerInit {
)))
.build());
if (event.isFirstSpawn()) {
Notification notification = new Notification(
Component.text("Welcome!"),

View File

@ -0,0 +1,16 @@
package net.minestom.server;
/**
* AUTOGENERATED by ConstantsGenerator
*/
interface MinecraftConstants {
String VERSION_NAME = "1.21 Pre-Release 1";
int PROTOCOL_VERSION = 1073742023;
int DATA_VERSION = 3948;
int RESOURCE_PACK_VERSION = 34;
int DATA_PACK_VERSION = 46;
}

View File

@ -19,6 +19,10 @@ interface Attributes {
Attribute PLAYER_BLOCK_INTERACTION_RANGE = AttributeImpl.get("minecraft:player.block_interaction_range");
Attribute GENERIC_BURNING_TIME = AttributeImpl.get("minecraft:generic.burning_time");
Attribute GENERIC_EXPLOSION_KNOCKBACK_RESISTANCE = AttributeImpl.get("minecraft:generic.explosion_knockback_resistance");
Attribute PLAYER_ENTITY_INTERACTION_RANGE = AttributeImpl.get("minecraft:player.entity_interaction_range");
Attribute GENERIC_FALL_DAMAGE_MULTIPLIER = AttributeImpl.get("minecraft:generic.fall_damage_multiplier");
@ -39,13 +43,27 @@ interface Attributes {
Attribute GENERIC_MAX_HEALTH = AttributeImpl.get("minecraft:generic.max_health");
Attribute PLAYER_MINING_EFFICIENCY = AttributeImpl.get("minecraft:player.mining_efficiency");
Attribute GENERIC_MOVEMENT_EFFICIENCY = AttributeImpl.get("minecraft:generic.movement_efficiency");
Attribute GENERIC_MOVEMENT_SPEED = AttributeImpl.get("minecraft:generic.movement_speed");
Attribute GENERIC_OXYGEN_BONUS = AttributeImpl.get("minecraft:generic.oxygen_bonus");
Attribute GENERIC_SAFE_FALL_DISTANCE = AttributeImpl.get("minecraft:generic.safe_fall_distance");
Attribute GENERIC_SCALE = AttributeImpl.get("minecraft:generic.scale");
Attribute PLAYER_SNEAKING_SPEED = AttributeImpl.get("minecraft:player.sneaking_speed");
Attribute ZOMBIE_SPAWN_REINFORCEMENTS = AttributeImpl.get("minecraft:zombie.spawn_reinforcements");
Attribute GENERIC_STEP_HEIGHT = AttributeImpl.get("minecraft:generic.step_height");
Attribute PLAYER_SUBMERGED_MINING_SPEED = AttributeImpl.get("minecraft:player.submerged_mining_speed");
Attribute PLAYER_SWEEPING_DAMAGE_RATIO = AttributeImpl.get("minecraft:player.sweeping_damage_ratio");
Attribute GENERIC_WATER_MOVEMENT_EFFICIENCY = AttributeImpl.get("minecraft:generic.water_movement_efficiency");
}

View File

@ -25,6 +25,8 @@ interface DamageTypes {
DynamicRegistry.Key<DamageType> MOB_PROJECTILE = DynamicRegistry.Key.of("minecraft:mob_projectile");
DynamicRegistry.Key<DamageType> CAMPFIRE = DynamicRegistry.Key.of("minecraft:campfire");
DynamicRegistry.Key<DamageType> THROWN = DynamicRegistry.Key.of("minecraft:thrown");
DynamicRegistry.Key<DamageType> FALLING_STALACTITE = DynamicRegistry.Key.of("minecraft:falling_stalactite");
@ -33,6 +35,8 @@ interface DamageTypes {
DynamicRegistry.Key<DamageType> FALLING_BLOCK = DynamicRegistry.Key.of("minecraft:falling_block");
DynamicRegistry.Key<DamageType> WIND_CHARGE = DynamicRegistry.Key.of("minecraft:wind_charge");
DynamicRegistry.Key<DamageType> PLAYER_EXPLOSION = DynamicRegistry.Key.of("minecraft:player_explosion");
DynamicRegistry.Key<DamageType> SPIT = DynamicRegistry.Key.of("minecraft:spit");

View File

@ -0,0 +1,109 @@
package net.minestom.server.entity.metadata.other;
import net.minestom.server.registry.DynamicRegistry;
/**
* Code autogenerated, do not edit!
*/
@SuppressWarnings("unused")
interface PaintingVariants {
DynamicRegistry.Key<PaintingMeta.Variant> BOUQUET = DynamicRegistry.Key.of("minecraft:bouquet");
DynamicRegistry.Key<PaintingMeta.Variant> WITHER = DynamicRegistry.Key.of("minecraft:wither");
DynamicRegistry.Key<PaintingMeta.Variant> ALBAN = DynamicRegistry.Key.of("minecraft:alban");
DynamicRegistry.Key<PaintingMeta.Variant> UNPACKED = DynamicRegistry.Key.of("minecraft:unpacked");
DynamicRegistry.Key<PaintingMeta.Variant> AZTEC = DynamicRegistry.Key.of("minecraft:aztec");
DynamicRegistry.Key<PaintingMeta.Variant> MATCH = DynamicRegistry.Key.of("minecraft:match");
DynamicRegistry.Key<PaintingMeta.Variant> FINDING = DynamicRegistry.Key.of("minecraft:finding");
DynamicRegistry.Key<PaintingMeta.Variant> BAROQUE = DynamicRegistry.Key.of("minecraft:baroque");
DynamicRegistry.Key<PaintingMeta.Variant> ENDBOSS = DynamicRegistry.Key.of("minecraft:endboss");
DynamicRegistry.Key<PaintingMeta.Variant> ORB = DynamicRegistry.Key.of("minecraft:orb");
DynamicRegistry.Key<PaintingMeta.Variant> AZTEC2 = DynamicRegistry.Key.of("minecraft:aztec2");
DynamicRegistry.Key<PaintingMeta.Variant> SUNFLOWERS = DynamicRegistry.Key.of("minecraft:sunflowers");
DynamicRegistry.Key<PaintingMeta.Variant> CHANGING = DynamicRegistry.Key.of("minecraft:changing");
DynamicRegistry.Key<PaintingMeta.Variant> WASTELAND = DynamicRegistry.Key.of("minecraft:wasteland");
DynamicRegistry.Key<PaintingMeta.Variant> DONKEY_KONG = DynamicRegistry.Key.of("minecraft:donkey_kong");
DynamicRegistry.Key<PaintingMeta.Variant> BUST = DynamicRegistry.Key.of("minecraft:bust");
DynamicRegistry.Key<PaintingMeta.Variant> POOL = DynamicRegistry.Key.of("minecraft:pool");
DynamicRegistry.Key<PaintingMeta.Variant> PIGSCENE = DynamicRegistry.Key.of("minecraft:pigscene");
DynamicRegistry.Key<PaintingMeta.Variant> BURNING_SKULL = DynamicRegistry.Key.of("minecraft:burning_skull");
DynamicRegistry.Key<PaintingMeta.Variant> FIRE = DynamicRegistry.Key.of("minecraft:fire");
DynamicRegistry.Key<PaintingMeta.Variant> SEA = DynamicRegistry.Key.of("minecraft:sea");
DynamicRegistry.Key<PaintingMeta.Variant> SUNSET = DynamicRegistry.Key.of("minecraft:sunset");
DynamicRegistry.Key<PaintingMeta.Variant> POND = DynamicRegistry.Key.of("minecraft:pond");
DynamicRegistry.Key<PaintingMeta.Variant> HUMBLE = DynamicRegistry.Key.of("minecraft:humble");
DynamicRegistry.Key<PaintingMeta.Variant> TIDES = DynamicRegistry.Key.of("minecraft:tides");
DynamicRegistry.Key<PaintingMeta.Variant> PRAIRIE_RIDE = DynamicRegistry.Key.of("minecraft:prairie_ride");
DynamicRegistry.Key<PaintingMeta.Variant> FERN = DynamicRegistry.Key.of("minecraft:fern");
DynamicRegistry.Key<PaintingMeta.Variant> PASSAGE = DynamicRegistry.Key.of("minecraft:passage");
DynamicRegistry.Key<PaintingMeta.Variant> LOWMIST = DynamicRegistry.Key.of("minecraft:lowmist");
DynamicRegistry.Key<PaintingMeta.Variant> COURBET = DynamicRegistry.Key.of("minecraft:courbet");
DynamicRegistry.Key<PaintingMeta.Variant> WANDERER = DynamicRegistry.Key.of("minecraft:wanderer");
DynamicRegistry.Key<PaintingMeta.Variant> BACKYARD = DynamicRegistry.Key.of("minecraft:backyard");
DynamicRegistry.Key<PaintingMeta.Variant> EARTH = DynamicRegistry.Key.of("minecraft:earth");
DynamicRegistry.Key<PaintingMeta.Variant> SKULL_AND_ROSES = DynamicRegistry.Key.of("minecraft:skull_and_roses");
DynamicRegistry.Key<PaintingMeta.Variant> CAVEBIRD = DynamicRegistry.Key.of("minecraft:cavebird");
DynamicRegistry.Key<PaintingMeta.Variant> FIGHTERS = DynamicRegistry.Key.of("minecraft:fighters");
DynamicRegistry.Key<PaintingMeta.Variant> COTAN = DynamicRegistry.Key.of("minecraft:cotan");
DynamicRegistry.Key<PaintingMeta.Variant> CREEBET = DynamicRegistry.Key.of("minecraft:creebet");
DynamicRegistry.Key<PaintingMeta.Variant> OWLEMONS = DynamicRegistry.Key.of("minecraft:owlemons");
DynamicRegistry.Key<PaintingMeta.Variant> GRAHAM = DynamicRegistry.Key.of("minecraft:graham");
DynamicRegistry.Key<PaintingMeta.Variant> MEDITATIVE = DynamicRegistry.Key.of("minecraft:meditative");
DynamicRegistry.Key<PaintingMeta.Variant> KEBAB = DynamicRegistry.Key.of("minecraft:kebab");
DynamicRegistry.Key<PaintingMeta.Variant> STAGE = DynamicRegistry.Key.of("minecraft:stage");
DynamicRegistry.Key<PaintingMeta.Variant> BOMB = DynamicRegistry.Key.of("minecraft:bomb");
DynamicRegistry.Key<PaintingMeta.Variant> PLANT = DynamicRegistry.Key.of("minecraft:plant");
DynamicRegistry.Key<PaintingMeta.Variant> WATER = DynamicRegistry.Key.of("minecraft:water");
DynamicRegistry.Key<PaintingMeta.Variant> POINTER = DynamicRegistry.Key.of("minecraft:pointer");
DynamicRegistry.Key<PaintingMeta.Variant> SKELETON = DynamicRegistry.Key.of("minecraft:skeleton");
DynamicRegistry.Key<PaintingMeta.Variant> VOID = DynamicRegistry.Key.of("minecraft:void");
DynamicRegistry.Key<PaintingMeta.Variant> WIND = DynamicRegistry.Key.of("minecraft:wind");
}

View File

@ -13,6 +13,8 @@ interface BannerPatterns {
DynamicRegistry.Key<BannerPattern> STRIPE_RIGHT = DynamicRegistry.Key.of("minecraft:stripe_right");
DynamicRegistry.Key<BannerPattern> FLOW = DynamicRegistry.Key.of("minecraft:flow");
DynamicRegistry.Key<BannerPattern> RHOMBUS = DynamicRegistry.Key.of("minecraft:rhombus");
DynamicRegistry.Key<BannerPattern> TRIANGLES_TOP = DynamicRegistry.Key.of("minecraft:triangles_top");
@ -53,6 +55,8 @@ interface BannerPatterns {
DynamicRegistry.Key<BannerPattern> STRIPE_DOWNRIGHT = DynamicRegistry.Key.of("minecraft:stripe_downright");
DynamicRegistry.Key<BannerPattern> GUSTER = DynamicRegistry.Key.of("minecraft:guster");
DynamicRegistry.Key<BannerPattern> GRADIENT_UP = DynamicRegistry.Key.of("minecraft:gradient_up");
DynamicRegistry.Key<BannerPattern> DIAGONAL_RIGHT = DynamicRegistry.Key.of("minecraft:diagonal_right");

View File

@ -0,0 +1,47 @@
package net.minestom.server.instance.block.jukebox;
import net.minestom.server.registry.DynamicRegistry;
/**
* Code autogenerated, do not edit!
*/
@SuppressWarnings("unused")
interface JukeboxSongs {
DynamicRegistry.Key<JukeboxSong> PRECIPICE = DynamicRegistry.Key.of("minecraft:precipice");
DynamicRegistry.Key<JukeboxSong> STAL = DynamicRegistry.Key.of("minecraft:stal");
DynamicRegistry.Key<JukeboxSong> STRAD = DynamicRegistry.Key.of("minecraft:strad");
DynamicRegistry.Key<JukeboxSong> CREATOR_MUSIC_BOX = DynamicRegistry.Key.of("minecraft:creator_music_box");
DynamicRegistry.Key<JukeboxSong> _13 = DynamicRegistry.Key.of("minecraft:13");
DynamicRegistry.Key<JukeboxSong> RELIC = DynamicRegistry.Key.of("minecraft:relic");
DynamicRegistry.Key<JukeboxSong> FAR = DynamicRegistry.Key.of("minecraft:far");
DynamicRegistry.Key<JukeboxSong> BLOCKS = DynamicRegistry.Key.of("minecraft:blocks");
DynamicRegistry.Key<JukeboxSong> _5 = DynamicRegistry.Key.of("minecraft:5");
DynamicRegistry.Key<JukeboxSong> OTHERSIDE = DynamicRegistry.Key.of("minecraft:otherside");
DynamicRegistry.Key<JukeboxSong> MELLOHI = DynamicRegistry.Key.of("minecraft:mellohi");
DynamicRegistry.Key<JukeboxSong> MALL = DynamicRegistry.Key.of("minecraft:mall");
DynamicRegistry.Key<JukeboxSong> CHIRP = DynamicRegistry.Key.of("minecraft:chirp");
DynamicRegistry.Key<JukeboxSong> CREATOR = DynamicRegistry.Key.of("minecraft:creator");
DynamicRegistry.Key<JukeboxSong> PIGSTEP = DynamicRegistry.Key.of("minecraft:pigstep");
DynamicRegistry.Key<JukeboxSong> WARD = DynamicRegistry.Key.of("minecraft:ward");
DynamicRegistry.Key<JukeboxSong> CAT = DynamicRegistry.Key.of("minecraft:cat");
DynamicRegistry.Key<JukeboxSong> WAIT = DynamicRegistry.Key.of("minecraft:wait");
DynamicRegistry.Key<JukeboxSong> _11 = DynamicRegistry.Key.of("minecraft:11");
}

View File

@ -1603,6 +1603,8 @@ interface Materials {
Material FLINT_AND_STEEL = MaterialImpl.get("minecraft:flint_and_steel");
Material BOWL = MaterialImpl.get("minecraft:bowl");
Material APPLE = MaterialImpl.get("minecraft:apple");
Material BOW = MaterialImpl.get("minecraft:bow");
@ -1701,8 +1703,6 @@ interface Materials {
Material STICK = MaterialImpl.get("minecraft:stick");
Material BOWL = MaterialImpl.get("minecraft:bowl");
Material MUSHROOM_STEW = MaterialImpl.get("minecraft:mushroom_stew");
Material STRING = MaterialImpl.get("minecraft:string");
@ -2349,6 +2349,10 @@ interface Materials {
Material MUSIC_DISC_CHIRP = MaterialImpl.get("minecraft:music_disc_chirp");
Material MUSIC_DISC_CREATOR = MaterialImpl.get("minecraft:music_disc_creator");
Material MUSIC_DISC_CREATOR_MUSIC_BOX = MaterialImpl.get("minecraft:music_disc_creator_music_box");
Material MUSIC_DISC_FAR = MaterialImpl.get("minecraft:music_disc_far");
Material MUSIC_DISC_MALL = MaterialImpl.get("minecraft:music_disc_mall");
@ -2373,6 +2377,8 @@ interface Materials {
Material MUSIC_DISC_PIGSTEP = MaterialImpl.get("minecraft:music_disc_pigstep");
Material MUSIC_DISC_PRECIPICE = MaterialImpl.get("minecraft:music_disc_precipice");
Material DISC_FRAGMENT_5 = MaterialImpl.get("minecraft:disc_fragment_5");
Material TRIDENT = MaterialImpl.get("minecraft:trident");

View File

@ -11,6 +11,8 @@ interface TrimPatterns {
DynamicRegistry.Key<TrimPattern> RIB = DynamicRegistry.Key.of("minecraft:rib");
DynamicRegistry.Key<TrimPattern> BOLT = DynamicRegistry.Key.of("minecraft:bolt");
DynamicRegistry.Key<TrimPattern> HOST = DynamicRegistry.Key.of("minecraft:host");
DynamicRegistry.Key<TrimPattern> SILENCE = DynamicRegistry.Key.of("minecraft:silence");
@ -19,6 +21,8 @@ interface TrimPatterns {
DynamicRegistry.Key<TrimPattern> WAYFINDER = DynamicRegistry.Key.of("minecraft:wayfinder");
DynamicRegistry.Key<TrimPattern> FLOW = DynamicRegistry.Key.of("minecraft:flow");
DynamicRegistry.Key<TrimPattern> DUNE = DynamicRegistry.Key.of("minecraft:dune");
DynamicRegistry.Key<TrimPattern> RAISER = DynamicRegistry.Key.of("minecraft:raiser");

View File

@ -1,91 +1,93 @@
package net.minestom.server.item.enchant;
import net.minestom.server.registry.DynamicRegistry;
/**
* Code autogenerated, do not edit!
*/
@SuppressWarnings("unused")
interface Enchantments {
Enchantment PROTECTION = EnchantmentImpl.get("minecraft:protection");
DynamicRegistry.Key<Enchantment> DEPTH_STRIDER = DynamicRegistry.Key.of("minecraft:depth_strider");
Enchantment FIRE_PROTECTION = EnchantmentImpl.get("minecraft:fire_protection");
DynamicRegistry.Key<Enchantment> VANISHING_CURSE = DynamicRegistry.Key.of("minecraft:vanishing_curse");
Enchantment FEATHER_FALLING = EnchantmentImpl.get("minecraft:feather_falling");
DynamicRegistry.Key<Enchantment> EFFICIENCY = DynamicRegistry.Key.of("minecraft:efficiency");
Enchantment BLAST_PROTECTION = EnchantmentImpl.get("minecraft:blast_protection");
DynamicRegistry.Key<Enchantment> IMPALING = DynamicRegistry.Key.of("minecraft:impaling");
Enchantment PROJECTILE_PROTECTION = EnchantmentImpl.get("minecraft:projectile_protection");
DynamicRegistry.Key<Enchantment> WIND_BURST = DynamicRegistry.Key.of("minecraft:wind_burst");
Enchantment RESPIRATION = EnchantmentImpl.get("minecraft:respiration");
DynamicRegistry.Key<Enchantment> BANE_OF_ARTHROPODS = DynamicRegistry.Key.of("minecraft:bane_of_arthropods");
Enchantment AQUA_AFFINITY = EnchantmentImpl.get("minecraft:aqua_affinity");
DynamicRegistry.Key<Enchantment> BINDING_CURSE = DynamicRegistry.Key.of("minecraft:binding_curse");
Enchantment THORNS = EnchantmentImpl.get("minecraft:thorns");
DynamicRegistry.Key<Enchantment> PUNCH = DynamicRegistry.Key.of("minecraft:punch");
Enchantment DEPTH_STRIDER = EnchantmentImpl.get("minecraft:depth_strider");
DynamicRegistry.Key<Enchantment> FLAME = DynamicRegistry.Key.of("minecraft:flame");
Enchantment FROST_WALKER = EnchantmentImpl.get("minecraft:frost_walker");
DynamicRegistry.Key<Enchantment> RIPTIDE = DynamicRegistry.Key.of("minecraft:riptide");
Enchantment BINDING_CURSE = EnchantmentImpl.get("minecraft:binding_curse");
DynamicRegistry.Key<Enchantment> BLAST_PROTECTION = DynamicRegistry.Key.of("minecraft:blast_protection");
Enchantment SOUL_SPEED = EnchantmentImpl.get("minecraft:soul_speed");
DynamicRegistry.Key<Enchantment> FROST_WALKER = DynamicRegistry.Key.of("minecraft:frost_walker");
Enchantment SWIFT_SNEAK = EnchantmentImpl.get("minecraft:swift_sneak");
DynamicRegistry.Key<Enchantment> PROTECTION = DynamicRegistry.Key.of("minecraft:protection");
Enchantment SHARPNESS = EnchantmentImpl.get("minecraft:sharpness");
DynamicRegistry.Key<Enchantment> FIRE_ASPECT = DynamicRegistry.Key.of("minecraft:fire_aspect");
Enchantment SMITE = EnchantmentImpl.get("minecraft:smite");
DynamicRegistry.Key<Enchantment> LOYALTY = DynamicRegistry.Key.of("minecraft:loyalty");
Enchantment BANE_OF_ARTHROPODS = EnchantmentImpl.get("minecraft:bane_of_arthropods");
DynamicRegistry.Key<Enchantment> SWEEPING_EDGE = DynamicRegistry.Key.of("minecraft:sweeping_edge");
Enchantment KNOCKBACK = EnchantmentImpl.get("minecraft:knockback");
DynamicRegistry.Key<Enchantment> FIRE_PROTECTION = DynamicRegistry.Key.of("minecraft:fire_protection");
Enchantment FIRE_ASPECT = EnchantmentImpl.get("minecraft:fire_aspect");
DynamicRegistry.Key<Enchantment> QUICK_CHARGE = DynamicRegistry.Key.of("minecraft:quick_charge");
Enchantment LOOTING = EnchantmentImpl.get("minecraft:looting");
DynamicRegistry.Key<Enchantment> RESPIRATION = DynamicRegistry.Key.of("minecraft:respiration");
Enchantment SWEEPING_EDGE = EnchantmentImpl.get("minecraft:sweeping_edge");
DynamicRegistry.Key<Enchantment> LUCK_OF_THE_SEA = DynamicRegistry.Key.of("minecraft:luck_of_the_sea");
Enchantment EFFICIENCY = EnchantmentImpl.get("minecraft:efficiency");
DynamicRegistry.Key<Enchantment> SOUL_SPEED = DynamicRegistry.Key.of("minecraft:soul_speed");
Enchantment SILK_TOUCH = EnchantmentImpl.get("minecraft:silk_touch");
DynamicRegistry.Key<Enchantment> DENSITY = DynamicRegistry.Key.of("minecraft:density");
Enchantment UNBREAKING = EnchantmentImpl.get("minecraft:unbreaking");
DynamicRegistry.Key<Enchantment> POWER = DynamicRegistry.Key.of("minecraft:power");
Enchantment FORTUNE = EnchantmentImpl.get("minecraft:fortune");
DynamicRegistry.Key<Enchantment> SILK_TOUCH = DynamicRegistry.Key.of("minecraft:silk_touch");
Enchantment POWER = EnchantmentImpl.get("minecraft:power");
DynamicRegistry.Key<Enchantment> CHANNELING = DynamicRegistry.Key.of("minecraft:channeling");
Enchantment PUNCH = EnchantmentImpl.get("minecraft:punch");
DynamicRegistry.Key<Enchantment> FORTUNE = DynamicRegistry.Key.of("minecraft:fortune");
Enchantment FLAME = EnchantmentImpl.get("minecraft:flame");
DynamicRegistry.Key<Enchantment> LOOTING = DynamicRegistry.Key.of("minecraft:looting");
Enchantment INFINITY = EnchantmentImpl.get("minecraft:infinity");
DynamicRegistry.Key<Enchantment> BREACH = DynamicRegistry.Key.of("minecraft:breach");
Enchantment LUCK_OF_THE_SEA = EnchantmentImpl.get("minecraft:luck_of_the_sea");
DynamicRegistry.Key<Enchantment> PIERCING = DynamicRegistry.Key.of("minecraft:piercing");
Enchantment LURE = EnchantmentImpl.get("minecraft:lure");
DynamicRegistry.Key<Enchantment> MENDING = DynamicRegistry.Key.of("minecraft:mending");
Enchantment LOYALTY = EnchantmentImpl.get("minecraft:loyalty");
DynamicRegistry.Key<Enchantment> FEATHER_FALLING = DynamicRegistry.Key.of("minecraft:feather_falling");
Enchantment IMPALING = EnchantmentImpl.get("minecraft:impaling");
DynamicRegistry.Key<Enchantment> SHARPNESS = DynamicRegistry.Key.of("minecraft:sharpness");
Enchantment RIPTIDE = EnchantmentImpl.get("minecraft:riptide");
DynamicRegistry.Key<Enchantment> KNOCKBACK = DynamicRegistry.Key.of("minecraft:knockback");
Enchantment CHANNELING = EnchantmentImpl.get("minecraft:channeling");
DynamicRegistry.Key<Enchantment> SMITE = DynamicRegistry.Key.of("minecraft:smite");
Enchantment MULTISHOT = EnchantmentImpl.get("minecraft:multishot");
DynamicRegistry.Key<Enchantment> INFINITY = DynamicRegistry.Key.of("minecraft:infinity");
Enchantment QUICK_CHARGE = EnchantmentImpl.get("minecraft:quick_charge");
DynamicRegistry.Key<Enchantment> PROJECTILE_PROTECTION = DynamicRegistry.Key.of("minecraft:projectile_protection");
Enchantment PIERCING = EnchantmentImpl.get("minecraft:piercing");
DynamicRegistry.Key<Enchantment> THORNS = DynamicRegistry.Key.of("minecraft:thorns");
Enchantment DENSITY = EnchantmentImpl.get("minecraft:density");
DynamicRegistry.Key<Enchantment> AQUA_AFFINITY = DynamicRegistry.Key.of("minecraft:aqua_affinity");
Enchantment BREACH = EnchantmentImpl.get("minecraft:breach");
DynamicRegistry.Key<Enchantment> LURE = DynamicRegistry.Key.of("minecraft:lure");
Enchantment WIND_BURST = EnchantmentImpl.get("minecraft:wind_burst");
DynamicRegistry.Key<Enchantment> MULTISHOT = DynamicRegistry.Key.of("minecraft:multishot");
Enchantment MENDING = EnchantmentImpl.get("minecraft:mending");
DynamicRegistry.Key<Enchantment> SWIFT_SNEAK = DynamicRegistry.Key.of("minecraft:swift_sneak");
Enchantment VANISHING_CURSE = EnchantmentImpl.get("minecraft:vanishing_curse");
DynamicRegistry.Key<Enchantment> UNBREAKING = DynamicRegistry.Key.of("minecraft:unbreaking");
}

View File

@ -1371,11 +1371,11 @@ interface SoundEvents {
SoundEvent BLOCK_TRIAL_SPAWNER_DETECT_PLAYER = BuiltinSoundEvent.get("minecraft:block.trial_spawner.detect_player");
SoundEvent BLOCK_TRIAL_SPAWNER_CHARGE_ACTIVATE = BuiltinSoundEvent.get("minecraft:block.trial_spawner.charge_activate");
SoundEvent BLOCK_TRIAL_SPAWNER_OMINOUS_ACTIVATE = BuiltinSoundEvent.get("minecraft:block.trial_spawner.ominous_activate");
SoundEvent BLOCK_TRIAL_SPAWNER_AMBIENT = BuiltinSoundEvent.get("minecraft:block.trial_spawner.ambient");
SoundEvent BLOCK_TRIAL_SPAWNER_AMBIENT_CHARGED = BuiltinSoundEvent.get("minecraft:block.trial_spawner.ambient_charged");
SoundEvent BLOCK_TRIAL_SPAWNER_AMBIENT_OMINOUS = BuiltinSoundEvent.get("minecraft:block.trial_spawner.ambient_ominous");
SoundEvent BLOCK_TRIAL_SPAWNER_OPEN_SHUTTER = BuiltinSoundEvent.get("minecraft:block.trial_spawner.open_shutter");
@ -1777,6 +1777,12 @@ interface SoundEvents {
SoundEvent MUSIC_DISC_RELIC = BuiltinSoundEvent.get("minecraft:music_disc.relic");
SoundEvent MUSIC_DISC_CREATOR = BuiltinSoundEvent.get("minecraft:music_disc.creator");
SoundEvent MUSIC_DISC_CREATOR_MUSIC_BOX = BuiltinSoundEvent.get("minecraft:music_disc.creator_music_box");
SoundEvent MUSIC_DISC_PRECIPICE = BuiltinSoundEvent.get("minecraft:music_disc.precipice");
SoundEvent MUSIC_DRAGON = BuiltinSoundEvent.get("minecraft:music.dragon");
SoundEvent MUSIC_END = BuiltinSoundEvent.get("minecraft:music.end");
@ -2883,6 +2889,8 @@ interface SoundEvents {
SoundEvent BLOCK_VAULT_EJECT_ITEM = BuiltinSoundEvent.get("minecraft:block.vault.eject_item");
SoundEvent BLOCK_VAULT_REJECT_REWARDED_PLAYER = BuiltinSoundEvent.get("minecraft:block.vault.reject_rewarded_player");
SoundEvent BLOCK_VAULT_FALL = BuiltinSoundEvent.get("minecraft:block.vault.fall");
SoundEvent BLOCK_VAULT_HIT = BuiltinSoundEvent.get("minecraft:block.vault.hit");

View File

@ -6,14 +6,17 @@ import net.minestom.server.adventure.bossbar.BossBarManager;
import net.minestom.server.command.CommandManager;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.metadata.animal.tameable.WolfMeta;
import net.minestom.server.entity.metadata.other.PaintingMeta;
import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.exception.ExceptionManager;
import net.minestom.server.gamedata.tags.TagManager;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.banner.BannerPattern;
import net.minestom.server.instance.block.jukebox.JukeboxSong;
import net.minestom.server.item.armor.TrimMaterial;
import net.minestom.server.item.armor.TrimPattern;
import net.minestom.server.item.enchant.Enchantment;
import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.message.ChatType;
import net.minestom.server.monitoring.BenchmarkManager;
@ -46,14 +49,10 @@ import java.net.SocketAddress;
* The server needs to be initialized with {@link #init()} and started with {@link #start(String, int)}.
* You should register all of your dimensions, biomes, commands, events, etc... in-between.
*/
public final class MinecraftServer {
public final class MinecraftServer implements MinecraftConstants {
public static final ComponentLogger LOGGER = ComponentLogger.logger(MinecraftServer.class);
public static final String VERSION_NAME = "1.20.6";
public static final int PROTOCOL_VERSION = 766;
public static final int DATA_VERSION = 3839;
// Threads
public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark";
@ -287,6 +286,18 @@ public final class MinecraftServer {
return serverProcess.wolfVariant();
}
public static @NotNull DynamicRegistry<Enchantment> getEnchantmentRegistry() {
return serverProcess.enchantment();
}
public static @NotNull DynamicRegistry<PaintingMeta.Variant> getPaintingVariantRegistry() {
return serverProcess.paintingVariant();
}
public static @NotNull DynamicRegistry<JukeboxSong> getJukeboxSongRegistry() {
return serverProcess.jukeboxSong();
}
public static Server getServer() {
return serverProcess.server();
}

View File

@ -7,6 +7,7 @@ import net.minestom.server.command.CommandManager;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.metadata.animal.tameable.WolfMeta;
import net.minestom.server.entity.metadata.other.PaintingMeta;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.server.ServerTickMonitorEvent;
@ -17,8 +18,10 @@ import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.banner.BannerPattern;
import net.minestom.server.instance.block.jukebox.JukeboxSong;
import net.minestom.server.item.armor.TrimMaterial;
import net.minestom.server.item.armor.TrimPattern;
import net.minestom.server.item.enchant.Enchantment;
import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.message.ChatType;
import net.minestom.server.monitoring.BenchmarkManager;
@ -63,6 +66,9 @@ final class ServerProcessImpl implements ServerProcess {
private final DynamicRegistry<TrimPattern> trimPattern;
private final DynamicRegistry<BannerPattern> bannerPattern;
private final DynamicRegistry<WolfMeta.Variant> wolfVariant;
private final DynamicRegistry<Enchantment> enchantment;
private final DynamicRegistry<PaintingMeta.Variant> paintingVariant;
private final DynamicRegistry<JukeboxSong> jukeboxSong;
private final ConnectionManager connection;
private final PacketListenerManager packetListener;
@ -98,6 +104,9 @@ final class ServerProcessImpl implements ServerProcess {
this.trimPattern = TrimPattern.createDefaultRegistry();
this.bannerPattern = BannerPattern.createDefaultRegistry();
this.wolfVariant = WolfMeta.Variant.createDefaultRegistry();
this.enchantment = Enchantment.createDefaultRegistry();
this.paintingVariant = PaintingMeta.Variant.createDefaultRegistry();
this.jukeboxSong = JukeboxSong.createDefaultRegistry();
this.connection = new ConnectionManager();
this.packetListener = new PacketListenerManager();
@ -150,6 +159,21 @@ final class ServerProcessImpl implements ServerProcess {
return wolfVariant;
}
@Override
public @NotNull DynamicRegistry<Enchantment> enchantment() {
return enchantment;
}
@Override
public @NotNull DynamicRegistry<PaintingMeta.Variant> paintingVariant() {
return paintingVariant;
}
@Override
public @NotNull DynamicRegistry<JukeboxSong> jukeboxSong() {
return jukeboxSong;
}
@Override
public @NotNull ConnectionManager connection() {
return connection;

View File

@ -1,12 +1,13 @@
package net.minestom.server.command.builder.arguments.minecraft.registry;
import net.minestom.server.item.enchant.Enchantment;
import net.minestom.server.registry.DynamicRegistry;
import org.jetbrains.annotations.NotNull;
/**
* Represents an argument giving an {@link Enchantment}.
*/
public class ArgumentEnchantment extends ArgumentRegistry<Enchantment> {
public class ArgumentEnchantment extends ArgumentRegistry<DynamicRegistry.Key<Enchantment>> {
public ArgumentEnchantment(String id) {
super(id);
@ -18,8 +19,9 @@ public class ArgumentEnchantment extends ArgumentRegistry<Enchantment> {
}
@Override
public Enchantment getRegistry(@NotNull String value) {
return Enchantment.fromNamespaceId(value);
public DynamicRegistry.Key<Enchantment> getRegistry(@NotNull String value) {
// return Enchantment.fromNamespaceId(value);
throw new UnsupportedOperationException("todo");
}
@Override

View File

@ -146,13 +146,11 @@ public final class Metadata {
return new MetadataImpl.EntryImpl<>(TYPE_WOLF_VARIANT, value, WolfMeta.Variant.NETWORK_TYPE);
}
// WOLF VARIANT
public static Entry<FrogMeta.Variant> FrogVariant(@NotNull FrogMeta.Variant value) {
return new MetadataImpl.EntryImpl<>(TYPE_FROG_VARIANT, value, FrogMeta.Variant.NETWORK_TYPE);
}
public static Entry<PaintingMeta.Variant> PaintingVariant(@NotNull PaintingMeta.Variant value) {
public static Entry<DynamicRegistry.Key<PaintingMeta.Variant>> PaintingVariant(@NotNull DynamicRegistry.Key<PaintingMeta.Variant> value) {
return new MetadataImpl.EntryImpl<>(TYPE_PAINTING_VARIANT, value, PaintingMeta.Variant.NETWORK_TYPE);
}

View File

@ -1,8 +1,6 @@
package net.minestom.server.entity.attribute;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.Registry;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;

View File

@ -1,28 +1,52 @@
package net.minestom.server.entity.attribute;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.function.Consumer;
/**
* Represents an instance of an attribute and its modifiers.
*/
public final class AttributeInstance {
public static final NetworkBuffer.Type<AttributeInstance> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, AttributeInstance value) {
buffer.write(Attribute.NETWORK_TYPE, value.attribute());
buffer.write(NetworkBuffer.DOUBLE, value.getBaseValue());
buffer.writeCollection(AttributeModifier.NETWORK_TYPE, value.modifiers());
}
@Override
public AttributeInstance read(@NotNull NetworkBuffer buffer) {
return new AttributeInstance(buffer.read(Attribute.NETWORK_TYPE), buffer.read(NetworkBuffer.DOUBLE),
buffer.readCollection(AttributeModifier.NETWORK_TYPE, Short.MAX_VALUE), null);
}
};
private final Attribute attribute;
private final Map<UUID, AttributeModifier> modifiers = new HashMap<>();
private final Consumer<AttributeInstance> propertyChangeListener;
private final Map<NamespaceID, AttributeModifier> modifiers;
private final Collection<AttributeModifier> unmodifiableModifiers;
private double baseValue;
private final Consumer<AttributeInstance> propertyChangeListener;
private double cachedValue = 0.0f;
public AttributeInstance(@NotNull Attribute attribute, @Nullable Consumer<AttributeInstance> listener) {
this(attribute, attribute.defaultValue(), new ArrayList<>(), listener);
}
public AttributeInstance(@NotNull Attribute attribute, double baseValue, @NotNull Collection<AttributeModifier> modifiers, @Nullable Consumer<AttributeInstance> listener) {
this.attribute = attribute;
this.modifiers = new HashMap<>();
for (var modifier : modifiers) this.modifiers.put(modifier.id(), modifier);
this.unmodifiableModifiers = Collections.unmodifiableCollection(this.modifiers.values());
this.baseValue = baseValue;
this.propertyChangeListener = listener;
this.baseValue = attribute.defaultValue();
refreshCachedValue();
}
@ -31,7 +55,7 @@ public final class AttributeInstance {
*
* @return the associated attribute
*/
public @NotNull Attribute getAttribute() {
public @NotNull Attribute attribute() {
return attribute;
}
@ -58,13 +82,23 @@ public final class AttributeInstance {
}
}
/**
* Get the modifiers applied to this instance.
*
* @return an immutable collection of the modifiers applied to this attribute.
*/
@NotNull
public Collection<AttributeModifier> modifiers() {
return unmodifiableModifiers;
}
/**
* Add a modifier to this instance.
*
* @param modifier the modifier to add
*/
public void addModifier(@NotNull AttributeModifier modifier) {
if (modifiers.putIfAbsent(modifier.getId(), modifier) == null) {
if (modifiers.putIfAbsent(modifier.id(), modifier) == null) {
refreshCachedValue();
}
}
@ -75,7 +109,7 @@ public final class AttributeInstance {
* @param modifier the modifier to remove
*/
public void removeModifier(@NotNull AttributeModifier modifier) {
removeModifier(modifier.getId());
removeModifier(modifier.id());
}
/**
@ -83,22 +117,12 @@ public final class AttributeInstance {
*
* @param uuid The UUID of the modifier to remove
*/
public void removeModifier(@NotNull UUID uuid) {
if (modifiers.remove(uuid) != null) {
public void removeModifier(@NotNull NamespaceID id) {
if (modifiers.remove(id) != null) {
refreshCachedValue();
}
}
/**
* Get the modifiers applied to this instance.
*
* @return the modifiers.
*/
@NotNull
public Collection<AttributeModifier> getModifiers() {
return modifiers.values();
}
/**
* Gets the value of this instance calculated with modifiers applied.
*
@ -115,17 +139,17 @@ public final class AttributeInstance {
final Collection<AttributeModifier> modifiers = getModifiers();
double base = getBaseValue();
for (var modifier : modifiers.stream().filter(mod -> mod.getOperation() == AttributeOperation.ADD_VALUE).toArray(AttributeModifier[]::new)) {
base += modifier.getAmount();
for (var modifier : modifiers.stream().filter(mod -> mod.operation() == AttributeOperation.ADD_VALUE).toArray(AttributeModifier[]::new)) {
base += modifier.amount();
}
double result = base;
for (var modifier : modifiers.stream().filter(mod -> mod.getOperation() == AttributeOperation.MULTIPLY_BASE).toArray(AttributeModifier[]::new)) {
result += (base * modifier.getAmount());
for (var modifier : modifiers.stream().filter(mod -> mod.operation() == AttributeOperation.MULTIPLY_BASE).toArray(AttributeModifier[]::new)) {
result += (base * modifier.amount());
}
for (var modifier : modifiers.stream().filter(mod -> mod.getOperation() == AttributeOperation.MULTIPLY_TOTAL).toArray(AttributeModifier[]::new)) {
result *= (1.0f + modifier.getAmount());
for (var modifier : modifiers.stream().filter(mod -> mod.operation() == AttributeOperation.MULTIPLY_TOTAL).toArray(AttributeModifier[]::new)) {
result *= (1.0f + modifier.amount());
}
this.cachedValue = Math.clamp(result, getAttribute().minValue(), getAttribute().maxValue());
@ -135,4 +159,15 @@ public final class AttributeInstance {
propertyChangeListener.accept(this);
}
}
@Deprecated
@NotNull
public Collection<AttributeModifier> getModifiers() {
return modifiers();
}
@Deprecated
public @NotNull Attribute getAttribute() {
return attribute;
}
}

View File

@ -1,81 +1,48 @@
package net.minestom.server.entity.attribute;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* Represent an attribute modifier.
*/
public record AttributeModifier(
@NotNull UUID id,
@NotNull String name,
double amount,
@NotNull AttributeOperation operation
) implements NetworkBuffer.Writer {
public record AttributeModifier(@NotNull NamespaceID id, double amount, @NotNull AttributeOperation operation) {
public static final NetworkBuffer.Type<AttributeModifier> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, AttributeModifier value) {
buffer.write(NetworkBuffer.STRING, value.id.asString());
buffer.write(NetworkBuffer.DOUBLE, value.amount);
buffer.write(AttributeOperation.NETWORK_TYPE, value.operation);
}
@Override
public AttributeModifier read(@NotNull NetworkBuffer buffer) {
return new AttributeModifier(NamespaceID.from(buffer.read(NetworkBuffer.STRING)),
buffer.read(NetworkBuffer.DOUBLE), buffer.read(AttributeOperation.NETWORK_TYPE));
}
};
public static final BinaryTagSerializer<AttributeModifier> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> new AttributeModifier(NamespaceID.from(tag.getString("id")), tag.getDouble("amount"),
AttributeOperation.NBT_TYPE.read(tag.get("operation"))),
value -> CompoundBinaryTag.builder()
.putString("id", value.id.asString())
.putDouble("amount", value.amount)
.put("operation", AttributeOperation.NBT_TYPE.write(value.operation))
.build()
);
/**
* Creates a new modifier with a random id.
*
* @param name the name of this modifier
* @param id the (namespace) id of this modifier
* @param amount the value of this modifier
* @param operation the operation to apply this modifier with
*/
public AttributeModifier(@NotNull String name, double amount, @NotNull AttributeOperation operation) {
this(UUID.randomUUID(), name, amount, operation);
public AttributeModifier(@NotNull String id, double amount, @NotNull AttributeOperation operation) {
this(NamespaceID.from(id), amount, operation);
}
public AttributeModifier(@NotNull NetworkBuffer reader) {
this(reader.read(NetworkBuffer.UUID), reader.read(NetworkBuffer.STRING),
reader.read(NetworkBuffer.DOUBLE), reader.readEnum(AttributeOperation.class));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(NetworkBuffer.UUID, id);
writer.write(NetworkBuffer.STRING, name);
writer.write(NetworkBuffer.DOUBLE, amount);
writer.writeEnum(AttributeOperation.class, operation);
}
/**
* Gets the id of this modifier.
*
* @return the id of this modifier
*/
@Deprecated
public @NotNull UUID getId() {
return id;
}
/**
* Gets the name of this modifier.
*
* @return the name of this modifier
*/
@Deprecated
public @NotNull String getName() {
return name;
}
/**
* Gets the value of this modifier.
*
* @return the value of this modifier
*/
@Deprecated
public double getAmount() {
return amount;
}
/**
* Gets the operation of this modifier.
*
* @return the operation of this modifier
*/
@Deprecated
public @NotNull AttributeOperation getOperation() {
return operation;
}
}

View File

@ -1,5 +1,7 @@
package net.minestom.server.entity.attribute;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.Nullable;
public enum AttributeOperation {
@ -7,6 +9,9 @@ public enum AttributeOperation {
MULTIPLY_BASE(1),
MULTIPLY_TOTAL(2);
public static final NetworkBuffer.Type<AttributeOperation> NETWORK_TYPE = NetworkBuffer.Enum(AttributeOperation.class);
public static final BinaryTagSerializer<AttributeOperation> NBT_TYPE = BinaryTagSerializer.fromEnumStringable(AttributeOperation.class);
private static final AttributeOperation[] VALUES = new AttributeOperation[]{ADD_VALUE, MULTIPLY_BASE, MULTIPLY_TOTAL};
private final int id;

View File

@ -1,18 +1,23 @@
package net.minestom.server.entity.metadata.other;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.metadata.EntityMeta;
import net.minestom.server.entity.metadata.ObjectDataProvider;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.registry.ProtocolObject;
import net.minestom.server.registry.Registries;
import net.minestom.server.registry.Registry;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
public class PaintingMeta extends EntityMeta implements ObjectDataProvider {
public static final byte OFFSET = EntityMeta.MAX_OFFSET;
public static final byte MAX_OFFSET = OFFSET + 1;
@ -23,11 +28,11 @@ public class PaintingMeta extends EntityMeta implements ObjectDataProvider {
super(entity, metadata);
}
public @NotNull Variant getVariant() {
public @NotNull DynamicRegistry.Key<Variant> getVariant() {
return super.metadata.getIndex(OFFSET, Variant.KEBAB);
}
public void setVariant(@NotNull Variant value) {
public void setVariant(@NotNull DynamicRegistry.Key<Variant> value) {
super.metadata.setIndex(OFFSET, Metadata.PaintingVariant(value));
}
@ -74,90 +79,110 @@ public class PaintingMeta extends EntityMeta implements ObjectDataProvider {
}
}
public enum Variant implements StaticProtocolObject {
KEBAB(16, 16),
AZTEC(16, 16),
ALBAN(16, 16),
AZTEC2(16, 16),
BOMB(16, 16),
PLANT(16, 16),
WASTELAND(16, 16),
POOL(32, 16),
COURBET(32, 16),
SEA(32, 16),
SUNSET(32, 16),
CREEBET(32, 16),
WANDERER(16, 32),
GRAHAM(16, 32),
MATCH(32, 32),
BUST(32, 32),
STAGE(32, 32),
VOID(32, 32),
SKULL_AND_ROSES(32, 32),
WITHER(32, 32),
FIGHTERS(64, 32),
POINTER(64, 64),
PIGSCENE(64, 64),
BURNING_SKULL(64, 64),
SKELETON(64, 48),
EARTH(32, 32),
WIND(32, 32),
WATER(32, 32),
FIRE(32, 32),
DONKEY_KONG(64, 48);
public sealed interface Variant extends ProtocolObject, PaintingVariants permits VariantImpl {
@NotNull NetworkBuffer.Type<DynamicRegistry.Key<Variant>> NETWORK_TYPE = NetworkBuffer.RegistryKey(Registries::paintingVariant);
@NotNull BinaryTagSerializer<DynamicRegistry.Key<Variant>> NBT_TYPE = BinaryTagSerializer.registryKey(Registries::paintingVariant);
public static final NetworkBuffer.Type<Variant> NETWORK_TYPE = NetworkBuffer.Enum(Variant.class);
private static final Variant[] VALUES = values();
public static @Nullable Variant fromId(int id) {
if (id < 0 || id >= VALUES.length) {
return null;
}
return VALUES[id];
static @NotNull Variant create(
@NotNull NamespaceID namespace,
@NotNull NamespaceID assetId,
int width, int height
) {
return new VariantImpl(namespace, assetId, width, height, null);
}
public static @Nullable Variant fromNamespaceId(@Nullable String namespaceId) {
if (namespaceId == null) return null;
return fromNamespaceId(NamespaceID.from(namespaceId));
static @NotNull Builder builder(@NotNull String namespace) {
return builder(NamespaceID.from(namespace));
}
public static @Nullable Variant fromNamespaceId(@Nullable NamespaceID namespaceId) {
if (namespaceId == null) return null;
for (Variant value : VALUES) {
if (value.namespace().equals(namespaceId)) {
return value;
}
}
return null;
static @NotNull Builder builder(@NotNull NamespaceID namespace) {
return new Builder(namespace);
}
private final NamespaceID namespace;
private final int width;
private final int height;
Variant(int width, int height) {
this.namespace = NamespaceID.from("minecraft", name().toLowerCase(Locale.ROOT));
this.width = width;
this.height = height;
/**
* <p>Creates a new registry for painting variants, loading the vanilla painting variants.</p>
*
* @see net.minestom.server.MinecraftServer to get an existing instance of the registry
*/
@ApiStatus.Internal
static @NotNull DynamicRegistry<Variant> createDefaultRegistry() {
return DynamicRegistry.create(
"minecraft:painting_variant", VariantImpl.REGISTRY_NBT_TYPE, Registry.Resource.PAINTING_VARIANTS,
(namespace, props) -> new VariantImpl(Registry.paintingVariant(namespace, props))
);
}
@NotNull NamespaceID assetId();
int width();
int height();
@Override
public int id() {
return ordinal();
@Nullable Registry.PaintingVariantEntry registry();
class Builder {
private final NamespaceID namespace;
private NamespaceID assetId;
private int width;
private int height;
private Builder(@NotNull NamespaceID namespace) {
this.namespace = namespace;
}
@Contract(value = "_ -> this", pure = true)
public @NotNull Builder assetId(@NotNull NamespaceID assetId) {
this.assetId = assetId;
return this;
}
@Contract(value = "_ -> this", pure = true)
public @NotNull Builder width(int width) {
this.width = width;
return this;
}
@Contract(value = "_ -> this", pure = true)
public @NotNull Builder height(int height) {
this.height = height;
return this;
}
public @NotNull Variant build() {
return new VariantImpl(namespace, assetId, width, height, null);
}
}
}
record VariantImpl(
@NotNull NamespaceID namespace,
@NotNull NamespaceID assetId,
int width,
int height,
@Nullable Registry.PaintingVariantEntry registry
) implements Variant {
private static final BinaryTagSerializer<Variant> REGISTRY_NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> {
throw new UnsupportedOperationException("PaintingVariant is read-only");
},
variant -> CompoundBinaryTag.builder()
.putString("asset_id", variant.assetId().asString())
.putInt("width", variant.width())
.putInt("height", variant.height())
.build()
);
@SuppressWarnings("ConstantValue") // The builder can violate the nullability constraints
VariantImpl {
Check.notNull(namespace, "Namespace cannot be null");
Check.argCondition(assetId == null, "missing asset id: {0}", namespace);
Check.argCondition(width <= 0, "width must be positive: {0}", namespace);
Check.argCondition(height <= 0, "height must be positive: {0}", namespace);
}
public int width() {
return width;
}
public int height() {
return height;
}
@Override
public @NotNull NamespaceID namespace() {
return namespace;
VariantImpl(@NotNull Registry.PaintingVariantEntry registry) {
this(registry.namespace(), registry.assetId(), registry.width(), registry.height(), registry);
}
}

View File

@ -0,0 +1,99 @@
package net.minestom.server.instance.block.jukebox;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.registry.ProtocolObject;
import net.minestom.server.registry.Registries;
import net.minestom.server.registry.Registry;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public sealed interface JukeboxSong extends ProtocolObject, JukeboxSongs permits JukeboxSongImpl {
@NotNull NetworkBuffer.Type<DynamicRegistry.Key<JukeboxSong>> NETWORK_TYPE = NetworkBuffer.RegistryKey(Registries::jukeboxSong);
@NotNull BinaryTagSerializer<DynamicRegistry.Key<JukeboxSong>> NBT_TYPE = BinaryTagSerializer.registryKey(Registries::jukeboxSong);
static @NotNull JukeboxSong create(
@NotNull NamespaceID namespace,
@NotNull SoundEvent soundEvent,
@NotNull Component description,
float lengthInSeconds,
int comparatorOutput
) {
return new JukeboxSongImpl(namespace, soundEvent, description, lengthInSeconds, comparatorOutput, null);
}
static @NotNull Builder builder(@NotNull String namespace) {
return builder(NamespaceID.from(namespace));
}
static @NotNull Builder builder(@NotNull NamespaceID namespace) {
return new Builder(namespace);
}
/**
* <p>Creates a new registry for banner patterns, loading the vanilla banner patterns.</p>
*
* @see net.minestom.server.MinecraftServer to get an existing instance of the registry
*/
@ApiStatus.Internal
static @NotNull DynamicRegistry<JukeboxSong> createDefaultRegistry() {
return DynamicRegistry.create(
"minecraft:jukebox_song", JukeboxSongImpl.REGISTRY_NBT_TYPE, Registry.Resource.JUKEBOX_SONGS,
(namespace, props) -> new JukeboxSongImpl(Registry.jukeboxSong(namespace, props))
);
}
@NotNull SoundEvent soundEvent();
@NotNull Component description();
float lengthInSeconds();
int comparatorOutput();
@Override
@Nullable Registry.JukeboxSongEntry registry();
final class Builder {
private final NamespaceID namespace;
private SoundEvent soundEvent;
private Component description;
private float lengthInSeconds;
private int comparatorOutput = 0;
private Builder(@NotNull NamespaceID namespace) {
this.namespace = namespace;
}
public @NotNull Builder soundEvent(@NotNull SoundEvent soundEvent) {
this.soundEvent = soundEvent;
return this;
}
public @NotNull Builder description(@NotNull Component description) {
this.description = description;
return this;
}
public @NotNull Builder lengthInSeconds(float lengthInSeconds) {
this.lengthInSeconds = lengthInSeconds;
return this;
}
public @NotNull Builder comparatorOutput(int comparatorOutput) {
this.comparatorOutput = comparatorOutput;
return this;
}
public @NotNull JukeboxSong build() {
return new JukeboxSongImpl(namespace, soundEvent, description, lengthInSeconds, comparatorOutput, null);
}
}
}

View File

@ -0,0 +1,45 @@
package net.minestom.server.instance.block.jukebox;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.text.Component;
import net.minestom.server.registry.Registry;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
record JukeboxSongImpl(
@NotNull NamespaceID namespace,
@NotNull SoundEvent soundEvent,
@NotNull Component description,
float lengthInSeconds,
int comparatorOutput,
@Nullable Registry.JukeboxSongEntry registry
) implements JukeboxSong {
static final BinaryTagSerializer<JukeboxSong> REGISTRY_NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> {
throw new UnsupportedOperationException("JukeboxSong is read-only");
},
jukeboxSong -> CompoundBinaryTag.builder()
.putString("sound_event", jukeboxSong.soundEvent().name())
.put("description", BinaryTagSerializer.NBT_COMPONENT.write(jukeboxSong.description()))
.putFloat("length_in_seconds", jukeboxSong.lengthInSeconds())
.putInt("comparator_output", jukeboxSong.comparatorOutput())
.build()
);
@SuppressWarnings("ConstantValue") // The builder can violate the nullability constraints
JukeboxSongImpl {
Check.notNull(namespace, "Namespace cannot be null");
Check.argCondition(soundEvent == null, "missing sound event: {0}", namespace);
Check.argCondition(description == null, "missing description: {0}", namespace);
}
JukeboxSongImpl(@NotNull Registry.JukeboxSongEntry registry) {
this(registry.namespace(), registry.soundEvent(), registry.description(), registry.lengthInSeconds(), registry.comparatorOutput(), registry);
}
}

View File

@ -76,7 +76,8 @@ public class EnchantmentTableInventory extends Inventory {
final short id = enchantmentShown[enchantmentSlot.ordinal()];
if (id == -1)
return null;
return Enchantment.fromId(id);
// return Enchantment.fromId(id);
throw new UnsupportedOperationException("todo");
}
/**
@ -88,13 +89,13 @@ public class EnchantmentTableInventory extends Inventory {
* @param enchantment the enchantment
*/
public void setEnchantmentShown(EnchantmentSlot enchantmentSlot, Enchantment enchantment) {
final short id = enchantment == null ? -1 : (short) enchantment.id();
switch (enchantmentSlot) {
case TOP -> sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_ID_TOP, id);
case MIDDLE -> sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_ID_MIDDLE, id);
case BOTTOM -> sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_ID_BOTTOM, id);
}
this.enchantmentShown[enchantmentSlot.ordinal()] = id;
// final short id = enchantment == null ? -1 : (short) enchantment.id();
// switch (enchantmentSlot) {
// case TOP -> sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_ID_TOP, id);
// case MIDDLE -> sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_ID_MIDDLE, id);
// case BOTTOM -> sendProperty(InventoryProperty.ENCHANTMENT_TABLE_ENCH_ID_BOTTOM, id);
// }
// this.enchantmentShown[enchantmentSlot.ordinal()] = id;
}
/**

View File

@ -58,6 +58,7 @@ public final class ItemComponent {
public static final DataComponent<CustomData> BLOCK_ENTITY_DATA = DataComponent.register("block_entity_data", CustomData.NETWORK_TYPE, CustomData.NBT_TYPE);
public static final DataComponent<String> INSTRUMENT = DataComponent.register("instrument", NetworkBuffer.STRING, BinaryTagSerializer.STRING);
public static final DataComponent<Integer> OMINOUS_BOTTLE_AMPLIFIER = DataComponent.register("ominous_bottle_amplifier", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
public static final DataComponent<JukeboxPlayable> JUKEBOX_PLAYABLE = DataComponent.register("jukebox_playable", JukeboxPlayable.NETWORK_TYPE, JukeboxPlayable.NBT_TYPE);
public static final DataComponent<List<String>> RECIPES = DataComponent.register("recipes", NetworkBuffer.STRING.list(Short.MAX_VALUE), BinaryTagSerializer.STRING.list());
public static final DataComponent<LodestoneTracker> LODESTONE_TRACKER = DataComponent.register("lodestone_tracker", LodestoneTracker.NETWORK_TYPE, LodestoneTracker.NBT_TYPE);
public static final DataComponent<FireworkExplosion> FIREWORK_EXPLOSION = DataComponent.register("firework_explosion", FireworkExplosion.NETWORK_TYPE, FireworkExplosion.NBT_TYPE);

View File

@ -1,6 +1,8 @@
package net.minestom.server.item.attribute;
import net.minestom.server.entity.EquipmentSlot;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@ -16,6 +18,9 @@ public enum AttributeSlot {
ARMOR(EquipmentSlot.CHESTPLATE, EquipmentSlot.LEGGINGS, EquipmentSlot.BOOTS, EquipmentSlot.HELMET),
BODY(EquipmentSlot.CHESTPLATE, EquipmentSlot.LEGGINGS);
public static final NetworkBuffer.Type<AttributeSlot> NETWORK_TYPE = NetworkBuffer.Enum(AttributeSlot.class);
public static final BinaryTagSerializer<AttributeSlot> NBT_TYPE = BinaryTagSerializer.fromEnumStringable(AttributeSlot.class);
private final List<EquipmentSlot> equipmentSlots;
AttributeSlot(@NotNull EquipmentSlot... equipmentSlots) {

View File

@ -1,18 +1,18 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.*;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import net.minestom.server.entity.attribute.Attribute;
import net.minestom.server.entity.attribute.AttributeModifier;
import net.minestom.server.entity.attribute.AttributeOperation;
import net.minestom.server.item.attribute.AttributeSlot;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.UniqueIdUtils;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public record AttributeList(@NotNull List<Modifier> modifiers, boolean showInTooltip) {
public static final AttributeList EMPTY = new AttributeList(List.of(), true);
@ -20,13 +20,13 @@ public record AttributeList(@NotNull List<Modifier> modifiers, boolean showInToo
public static final NetworkBuffer.Type<AttributeList> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, AttributeList value) {
buffer.writeCollection(value.modifiers);
buffer.writeCollection(Modifier.NETWORK_TYPE, value.modifiers);
buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip);
}
@Override
public AttributeList read(@NotNull NetworkBuffer buffer) {
return new AttributeList(buffer.readCollection(Modifier::new, Short.MAX_VALUE),
return new AttributeList(buffer.readCollection(Modifier.NETWORK_TYPE, Short.MAX_VALUE),
buffer.read(NetworkBuffer.BOOLEAN));
}
};
@ -34,16 +34,9 @@ public record AttributeList(@NotNull List<Modifier> modifiers, boolean showInToo
public static final BinaryTagSerializer<AttributeList> NBT_TYPE = new BinaryTagSerializer<>() {
@Override
public @NotNull BinaryTag write(@NotNull AttributeList value) {
ListBinaryTag.Builder<CompoundBinaryTag> modifiers = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
ListBinaryTag.Builder<BinaryTag> modifiers = ListBinaryTag.builder();
for (Modifier modifier : value.modifiers) {
modifiers.add(CompoundBinaryTag.builder()
.putString("type", modifier.attribute.name())
.putString("slot", modifier.slot.name().toLowerCase(Locale.ROOT))
.put("uuid", UniqueIdUtils.toNbt(modifier.modifier.id()))
.putString("name", modifier.modifier.name())
.putDouble("amount", modifier.modifier.amount())
.putString("operation", modifier.modifier.operation().name().toLowerCase(Locale.ROOT))
.build());
modifiers.add(Modifier.NBT_TYPE.write(modifier));
}
return CompoundBinaryTag.builder()
.put("modifiers", modifiers.build())
@ -53,50 +46,45 @@ public record AttributeList(@NotNull List<Modifier> modifiers, boolean showInToo
@Override
public @NotNull AttributeList read(@NotNull BinaryTag tag) {
boolean showInTooltip = true;
ListBinaryTag modifiersTag;
if (tag instanceof CompoundBinaryTag compound) {
modifiersTag = compound.getList("modifiers", BinaryTagTypes.COMPOUND);
showInTooltip = compound.getBoolean("show_in_tooltip", true);
} else if (tag instanceof ListBinaryTag list) {
modifiersTag = list;
} else return EMPTY;
List<Modifier> modifiers = new ArrayList<>(modifiersTag.size());
for (BinaryTag modifierTagRaw : modifiersTag) {
if (!(modifierTagRaw instanceof CompoundBinaryTag modifierTag)) continue;
Attribute attribute = Attribute.fromNamespaceId(modifierTag.getString("type"));
if (attribute == null) continue; // Unknown attribute, skip
AttributeSlot slot = AttributeSlot.valueOf(modifierTag.getString("slot").toUpperCase(Locale.ROOT));
AttributeModifier modifier = new AttributeModifier(
UniqueIdUtils.fromNbt((IntArrayBinaryTag) modifierTag.get("uuid")),
modifierTag.getString("name"),
modifierTag.getDouble("amount"),
AttributeOperation.valueOf(modifierTag.getString("operation").toUpperCase(Locale.ROOT))
return switch (tag) {
case CompoundBinaryTag compound -> new AttributeList(
compound.getList("modifiers", BinaryTagTypes.COMPOUND).stream().map(Modifier.NBT_TYPE::read).toList(),
compound.getBoolean("show_in_tooltip", true)
);
modifiers.add(new Modifier(attribute, modifier, slot));
}
return new AttributeList(modifiers, showInTooltip);
case ListBinaryTag list -> new AttributeList(list.stream().map(Modifier.NBT_TYPE::read).toList());
default -> EMPTY;
};
}
};
public record Modifier(
@NotNull Attribute attribute,
@NotNull AttributeModifier modifier,
@NotNull AttributeSlot slot
) implements NetworkBuffer.Writer {
public record Modifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier, @NotNull AttributeSlot slot) {
public static final NetworkBuffer.Type<Modifier> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, Modifier value) {
buffer.write(Attribute.NETWORK_TYPE, value.attribute);
buffer.write(AttributeModifier.NETWORK_TYPE, value.modifier);
buffer.writeEnum(AttributeSlot.class, value.slot);
}
public Modifier(@NotNull NetworkBuffer reader) {
this(reader.read(Attribute.NETWORK_TYPE),
new AttributeModifier(reader),
reader.readEnum(AttributeSlot.class));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(Attribute.NETWORK_TYPE, attribute);
modifier.write(writer);
writer.writeEnum(AttributeSlot.class, slot);
}
@Override
public Modifier read(@NotNull NetworkBuffer buffer) {
return new Modifier(buffer.read(Attribute.NETWORK_TYPE),
buffer.read(AttributeModifier.NETWORK_TYPE),
buffer.readEnum(AttributeSlot.class));
}
};
public static final BinaryTagSerializer<Modifier> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> new Modifier(
Attribute.NBT_TYPE.read(tag.get("type")),
AttributeModifier.NBT_TYPE.read(tag),
tag.get("slot") instanceof BinaryTag slot ? AttributeSlot.NBT_TYPE.read(slot) : AttributeSlot.ANY
),
modifier -> CompoundBinaryTag.builder()
.put("type", Attribute.NBT_TYPE.write(modifier.attribute))
.put((CompoundBinaryTag) AttributeModifier.NBT_TYPE.write(modifier.modifier))
.put("slot", AttributeSlot.NBT_TYPE.write(modifier.slot))
.build()
);
}
public AttributeList {

View File

@ -4,6 +4,7 @@ import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.item.enchant.Enchantment;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
@ -11,15 +12,15 @@ import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
public record EnchantmentList(@NotNull Map<Enchantment, Integer> enchantments, boolean showInTooltip) {
public record EnchantmentList(@NotNull Map<DynamicRegistry.Key<Enchantment>, Integer> enchantments, boolean showInTooltip) {
public static final EnchantmentList EMPTY = new EnchantmentList(Map.of(), true);
public static NetworkBuffer.Type<EnchantmentList> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, @NotNull EnchantmentList value) {
buffer.write(NetworkBuffer.VAR_INT, value.enchantments.size());
for (Map.Entry<Enchantment, Integer> entry : value.enchantments.entrySet()) {
buffer.write(NetworkBuffer.VAR_INT, entry.getKey().id());
for (Map.Entry<DynamicRegistry.Key<Enchantment>, Integer> entry : value.enchantments.entrySet()) {
// buffer.write(NetworkBuffer.VAR_INT, entry.getKey().id());
buffer.write(NetworkBuffer.VAR_INT, entry.getValue());
}
buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip);
@ -29,11 +30,11 @@ public record EnchantmentList(@NotNull Map<Enchantment, Integer> enchantments, b
public @NotNull EnchantmentList read(@NotNull NetworkBuffer buffer) {
int size = buffer.read(NetworkBuffer.VAR_INT);
Check.argCondition(size < 0 || size > Short.MAX_VALUE, "Invalid enchantment list size: {0}", size);
Map<Enchantment, Integer> enchantments = new HashMap<>(size);
Map<DynamicRegistry.Key<Enchantment>, Integer> enchantments = new HashMap<>(size);
for (int i = 0; i < size; i++) {
Enchantment enchantment = Enchantment.fromId(buffer.read(NetworkBuffer.VAR_INT));
int level = buffer.read(NetworkBuffer.VAR_INT);
enchantments.put(enchantment, level);
// Enchantment enchantment = Enchantment.fromId(buffer.read(NetworkBuffer.VAR_INT));
// int level = buffer.read(NetworkBuffer.VAR_INT);
// enchantments.put(enchantment, level);
}
boolean showInTooltip = buffer.read(NetworkBuffer.BOOLEAN);
return new EnchantmentList(enchantments, showInTooltip);
@ -44,12 +45,12 @@ public record EnchantmentList(@NotNull Map<Enchantment, Integer> enchantments, b
tag -> {
// We have two variants of the enchantment list, one with {levels: {...}, show_in_tooltip: boolean} and one with {...}.
CompoundBinaryTag levels = tag.keySet().contains("levels") ? tag.getCompound("levels") : tag;
Map<Enchantment, Integer> enchantments = new HashMap<>(levels.size());
Map<DynamicRegistry.Key<Enchantment>, Integer> enchantments = new HashMap<>(levels.size());
for (Map.Entry<String, ? extends BinaryTag> entry : levels) {
Enchantment enchantment = Enchantment.fromNamespaceId(entry.getKey());
Check.notNull(enchantment, "Unknown enchantment: {0}", entry.getKey());
int level = BinaryTagSerializer.INT.read(entry.getValue());
if (level > 0) enchantments.put(enchantment, level);
// Enchantment enchantment = Enchantment.fromNamespaceId(entry.getKey());
// Check.notNull(enchantment, "Unknown enchantment: {0}", entry.getKey());
// int level = BinaryTagSerializer.INT.read(entry.getValue());
// if (level > 0) enchantments.put(enchantment, level);
}
// Doesnt matter which variant we chose, the default will work.
@ -59,7 +60,7 @@ public record EnchantmentList(@NotNull Map<Enchantment, Integer> enchantments, b
},
value -> {
CompoundBinaryTag.Builder levels = CompoundBinaryTag.builder();
for (Map.Entry<Enchantment, Integer> entry : value.enchantments.entrySet()) {
for (Map.Entry<DynamicRegistry.Key<Enchantment>, Integer> entry : value.enchantments.entrySet()) {
levels.put(entry.getKey().name(), BinaryTagSerializer.INT.write(entry.getValue()));
}
@ -74,30 +75,30 @@ public record EnchantmentList(@NotNull Map<Enchantment, Integer> enchantments, b
enchantments = Map.copyOf(enchantments);
}
public EnchantmentList(@NotNull Map<Enchantment, Integer> enchantments) {
public EnchantmentList(@NotNull Map<DynamicRegistry.Key<Enchantment>, Integer> enchantments) {
this(enchantments, true);
}
public EnchantmentList(@NotNull Enchantment enchantment, int level) {
public EnchantmentList(@NotNull DynamicRegistry.Key<Enchantment> enchantment, int level) {
this(Map.of(enchantment, level), true);
}
public boolean has(@NotNull Enchantment enchantment) {
public boolean has(@NotNull DynamicRegistry.Key<Enchantment> enchantment) {
return enchantments.containsKey(enchantment);
}
public int level(@NotNull Enchantment enchantment) {
public int level(@NotNull DynamicRegistry.Key<Enchantment> enchantment) {
return enchantments.getOrDefault(enchantment, 0);
}
public @NotNull EnchantmentList with(@NotNull Enchantment enchantment, int level) {
Map<Enchantment, Integer> newEnchantments = new HashMap<>(enchantments);
public @NotNull EnchantmentList with(@NotNull DynamicRegistry.Key<Enchantment> enchantment, int level) {
Map<DynamicRegistry.Key<Enchantment>, Integer> newEnchantments = new HashMap<>(enchantments);
newEnchantments.put(enchantment, level);
return new EnchantmentList(newEnchantments, showInTooltip);
}
public @NotNull EnchantmentList remove(@NotNull Enchantment enchantment) {
Map<Enchantment, Integer> newEnchantments = new HashMap<>(enchantments);
public @NotNull EnchantmentList remove(@NotNull DynamicRegistry.Key<Enchantment> enchantment) {
Map<DynamicRegistry.Key<Enchantment>, Integer> newEnchantments = new HashMap<>(enchantments);
newEnchantments.remove(enchantment);
return new EnchantmentList(newEnchantments, showInTooltip);
}

View File

@ -1,8 +1,10 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.ServerFlag;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.potion.CustomPotionEffect;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
@ -10,7 +12,8 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds, @NotNull List<EffectChance> effects) {
public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds,
@NotNull ItemStack usingConvertsTo, @NotNull List<EffectChance> effects) {
public static final float DEFAULT_EAT_SECONDS = 1.6f;
public static final NetworkBuffer.Type<Food> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@ -20,6 +23,7 @@ public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat
buffer.write(NetworkBuffer.FLOAT, value.saturationModifier);
buffer.write(NetworkBuffer.BOOLEAN, value.canAlwaysEat);
buffer.write(NetworkBuffer.FLOAT, value.eatSeconds);
buffer.write(ItemStack.OPTIONAL_NETWORK_TYPE, value.usingConvertsTo);
buffer.writeCollection(EffectChance.NETWORK_TYPE, value.effects);
}
@ -30,6 +34,7 @@ public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat
buffer.read(NetworkBuffer.FLOAT),
buffer.read(NetworkBuffer.BOOLEAN),
buffer.read(NetworkBuffer.FLOAT),
buffer.read(ItemStack.OPTIONAL_NETWORK_TYPE),
buffer.readCollection(EffectChance.NETWORK_TYPE, Short.MAX_VALUE)
);
}
@ -40,14 +45,21 @@ public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat
tag.getFloat("saturation_modifier"),
tag.getBoolean("can_always_eat"),
tag.getFloat("eat_seconds", DEFAULT_EAT_SECONDS),
tag.get("using_converts_to") instanceof BinaryTag usingConvertsTo
? ItemStack.NBT_TYPE.read(usingConvertsTo) : ItemStack.AIR,
EffectChance.NBT_LIST_TYPE.read(tag.getList("effects", BinaryTagTypes.COMPOUND))),
value -> CompoundBinaryTag.builder()
.putInt("nutrition", value.nutrition)
.putFloat("saturationModifier", value.saturationModifier)
.putBoolean("canAlwaysEat", value.canAlwaysEat)
.putFloat("eatSeconds", value.eatSeconds)
.put("effects", EffectChance.NBT_LIST_TYPE.write(value.effects))
.build()
value -> {
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
.putInt("nutrition", value.nutrition)
.putFloat("saturation_odifier", value.saturationModifier)
.putBoolean("can_always_eat", value.canAlwaysEat)
.putFloat("eat_seconds", value.eatSeconds)
.put("effects", EffectChance.NBT_LIST_TYPE.write(value.effects));
if (!value.usingConvertsTo.isAir()) {
builder.put("using_converts_to", ItemStack.NBT_TYPE.write(value.usingConvertsTo));
}
return builder.build();
}
);
public Food {

View File

@ -0,0 +1,59 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.block.jukebox.JukeboxSong;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
public record JukeboxPlayable(@NotNull DynamicRegistry.Key<JukeboxSong> song, boolean showInTooltip) {
public static final NetworkBuffer.Type<JukeboxPlayable> NETWORK_TYPE = new NetworkBuffer.Type<>() {
// For some reason I(matt) cannot discern, the wire format for this type can write the song
// as either a registry ID or a namespace ID. Minestom always writes as a registry id.
@Override
public void write(@NotNull NetworkBuffer buffer, JukeboxPlayable value) {
buffer.write(NetworkBuffer.BOOLEAN, true); // First option (registry id)
buffer.write(JukeboxSong.NETWORK_TYPE, value.song);
buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip);
}
@Override
public JukeboxPlayable read(@NotNull NetworkBuffer buffer) {
DynamicRegistry.Key<JukeboxSong> song;
if (buffer.read(NetworkBuffer.BOOLEAN)) {
song = buffer.read(JukeboxSong.NETWORK_TYPE);
} else {
song = DynamicRegistry.Key.of(buffer.read(NetworkBuffer.STRING));
final DynamicRegistry<JukeboxSong> registry = MinecraftServer.getJukeboxSongRegistry();
Check.stateCondition(registry.get(song) != null, "unknown song: {0}", song);
}
return new JukeboxPlayable(song, buffer.read(NetworkBuffer.BOOLEAN));
}
};
public static final BinaryTagSerializer<JukeboxPlayable> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> new JukeboxPlayable(
JukeboxSong.NBT_TYPE.read(tag.get("song")),
tag.getBoolean("show_in_tooltip")),
value -> CompoundBinaryTag.builder()
.put("song", JukeboxSong.NBT_TYPE.write(value.song))
.putBoolean("show_in_tooltip", value.showInTooltip)
.build()
);
public JukeboxPlayable(@NotNull DynamicRegistry.Key<JukeboxSong> song) {
this(song, true);
}
public @NotNull JukeboxPlayable withSong(@NotNull DynamicRegistry.Key<JukeboxSong> song) {
return new JukeboxPlayable(song, showInTooltip);
}
public @NotNull JukeboxPlayable withTooltip(boolean showInTooltip) {
return new JukeboxPlayable(song, showInTooltip);
}
}

View File

@ -1,47 +1,56 @@
package net.minestom.server.item.enchant;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.registry.ProtocolObject;
import net.minestom.server.registry.Registries;
import net.minestom.server.registry.Registry;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.Contract;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public sealed interface Enchantment extends ProtocolObject, Enchantments permits EnchantmentImpl {
@NotNull NetworkBuffer.Type<DynamicRegistry.Key<Enchantment>> NETWORK_TYPE = NetworkBuffer.RegistryKey(Registries::enchantment);
@NotNull BinaryTagSerializer<DynamicRegistry.Key<Enchantment>> NBT_TYPE = BinaryTagSerializer.registryKey(Registries::enchantment);
public sealed interface Enchantment extends StaticProtocolObject, Enchantments permits EnchantmentImpl {
static @NotNull Builder builder(@NotNull String namespace) {
return builder(NamespaceID.from(namespace));
}
static @NotNull Builder builder(@NotNull NamespaceID namespace) {
return new Builder(namespace);
}
/**
* Returns the enchantment registry.
* <p>Creates a new registry for enchantments, loading the vanilla enchantments.</p>
*
* @return the enchantment registry
* @see net.minestom.server.MinecraftServer to get an existing instance of the registry
*/
@Contract(pure = true)
@NotNull Registry.EnchantmentEntry registry();
@Override
default @NotNull NamespaceID namespace() {
return registry().namespace();
@ApiStatus.Internal
static @NotNull DynamicRegistry<Enchantment> createDefaultRegistry() {
return DynamicRegistry.create(
"minecraft:enchantment", EnchantmentImpl.REGISTRY_NBT_TYPE
//todo reenable to load vanilla enchants.
// Registry.Resource.ENCHANTMENTS,
// (namespace, props) -> new EnchantmentImpl(Registry.enchantment(namespace, props))
);
}
@Override
default int id() {
return registry().id();
@Nullable Registry.EnchantmentEntry registry();
class Builder {
private final NamespaceID namespace;
private Builder(@NotNull NamespaceID namespace) {
this.namespace = namespace;
}
public @NotNull Enchantment build() {
return new EnchantmentImpl(namespace, null);
}
}
static @NotNull Collection<@NotNull Enchantment> values() {
return EnchantmentImpl.values();
}
static @Nullable Enchantment fromNamespaceId(@NotNull String namespaceID) {
return EnchantmentImpl.getSafe(namespaceID);
}
static @Nullable Enchantment fromNamespaceId(@NotNull NamespaceID namespaceID) {
return fromNamespaceId(namespaceID.asString());
}
static @Nullable Enchantment fromId(int id) {
return EnchantmentImpl.getId(id);
}
}

View File

@ -1,32 +1,29 @@
package net.minestom.server.item.enchant;
import net.minestom.server.registry.Registry;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
record EnchantmentImpl(@NotNull NamespaceID namespace, @Nullable Registry.EnchantmentEntry registry) implements Enchantment {
record EnchantmentImpl(Registry.EnchantmentEntry registry) implements Enchantment {
private static final Registry.Container<Enchantment> CONTAINER = Registry.createStaticContainer(Registry.Resource.ENCHANTMENTS,
(namespace, properties) -> new EnchantmentImpl(Registry.enchantment(namespace, properties)));
static final BinaryTagSerializer<Enchantment> REGISTRY_NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> {
throw new UnsupportedOperationException("BannerPattern is read-only");
},
bannerPattern -> {
throw new UnsupportedOperationException("todo");
}
);
static Enchantment get(@NotNull String namespace) {
return CONTAINER.get(namespace);
EnchantmentImpl {
Check.notNull(namespace, "Namespace cannot be null");
}
static Enchantment getSafe(@NotNull String namespace) {
return CONTAINER.getSafe(namespace);
EnchantmentImpl(@NotNull Registry.EnchantmentEntry registry) {
this(registry.namespace(), registry);
}
static Enchantment getId(int id) {
return CONTAINER.getId(id);
}
static Collection<Enchantment> values() {
return CONTAINER.values();
}
@Override
public String toString() {
return name();
}
}

View File

@ -295,6 +295,7 @@ public final class ConnectionManager {
throw new RuntimeException("Error receiving known packs", e);
}
boolean excludeVanilla = !knownPacks.contains(SelectKnownPacksPacket.MINECRAFT_CORE);
excludeVanilla = false; //todo
var serverProcess = MinecraftServer.process();
player.sendPacket(serverProcess.chatType().registryDataPacket(excludeVanilla));
@ -305,6 +306,9 @@ public final class ConnectionManager {
player.sendPacket(serverProcess.trimPattern().registryDataPacket(excludeVanilla));
player.sendPacket(serverProcess.bannerPattern().registryDataPacket(excludeVanilla));
player.sendPacket(serverProcess.wolfVariant().registryDataPacket(excludeVanilla));
player.sendPacket(serverProcess.enchantment().registryDataPacket(excludeVanilla));
player.sendPacket(serverProcess.paintingVariant().registryDataPacket(excludeVanilla));
player.sendPacket(serverProcess.jukeboxSong().registryDataPacket(excludeVanilla));
player.sendPacket(TagsPacket.DEFAULT_TAGS);
}

View File

@ -193,6 +193,25 @@ public final class NetworkBuffer {
return values;
}
public <K, V> @NotNull Map<K, V> writeMap(@NotNull NetworkBuffer.Type<K> keyType, @NotNull NetworkBuffer.Type<V> valueType, @NotNull Map<K, V> map) {
write(VAR_INT, map.size());
for (Map.Entry<K, V> entry : map.entrySet()) {
write(keyType, entry.getKey());
write(valueType, entry.getValue());
}
return map;
}
public <K, V> @NotNull Map<K, V> readMap(@NotNull NetworkBuffer.Type<K> keyType, @NotNull NetworkBuffer.Type<V> valueType, int maxSize) {
final int size = read(VAR_INT);
Check.argCondition(size > maxSize, "Map size ({0}) is higher than the maximum allowed size ({1})", size, maxSize);
final Map<K, V> map = new HashMap<>(size);
for (int i = 0; i < size; i++) {
map.put(read(keyType), read(valueType));
}
return map;
}
public <E extends Enum<?>> void writeEnum(@NotNull Class<E> enumClass, @NotNull E value) {
write(VAR_INT, value.ordinal());
}

View File

@ -7,14 +7,17 @@ import org.jetbrains.annotations.NotNull;
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
public record ClientUseItemPacket(@NotNull Player.Hand hand, int sequence) implements ClientPacket {
public record ClientUseItemPacket(@NotNull Player.Hand hand, int sequence, float yaw, float pitch) implements ClientPacket {
public ClientUseItemPacket(@NotNull NetworkBuffer reader) {
this(reader.readEnum(Player.Hand.class), reader.read(VAR_INT));
this(reader.readEnum(Player.Hand.class), reader.read(VAR_INT),
reader.read(NetworkBuffer.FLOAT), reader.read(NetworkBuffer.FLOAT));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.writeEnum(Player.Hand.class, hand);
writer.write(VAR_INT, sequence);
writer.write(NetworkBuffer.FLOAT, yaw);
writer.write(NetworkBuffer.FLOAT, pitch);
}
}

View File

@ -33,6 +33,8 @@ public final class ServerPacketIdentifier {
public static final int CONFIGURATION_UPDATE_ENABLED_FEATURES = nextConfigurationId();
public static final int CONFIGURATION_TAGS = nextConfigurationId();
public static final int CONFIGURATION_SELECT_KNOWN_PACKS = nextConfigurationId();
public static final int CONFIGURATION_CUSTOM_REPORT_DETAILS = nextConfigurationId();
public static final int CONFIGURATION_SERVER_LINKS = nextConfigurationId();
public static final int BUNDLE = nextPlayId();
public static final int SPAWN_ENTITY = nextPlayId();
@ -156,6 +158,8 @@ public final class ServerPacketIdentifier {
public static final int DECLARE_RECIPES = nextPlayId();
public static final int TAGS = nextPlayId();
public static final int PROJECTILE_POWER = nextPlayId();
public static final int CUSTOM_REPORT_DETAILS = nextPlayId();
public static final int SERVER_LINKS = nextPlayId();
private static int nextStatusId() {
return STATUS_ID.getAndIncrement();

View File

@ -0,0 +1,37 @@
package net.minestom.server.network.packet.server.common;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public record CustomReportDetailsPacket(
@NotNull Map<String, String> details
) implements ServerPacket.Configuration, ServerPacket.Play {
private static final int MAX_DETAILS = 32;
public CustomReportDetailsPacket {
details = Map.copyOf(details);
}
public CustomReportDetailsPacket(@NotNull NetworkBuffer reader) {
this(reader.readMap(NetworkBuffer.STRING, NetworkBuffer.STRING, MAX_DETAILS));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.writeMap(NetworkBuffer.STRING, NetworkBuffer.STRING, details);
}
@Override
public int configurationId() {
return ServerPacketIdentifier.CONFIGURATION_CUSTOM_REPORT_DETAILS;
}
@Override
public int playId() {
return ServerPacketIdentifier.CUSTOM_REPORT_DETAILS;
}
}

View File

@ -0,0 +1,97 @@
package net.minestom.server.network.packet.server.common;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public record ServerLinksPacket(@NotNull List<Entry> entries) implements ServerPacket.Configuration, ServerPacket.Play {
private static final int MAX_ENTRIES = 100;
public ServerLinksPacket {
entries = List.copyOf(entries);
}
public ServerLinksPacket(@NotNull Entry... entries) {
this(List.of(entries));
}
public ServerLinksPacket(@NotNull NetworkBuffer reader) {
this(reader.read(Entry.LIST_NETWORK_TYPE));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(Entry.LIST_NETWORK_TYPE, entries);
}
@Override
public int configurationId() {
return ServerPacketIdentifier.CONFIGURATION_SERVER_LINKS;
}
@Override
public int playId() {
return ServerPacketIdentifier.SERVER_LINKS;
}
public record Entry(@Nullable KnownLinkType knownType, @Nullable Component customType, @NotNull String link) {
public static final NetworkBuffer.Type<Entry> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, Entry value) {
buffer.write(NetworkBuffer.BOOLEAN, value.knownType != null);
if (value.knownType != null) {
buffer.write(KnownLinkType.NETWORK_TYPE, value.knownType);
} else {
assert value.customType != null;
buffer.write(NetworkBuffer.COMPONENT, value.customType);
}
buffer.write(NetworkBuffer.STRING, value.link);
}
@Override
public Entry read(@NotNull NetworkBuffer buffer) {
boolean known = buffer.read(NetworkBuffer.BOOLEAN);
if (known) {
return new Entry(buffer.read(KnownLinkType.NETWORK_TYPE), buffer.read(NetworkBuffer.STRING));
} else {
return new Entry(buffer.read(NetworkBuffer.COMPONENT), buffer.read(NetworkBuffer.STRING));
}
}
};
public static final NetworkBuffer.Type<List<Entry>> LIST_NETWORK_TYPE = NETWORK_TYPE.list(MAX_ENTRIES);
public Entry {
Check.argCondition(knownType == null && customType == null, "One of knownType and customType must be present");
Check.argCondition(knownType != null && customType != null, "Only one of knownType and customType may be present");
}
public Entry(@NotNull KnownLinkType type, @NotNull String link) {
this(type, null, link);
}
public Entry(@NotNull Component type, @NotNull String link) {
this(null, type, link);
}
}
public enum KnownLinkType {
BUG_REPORT,
COMMUNITY_GUIDELINES,
SUPPORT,
STATUS,
FEEDBACK,
COMMUNITY,
WEBSITE,
FORUMS,
NEWS,
ANNOUNCEMENTS;
public static final NetworkBuffer.Type<KnownLinkType> NETWORK_TYPE = NetworkBuffer.Enum(KnownLinkType.class);
}
}

View File

@ -1,65 +1,30 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.entity.attribute.Attribute;
import net.minestom.server.entity.attribute.AttributeInstance;
import net.minestom.server.entity.attribute.AttributeModifier;
import net.minestom.server.entity.attribute.AttributeOperation;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import static net.minestom.server.network.NetworkBuffer.*;
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
public record EntityAttributesPacket(int entityId, List<AttributeInstance> properties) implements ServerPacket.Play {
public record EntityAttributesPacket(int entityId, List<AttributeInstance> attributes) implements ServerPacket.Play {
public static final int MAX_ENTRIES = 1024;
public EntityAttributesPacket {
properties = List.copyOf(properties);
attributes = List.copyOf(attributes);
}
public EntityAttributesPacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.readCollection(r -> {
int id = reader.read(VAR_INT);
final Attribute attribute = Attribute.fromId(id);
Check.notNull(attribute, "Unknown attribute id: " + id);
final double value = reader.read(DOUBLE);
int modifierCount = reader.read(VAR_INT);
AttributeInstance instance = new AttributeInstance(attribute, null);
for (int i = 0; i < modifierCount; i++) {
AttributeModifier modifier = new AttributeModifier(reader.read(UUID), "", reader.read(DOUBLE), AttributeOperation.fromId(reader.read(BYTE)));
instance.addModifier(modifier);
}
return instance;
}, MAX_ENTRIES));
this(reader.read(VAR_INT), reader.readCollection(AttributeInstance.NETWORK_TYPE, MAX_ENTRIES));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(VAR_INT, entityId);
writer.write(VAR_INT, properties.size());
for (AttributeInstance instance : properties) {
final Attribute attribute = instance.getAttribute();
writer.write(VAR_INT, attribute.id());
writer.write(DOUBLE, instance.getBaseValue());
{
Collection<AttributeModifier> modifiers = instance.getModifiers();
writer.write(VAR_INT, modifiers.size());
for (var modifier : modifiers) {
writer.write(UUID, modifier.getId());
writer.write(DOUBLE, modifier.getAmount());
writer.write(BYTE, (byte) modifier.getOperation().getId());
}
}
}
writer.writeCollection(AttributeInstance.NETWORK_TYPE, attributes);
}
@Override

View File

@ -1,23 +1,22 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Point;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import org.jetbrains.annotations.NotNull;
public record ProjectilePowerPacket(
int entityId, @NotNull Point power
int entityId, double accelerationPower
) implements ServerPacket.Play {
public ProjectilePowerPacket(@NotNull NetworkBuffer buffer) {
this(buffer.read(NetworkBuffer.VAR_INT), buffer.read(NetworkBuffer.VECTOR3D));
this(buffer.read(NetworkBuffer.VAR_INT), buffer.read(NetworkBuffer.DOUBLE));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(NetworkBuffer.VAR_INT, entityId);
writer.write(NetworkBuffer.VECTOR3D, power);
writer.write(NetworkBuffer.DOUBLE, accelerationPower);
}
@Override

View File

@ -2,9 +2,12 @@ package net.minestom.server.registry;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.metadata.animal.tameable.WolfMeta;
import net.minestom.server.entity.metadata.other.PaintingMeta;
import net.minestom.server.instance.block.banner.BannerPattern;
import net.minestom.server.instance.block.jukebox.JukeboxSong;
import net.minestom.server.item.armor.TrimMaterial;
import net.minestom.server.item.armor.TrimPattern;
import net.minestom.server.item.enchant.Enchantment;
import net.minestom.server.message.ChatType;
import net.minestom.server.world.DimensionType;
import net.minestom.server.world.biome.Biome;
@ -34,4 +37,10 @@ public interface Registries {
@NotNull DynamicRegistry<WolfMeta.Variant> wolfVariant();
@NotNull DynamicRegistry<Enchantment> enchantment();
@NotNull DynamicRegistry<PaintingMeta.Variant> paintingVariant();
@NotNull DynamicRegistry<JukeboxSong> jukeboxSong();
}

View File

@ -22,6 +22,7 @@ import net.minestom.server.entity.EquipmentSlot;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.Material;
import net.minestom.server.message.ChatTypeDecoration;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.collection.ObjectArray;
import net.minestom.server.utils.validate.Check;
@ -67,11 +68,6 @@ public final class Registry {
return new EntityEntry(namespace, main, null);
}
@ApiStatus.Internal
public static EnchantmentEntry enchantment(String namespace, @NotNull Properties main) {
return new EnchantmentEntry(namespace, main, null);
}
@ApiStatus.Internal
public static PotionEffectEntry potionEffect(String namespace, @NotNull Properties main) {
return new PotionEffectEntry(namespace, main, null);
@ -112,6 +108,21 @@ public final class Registry {
return new ChatTypeEntry(namespace, main, null);
}
@ApiStatus.Internal
public static EnchantmentEntry enchantment(String namespace, @NotNull Properties main) {
return new EnchantmentEntry(namespace, main, null);
}
@ApiStatus.Internal
public static PaintingVariantEntry paintingVariant(String namespace, @NotNull Properties main) {
return new PaintingVariantEntry(namespace, main, null);
}
@ApiStatus.Internal
public static JukeboxSongEntry jukeboxSong(String namespace, @NotNull Properties main) {
return new JukeboxSongEntry(namespace, main, null);
}
@ApiStatus.Internal
public static Map<String, Map<String, Object>> load(Resource resource) {
Map<String, Map<String, Object>> map = new HashMap<>();
@ -242,7 +253,6 @@ public final class Registry {
BLOCKS("blocks.json"),
ITEMS("items.json"),
ENTITIES("entities.json"),
ENCHANTMENTS("enchantments.json"),
SOUNDS("sounds.json"),
COMMAND_ARGUMENTS("command_arguments.json"),
STATISTICS("custom_statistics.json"),
@ -262,7 +272,10 @@ public final class Registry {
ATTRIBUTES("attributes.json"),
BANNER_PATTERNS("banner_patterns.json"),
WOLF_VARIANTS("wolf_variants.json"),
CHAT_TYPES("chat_types.json");
CHAT_TYPES("chat_types.json"),
ENCHANTMENTS("enchantments.json"),
PAINTING_VARIANTS("painting_variants.json"),
JUKEBOX_SONGS("jukebox_songs.json");
private final String name;
@ -791,27 +804,6 @@ public final class Registry {
}
}
public record EnchantmentEntry(NamespaceID namespace, int id,
String translationKey,
double maxLevel,
boolean isCursed,
boolean isDiscoverable,
boolean isTradeable,
boolean isTreasureOnly,
Properties custom) implements Entry {
public EnchantmentEntry(String namespace, Properties main, Properties custom) {
this(NamespaceID.from(namespace),
main.getInt("id"),
main.getString("translationKey"),
main.getDouble("maxLevel"),
main.getBoolean("curse", false),
main.getBoolean("discoverable", true),
main.getBoolean("tradeable", true),
main.getBoolean("treasureOnly", false),
custom);
}
}
public record PotionEffectEntry(NamespaceID namespace, int id,
String translationKey,
int color,
@ -927,6 +919,36 @@ public final class Registry {
}
public record EnchantmentEntry(NamespaceID namespace, Properties custom) implements Entry {
public EnchantmentEntry(String namespace, Properties main, Properties custom) {
this(NamespaceID.from(namespace),
//todo
custom);
}
}
public record PaintingVariantEntry(NamespaceID namespace, NamespaceID assetId, int width, int height, Properties custom) implements Entry {
public PaintingVariantEntry(String namespace, Properties main, Properties custom) {
this(NamespaceID.from(namespace),
NamespaceID.from(main.getString("asset_id")),
main.getInt("width"),
main.getInt("height"),
custom);
}
}
public record JukeboxSongEntry(NamespaceID namespace, SoundEvent soundEvent, Component description,
float lengthInSeconds, int comparatorOutput, Properties custom) implements Entry {
public JukeboxSongEntry(String namespace, Properties main, Properties custom) {
this(NamespaceID.from(namespace),
SoundEvent.fromNamespaceId(main.getString("sound_event")),
GsonComponentSerializer.gson().deserialize(main.section("description").toString()),
(float) main.getDouble("length_in_seconds"),
main.getInt("comparator_output"),
custom);
}
}
public interface Entry {
@ApiStatus.Experimental
Properties custom();