Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
192b409
chore: update gradlew and dependencies for MC 1.21.4
Sylfare Jan 25, 2025
77c80b6
feat: use gson for json parsing
Sylfare Jan 25, 2025
6b6789c
chore: update Minecraft to 1.21.5
Sylfare Apr 17, 2025
a7327ae
refactor: started refactoring JSON deserializers with Jackson
Sylfare Apr 18, 2025
bad90cd
chore: update Minecraft to 1.21.8 + gradlew
Sylfare Jul 19, 2025
5573cd1
refactor: use Jackson to deserialize items
Sylfare Jul 19, 2025
7fa91fb
refactor: code cleaning
Sylfare Jul 19, 2025
a366abb
feature: add custom item id to the final ItemStack
Sylfare Jul 19, 2025
1029bdb
feature: NamedspacedKey parser + maxStackSize and itemModel component…
Sylfare Jul 19, 2025
6a18d1f
chore: removed file from test server
Sylfare Jul 19, 2025
dd8db69
feature: also use json for recipes
Sylfare Jul 19, 2025
65d6a27
feature: started Equippable deserializer
Sylfare Jul 20, 2025
7698e59
feature: tool rules
Sylfare Jul 20, 2025
2c6dd49
feature: glider, enchantment glint override, rarity and jukebox playa…
Sylfare Jul 20, 2025
ffb9f29
feature: food + consumable components, and item deserializer
Sylfare Jul 20, 2025
eba0c4a
fix: only get items after loading, to allow "nesting"
Sylfare Jul 20, 2025
4c571c3
feature: death protection, consume effect, potion and potion type des…
Sylfare Jul 21, 2025
bbfe7eb
feature: add consumable effects in consumable deserializer
Sylfare Jul 21, 2025
9c3c62d
feature: dyed color and instrument components + color derserializer
Sylfare Jul 21, 2025
3a0c676
feature: profile and enchantable components
Sylfare Sep 13, 2025
f332fb9
refactor: remove unused classes
Sylfare Sep 13, 2025
b04a226
refactor: normalize Parsers names
Sylfare Sep 13, 2025
1c1ed9d
refactor: disable recipe logs, for now
Sylfare Sep 13, 2025
959d142
refactor: CustomItemDeserializer - sort component alphabetically
Sylfare Sep 13, 2025
7f87b1e
feature: repairCost, tooltipStyle and unbreakable components
Sylfare Sep 13, 2025
c19d01e
feature: attributes component
Sylfare Sep 14, 2025
135472c
fix: set equipment slot in attribute builder instead of AttributeModi…
Sylfare Sep 14, 2025
ac13690
chore: update to MC 1.21.10
Sylfare Oct 14, 2025
4a0fede
feature: baseColor and customModelData components
Sylfare Oct 14, 2025
ae39111
refactor: shadow jackson in plugin + dependencies version bump
Sylfare May 17, 2026
88198f2
refactor: cleaning unused code
Sylfare May 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Ignore Gradle project-specific cache directory
.gradle
.gradle/

# Ignore Gradle build output directory
build
.vscode
bin
bin

.idea/
run/
30 changes: 18 additions & 12 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This is a general purpose Gradle build.
* To learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.8/samples
*/

plugins {
`java-library`
id("io.papermc.paperweight.userdev") version "1.7.1"
alias { libs.plugins.paperweight }
alias { libs.plugins.runPaper }
alias { libs.plugins.shadow }
}

repositories {
Expand All @@ -20,12 +15,23 @@ repositories {
}

dependencies {
compileOnly("com.mojang:brigadier:1.0.18")
implementation("commons-io:commons-io:2.6")
paperweight.paperDevBundle("1.21-R0.1-SNAPSHOT")
implementation("net.kyori:adventure-text-minimessage:4.17.0")
paperweight.paperDevBundle(libs.versions.paper)
compileOnly(libs.brigadier)
implementation(libs.commonsIo)
implementation(libs.miniMessage)
compileOnly(libs.lombok)
annotationProcessor(libs.lombok)
implementation(libs.jackson)
}

java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}

tasks.shadowJar {
dependencies {
include(dependency("tools.jackson.core:jackson-databind"))
include(dependency("tools.jackson.core:jackson-core"))
include(dependency("com.fasterxml.jackson.core:jackson-annotations"))
}
}
22 changes: 22 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,24 @@
# This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
[versions]
paper = "1.21.11-R0.1-SNAPSHOT"
paperweight = "2.0.0-beta.18"
brigadier = "1.0.500"
runPaper = "3.0.0-beta.1"
lombok = "1.18.42"
adventure = "5.1.1"
commonsIo = "2.22.0"
jackson = "3.1.3"
shadow = "9.3.0"

[libraries]
brigadier = {group = "com.mojang", name = "brigadier", version.ref = "brigadier"}
lombok = {group = "org.projectlombok", name = "lombok", version.ref = "lombok"}
miniMessage = {group = "net.kyori", name = "adventure-text-minimessage", version.ref = "adventure"}
commonsIo = {group = "commons-io", name = "commons-io", version.ref = "commonsIo"}
jackson = {group = "tools.jackson.core", name = "jackson-databind", version.ref = "jackson"}

[plugins]
paperweight = { id = "io.papermc.paperweight.userdev", version.ref = "paperweight"}
runPaper = { id = "xyz.jpenilla.run-paper", version.ref="runPaper"}
shadow = { id = "com.gradleup.shadow", version.ref="shadow" }
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
10 changes: 6 additions & 4 deletions gradlew

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions gradlew.bat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

153 changes: 124 additions & 29 deletions src/main/java/re/sylfa/itemcreator/ItemCreator.java
Original file line number Diff line number Diff line change
@@ -1,86 +1,181 @@
package re.sylfa.itemcreator;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.destroystokyo.paper.profile.ProfileProperty;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.datacomponent.item.Consumable;
import io.papermc.paper.datacomponent.item.CustomModelData;
import io.papermc.paper.datacomponent.item.DeathProtection;
import io.papermc.paper.datacomponent.item.Enchantable;
import io.papermc.paper.datacomponent.item.ItemAttributeModifiers;
import io.papermc.paper.datacomponent.item.ResolvableProfile;
import io.papermc.paper.datacomponent.item.attribute.AttributeModifierDisplay;
import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import lombok.Getter;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.MusicInstrument;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.meta.components.EquippableComponent;
import org.bukkit.inventory.meta.components.FoodComponent;
import org.bukkit.inventory.meta.components.JukeboxPlayableComponent;
import org.bukkit.inventory.meta.components.ToolComponent;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.permissions.CommandPermissions;

import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import org.checkerframework.checker.nullness.qual.NonNull;
import re.sylfa.itemcreator.commands.ItemCreatorCommand;
import re.sylfa.itemcreator.deserializers.components.AttributeModifiersDeserializer;
import re.sylfa.itemcreator.deserializers.components.ConsumableDeserializer;
import re.sylfa.itemcreator.deserializers.components.ConsumeEffectDeserializer;
import re.sylfa.itemcreator.deserializers.components.CustomModelDataDeserializer;
import re.sylfa.itemcreator.deserializers.components.DeathProtectionDeserializer;
import re.sylfa.itemcreator.deserializers.components.EnchantableDeserializer;
import re.sylfa.itemcreator.deserializers.components.EquippableDeserializer;
import re.sylfa.itemcreator.deserializers.components.FoodDeserializer;
import re.sylfa.itemcreator.deserializers.components.JukeboxPlayableDeserializer;
import re.sylfa.itemcreator.deserializers.components.MusicInstrumentDeserializer;
import re.sylfa.itemcreator.deserializers.components.PotionEffectDeserializer;
import re.sylfa.itemcreator.deserializers.components.PotionEffectTypeDeserializer;
import re.sylfa.itemcreator.deserializers.components.ProfileDeserializer;
import re.sylfa.itemcreator.deserializers.components.ToolDeserializer;
import re.sylfa.itemcreator.deserializers.components.ToolRuleDeserializer;
import re.sylfa.itemcreator.deserializers.types.ColorDeserializer;
import re.sylfa.itemcreator.deserializers.types.CustomItemDeserializer;
import re.sylfa.itemcreator.deserializers.types.ItemDeserializer;
import re.sylfa.itemcreator.deserializers.types.ItemKeyDeserializer;
import re.sylfa.itemcreator.deserializers.types.KeyDeserializer;
import re.sylfa.itemcreator.deserializers.types.MaterialDeserializer;
import re.sylfa.itemcreator.deserializers.types.NamespacedKeyDeserializer;
import re.sylfa.itemcreator.deserializers.types.TextComponentDeserializer;
import re.sylfa.itemcreator.items.CustomItem;
import re.sylfa.itemcreator.items.ItemKey;
import re.sylfa.itemcreator.items.ItemReader;
import re.sylfa.itemcreator.items.ItemRegistry;
import re.sylfa.itemcreator.recipes.CustomRecipe;
import re.sylfa.itemcreator.recipes.RecipeReader;
import re.sylfa.itemcreator.recipes.RecipeRegistry;
import re.sylfa.itemcreator.util.Log;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.module.SimpleModule;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ItemCreator extends JavaPlugin {


@Getter
private static ItemCreator instance;
private static ItemRegistry itemRegistry = new ItemRegistry();
private static RecipeRegistry recipeRegistry = new RecipeRegistry();
@Getter
private static final ItemRegistry itemRegistry = new ItemRegistry();
@Getter
private static final RecipeRegistry recipeRegistry = new RecipeRegistry();

@Getter
private static ObjectMapper mapper;


@Override
public void onEnable() {
instance = this;
Log.log("Enabled!");
registerMappers();

init();
registerPermissions();
registerCommands();
}

public static ItemCreator getInstance() {
return instance;
}

public static ItemRegistry getItemRegistry() {
return itemRegistry;
}

public static RecipeRegistry getRecipeRegistry() {
return recipeRegistry;
}

public void init(){
itemRegistry.removeAll();
itemRegistry.add(ItemReader.readAllItems().toArray(CustomItem[]::new));


List<CustomRecipe> readRecipes = RecipeReader.readAllRecipes();
Map<NamespacedKey, Recipe> readRecipesMap = readRecipes.stream().collect(Collectors.toMap(r -> r.key(), r -> r.asRecipe()));
recipeRegistry.getAll().keySet().forEach(key -> Log.log("Removing %s: %b", key.asString(), Bukkit.removeRecipe(key)));
Map<NamespacedKey, Recipe> readRecipesMap = readRecipes.stream()
.collect(Collectors.toMap(
CustomRecipe::key,
CustomRecipe::asRecipe
));
recipeRegistry.getAll().keySet()
.forEach(key -> {
boolean recipeRemoved = Bukkit.removeRecipe(key);
// TODO toggleable in configuration
// Log.log("Removing %s: %b", key.asString(), recipeRemoved);
}
);
recipeRegistry.removeAll();

readRecipes.forEach(recipeRegistry::add);
readRecipesMap.values().forEach(r -> Bukkit.addRecipe(r, true));
// FIXME resendRecipes = false does not work for now
readRecipesMap.values().forEach(r -> Bukkit.addRecipe(r, false));
}

public void reload() {
init();
}

public void registerPermissions() {
private void registerPermissions() {
CommandPermissions.registerPermissions(new Permission("itemcreator.give", PermissionDefault.OP));
}

public void registerCommands() {
LifecycleEventManager<Plugin> manager = this.getLifecycleManager();
private void registerCommands() {
LifecycleEventManager<@NonNull Plugin> manager = this.getLifecycleManager();
manager.registerEventHandler(LifecycleEvents.COMMANDS, event -> {
final Commands commands = event.registrar();
List.of(
new ItemCreatorCommand()
).forEach(command -> commands.register(command.command(), command.aliases()));
});
}

private void registerMappers() {

SimpleModule module = new SimpleModule();
module.addDeserializer(CustomItem.class, new CustomItemDeserializer())
.addDeserializer(ItemStack.class, new ItemDeserializer())
.addDeserializer(Material.class, new MaterialDeserializer())
.addDeserializer(Component.class, new TextComponentDeserializer())
.addDeserializer(NamespacedKey.class, new NamespacedKeyDeserializer())
.addDeserializer(EquippableComponent.class, new EquippableDeserializer())
.addDeserializer(Key.class, new KeyDeserializer())
.addDeserializer(ToolComponent.class, new ToolDeserializer())
.addDeserializer(ToolRuleDeserializer.RuleValues.class, new ToolRuleDeserializer())
.addDeserializer(JukeboxPlayableComponent.class, new JukeboxPlayableDeserializer())
.addDeserializer(Consumable.class, new ConsumableDeserializer())
.addDeserializer(FoodComponent.class, new FoodDeserializer())
.addDeserializer(ItemKey.class, new ItemKeyDeserializer())
.addDeserializer(PotionEffect.class, new PotionEffectDeserializer())
.addDeserializer(DeathProtection.class, new DeathProtectionDeserializer())
.addDeserializer(ConsumeEffect.class, new ConsumeEffectDeserializer())
.addDeserializer(PotionEffectType.class, new PotionEffectTypeDeserializer())
.addDeserializer(Color.class, new ColorDeserializer())
.addDeserializer(MusicInstrument.class, new MusicInstrumentDeserializer())
.addDeserializer(Enchantable.class, new EnchantableDeserializer())
.addDeserializer(ResolvableProfile.class, new ProfileDeserializer())
.addDeserializer(ProfileProperty.class, new ProfileDeserializer.ProfilePropertyDeserializer())
.addDeserializer(ItemAttributeModifiers.class, new AttributeModifiersDeserializer())
.addDeserializer(AttributeModifiersDeserializer.AttributeModification.class, new AttributeModifiersDeserializer.AttributeModifierDeserializer())
.addDeserializer(AttributeModifierDisplay.class, new AttributeModifiersDeserializer.AttributeModifierDisplayDeserializer())
.addDeserializer(CustomModelData.class, new CustomModelDataDeserializer())
;

mapper = JsonMapper.builder()
.addModule(module)
.build();

}
}
Loading
Loading