Page MenuHomeDevCentral

No OneTemporary

diff --git a/.gitignore b/.gitignore
index 7d7f6f5..3af88f4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
.gradle
build/
plugins/**/gradle/
+plugins/suhayl/src/main/resources/resourcepack.properties
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
diff --git a/plugins/suhayl/build.gradle.kts b/plugins/suhayl/build.gradle.kts
index c332be5..d30e3f2 100644
--- a/plugins/suhayl/build.gradle.kts
+++ b/plugins/suhayl/build.gradle.kts
@@ -1,75 +1,147 @@
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.Copy
+import java.security.MessageDigest
+import java.util.Properties
+
plugins {
id("java")
}
group = "org.eu.loupsgris.quilvaryn"
version = "0.1-SNAPSHOT"
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
repositories {
mavenCentral()
maven {
name = "papermc"
url = uri("https://repo.papermc.io/repository/maven-public/")
}
}
dependencies {
testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
// Paper API (includes Bukkit + Spigot)
compileOnly("io.papermc.paper:paper-api:1.21.8-R0.1-SNAPSHOT")
// Adventure for l10n
compileOnly("net.kyori:adventure-api:4.24.0")
implementation("net.kyori:adventure-text-serializer-plain:4.24.0")
}
val promoteEnglishMessagesAsDefault by tasks.registering(Copy::class) {
from("src/main/resources/l10n/messages_en.properties")
into("src/main/resources/l10n")
rename { "messages.properties" }
}
tasks.processResources {
dependsOn(
promoteEnglishMessagesAsDefault,
)
}
+tasks.named("build") {
+ dependsOn(
+ promoteEnglishMessagesAsDefault,
+ "updateResourcePackProperties",
+ )
+}
+
+val resourcePackSourceDir = layout.projectDirectory.dir("src/main/resources/resourcepack")
+val resourcePackProperties = layout.projectDirectory.file("src/main/resources/resourcepack.properties")
+
+val resourcePackBuildDir = layout.buildDirectory.dir("resourcepack")
+val resourcePackZip = resourcePackBuildDir.get().file("suhayl.zip")
+val resourcePackSha1 = resourcePackBuildDir.get().file("suhayl.sha1")
+
+tasks.register<Zip>("zipResourcePack") {
+ from(resourcePackSourceDir)
+ archiveFileName.set("suhayl.zip")
+ destinationDirectory.set(resourcePackBuildDir)
+}
+
+tasks.register("computeResourcePackSha1") {
+ dependsOn("zipResourcePack")
+ inputs.file(resourcePackZip)
+ outputs.file(resourcePackSha1)
+
+ doLast {
+ val zipFile = resourcePackZip.asFile
+ val sha1 = MessageDigest.getInstance("SHA-1")
+ .digest(zipFile.readBytes())
+ .joinToString("") { "%02x".format(it) }
+
+ resourcePackSha1.asFile.writeText(sha1)
+ println("Resource pack SHA1: $sha1")
+ }
+}
+
+tasks.register("updateResourcePackProperties") {
+ dependsOn("computeResourcePackSha1")
+
+ doLast {
+ val sha1 = resourcePackSha1.asFile.readText().trim()
+ val propsFile = resourcePackProperties.asFile
+
+ val props = Properties().apply {
+ if (propsFile.exists()) {
+ propsFile.inputStream().use { load(it) }
+ }
+ }
+
+ props["resourcepack.url"] = "https://windriver.nasqueron.org/~minecraft/packs/suhayl.zip"
+ props["resourcepack.sha1"] = sha1
+
+ propsFile.outputStream().use { props.store(it, "Updated by Gradle") }
+
+ println("Updated ${propsFile.name} with SHA1=$sha1")
+ }
+}
+
+tasks.register<Exec>("deployResourcePack") {
+ val remoteHost = (findProperty("remoteHost") as String?) ?: "windriver.nasqueron.org"
+ val remoteUser = (findProperty("remoteUser") as String?) ?: System.getenv("USER") ?: "deploy"
+ val remoteDir = (findProperty("remoteResourcePackDir") as String?) ?: "/var/home-wwwroot/minecraft/packs/"
+
+ dependsOn("updateResourcePackProperties")
+ val zipFile = resourcePackZip.asFile
+ commandLine("scp", zipFile.absolutePath, "$remoteUser@$remoteHost:$remoteDir")
+}
+
tasks.register<Exec>("deploy") {
group = "deployment"
description = "SCP the built JAR to windriver.nasqueron.org (configurable via -PremoteUser and -PremoteDir)."
dependsOn(
tasks.named("build"),
tasks.named("jar"),
+ tasks.named("deployResourcePack"),
)
val remoteHost = (findProperty("remoteHost") as String?) ?: "windriver.nasqueron.org"
val remoteUser = (findProperty("remoteUser") as String?) ?: System.getenv("USER") ?: "deploy"
val remoteDir = (findProperty("remoteDir") as String?) ?: ""
// Resolve the jar file produced by the 'jar' task
val jarTask = tasks.named<Jar>("jar").get()
val jarFileProvider = jarTask.archiveFile
doFirst {
val jarFile = jarFileProvider.get().asFile
if (!jarFile.exists()) {
throw GradleException("JAR not found at ${'$'}{jarFile.absolutePath}. Try running './gradlew build' first.")
}
commandLine("scp", jarFile.absolutePath, "$remoteUser@$remoteHost:$remoteDir")
}
}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/SuhaylPlugin.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/SuhaylPlugin.java
index 26c2b33..e87d5c1 100644
--- a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/SuhaylPlugin.java
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/SuhaylPlugin.java
@@ -1,83 +1,88 @@
package org.eu.loupsgris.quilvaryn;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.eu.loupsgris.quilvaryn.config.SuhaylConfig;
import org.eu.loupsgris.quilvaryn.config.SuhaylTranslationRegistry;
import org.eu.loupsgris.quilvaryn.items.CommandmentStick;
-import org.eu.loupsgris.quilvaryn.listeners.HappyGhastBehavior;
-import org.eu.loupsgris.quilvaryn.listeners.OptimizedWeather;
-import org.eu.loupsgris.quilvaryn.listeners.WanderingTraderBehavior;
+import org.eu.loupsgris.quilvaryn.items.Quill;
+import org.eu.loupsgris.quilvaryn.listeners.*;
import org.eu.loupsgris.quilvaryn.services.WanderingTraderService;
import org.eu.loupsgris.quilvaryn.utils.ResourceLoader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class SuhaylPlugin extends JavaPlugin {
public SuhaylConfig config;
public static final String NAMESPACE = "suhayl";
@Override
public void onEnable() {
config = loadConfig();
loadTranslationRegistry();
// Register features
Bukkit.getPluginManager().registerEvents(new OptimizedWeather(this), this);
Bukkit.getPluginManager().registerEvents(new HappyGhastBehavior(this), this);
registerCommandmentStick();
+ registerQuill();
}
private SuhaylConfig loadConfig() {
File configFile = new File(getDataFolder(), "config.yml");
if (!configFile.exists()) {
return SuhaylConfig.byDefault();
}
getLogger().info("Loading custom " + configFile.getName());
return SuhaylConfig.Load(this.getConfig());
}
private void loadTranslationRegistry() {
ResourceLoader loader = path -> {
InputStream stream = this.getResource(path);
if (stream == null) {
throw new FileNotFoundException(path);
}
return stream;
};
SuhaylTranslationRegistry registry = new SuhaylTranslationRegistry(
getLogger(),
loader
);
registry.load();
}
private void registerCommandmentStick() {
WanderingTraderService service = new WanderingTraderService(config, getLogger());
WanderingTraderBehavior listener = new WanderingTraderBehavior(service);
Bukkit.getPluginManager().registerEvents(listener, this);
Bukkit.addRecipe(CommandmentStick.getRecipe());
}
+ private void registerQuill() {
+ Bukkit.getPluginManager().registerEvents(new QuillBehavior(), this);
+ Bukkit.addRecipe(Quill.getRecipe());
+ }
+
@Override
public void onDisable() {
getLogger().info("Suhayl quality of life plugin disabled.");
}
}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/SuhaylMessages.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/SuhaylMessages.java
index a6b1923..4c3bb84 100644
--- a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/SuhaylMessages.java
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/SuhaylMessages.java
@@ -1,21 +1,27 @@
package org.eu.loupsgris.quilvaryn.config;
+import org.bukkit.entity.Player;
+
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
public class SuhaylMessages {
public static final String BUNDLE_BASENAME = "l10n.messages";
public static String get(String key, Locale locale) {
try {
ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASENAME, locale);
return bundle.getString(key);
} catch (MissingResourceException e) {
return "#" + key + "#";
}
}
+ public static String get(String key, Player player) {
+ return get(key, player.locale());
+ }
+
}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/items/Quill.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/items/Quill.java
new file mode 100644
index 0000000..8777f39
--- /dev/null
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/items/Quill.java
@@ -0,0 +1,150 @@
+package org.eu.loupsgris.quilvaryn.items;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+
+import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.Sound;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.ShapedRecipe;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.bukkit.persistence.PersistentDataType;
+
+import org.eu.loupsgris.quilvaryn.SuhaylPlugin;
+import org.eu.loupsgris.quilvaryn.config.SuhaylMessages;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+
+public class Quill {
+
+ public static final String ITEM_TAG = "is_quill";
+
+ public static final String DURABILITY_TAG = "durability";
+ public static final int MAX_DURABILITY = 16;
+
+ /**
+ * Create the Quill item.
+ */
+ public static ItemStack getItem() {
+ ItemStack item = new ItemStack(Material.FEATHER, 1);
+
+ item.editMeta(meta -> {
+ meta.displayName(Component.translatable("item.quill.name"));
+
+ meta.lore(List.of(
+ Component.translatable("item.quill.lore1").color(NamedTextColor.GRAY),
+ Component.translatable("item.quill.lore2").color(NamedTextColor.GRAY)
+ ));
+
+ PersistentDataContainer dataContainer = meta.getPersistentDataContainer();
+ NamespacedKey key = new NamespacedKey(SuhaylPlugin.NAMESPACE, ITEM_TAG);
+ dataContainer.set(key, PersistentDataType.BOOLEAN, true);
+
+ meta.setMaxStackSize(1);
+ });
+
+ setDurability(item, MAX_DURABILITY);
+
+ return item;
+ }
+
+ public static boolean isItem(ItemStack item) {
+ if (item.getType() != Material.FEATHER || !item.hasItemMeta()) {
+ return false;
+ }
+
+ ItemMeta meta = item.getItemMeta();
+ PersistentDataContainer pdc = meta.getPersistentDataContainer();
+
+ NamespacedKey key = new NamespacedKey(SuhaylPlugin.NAMESPACE, ITEM_TAG);
+ return
+ pdc.has(key, PersistentDataType.BOOLEAN)
+ &&
+ pdc.get(key, PersistentDataType.BOOLEAN);
+ }
+
+ public static ShapedRecipe getRecipe() {
+ NamespacedKey key = new NamespacedKey(SuhaylPlugin.NAMESPACE, "quill");
+ ItemStack quill = getItem();
+
+ ShapedRecipe recipe = new ShapedRecipe(key, quill);
+ recipe.shape(
+ " F ",
+ " I ",
+ " "
+ );
+ recipe.setIngredient('F', Material.FEATHER);
+ recipe.setIngredient('I', Material.INK_SAC);
+
+ return recipe;
+ }
+
+ ///
+ /// Durability
+ ///
+
+ private static Optional<Integer> getDurability(ItemStack item) {
+ try {
+ PersistentDataContainer dataContainer = item.getItemMeta().getPersistentDataContainer();
+
+ NamespacedKey durabilityKey = new NamespacedKey(SuhaylPlugin.NAMESPACE, DURABILITY_TAG);
+ int durability = dataContainer.get(durabilityKey, PersistentDataType.INTEGER);
+
+ return Optional.of(durability);
+ } catch (NullPointerException ex) {
+ return Optional.empty();
+ }
+ }
+
+ private static void setDurability(ItemStack item, int durability) {
+ item.editMeta(meta -> {
+ PersistentDataContainer dataContainer = meta.getPersistentDataContainer();
+
+ NamespacedKey durabilityKey = new NamespacedKey(SuhaylPlugin.NAMESPACE, DURABILITY_TAG);
+ dataContainer.set(durabilityKey, PersistentDataType.INTEGER, durability);
+ });
+ }
+
+ public static void consumeDurability(ItemStack item, Player player) {
+ var optionalDurability = getDurability(item);
+ if (optionalDurability.isEmpty()) {
+ return;
+ }
+
+ int durability = optionalDurability.get() - 1;
+
+ if (durability > 0) {
+ setDurability(item, durability);
+ } else {
+ // Break item
+ breakItem(player, item);
+ }
+ }
+
+ private static void breakItem(Player player, ItemStack item) {
+ item.setAmount(0);
+
+ player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1f, 1f);
+
+ if (canRecycleFeather()) {
+ player.getInventory().addItem(new ItemStack(Material.FEATHER));
+ player.sendMessage(Component.text(SuhaylMessages.get("item.quill.break.recycled", player))
+ .color(NamedTextColor.GRAY));
+ } else {
+ player.sendMessage(Component.text(SuhaylMessages.get("item.quill.break.normal", player))
+ .color(NamedTextColor.GRAY));
+ }
+ }
+
+ private static Boolean canRecycleFeather () {
+ Random random = new Random();
+
+ return random.nextInt(4) == 0;
+ }
+
+}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/listeners/QuillBehavior.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/listeners/QuillBehavior.java
new file mode 100644
index 0000000..5bb5518
--- /dev/null
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/listeners/QuillBehavior.java
@@ -0,0 +1,143 @@
+package org.eu.loupsgris.quilvaryn.listeners;
+
+import io.papermc.paper.dialog.Dialog;
+import io.papermc.paper.registry.data.dialog.ActionButton;
+import io.papermc.paper.registry.data.dialog.DialogBase;
+import io.papermc.paper.registry.data.dialog.action.DialogAction;
+import io.papermc.paper.registry.data.dialog.action.DialogActionCallback;
+import io.papermc.paper.registry.data.dialog.input.DialogInput;
+import io.papermc.paper.registry.data.dialog.type.DialogType;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.event.ClickCallback;
+import net.kyori.adventure.text.format.NamedTextColor;
+
+import org.bukkit.block.BlockState;
+import org.bukkit.block.Container;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+
+import org.eu.loupsgris.quilvaryn.config.SuhaylMessages;
+import org.eu.loupsgris.quilvaryn.items.Quill;
+
+import java.util.List;
+import java.util.Locale;
+
+public class QuillBehavior implements Listener {
+
+ ///
+ /// Events
+ ///
+
+ @EventHandler
+ public void onQuillUse(PlayerInteractEvent event) {
+ if (!event.getAction().isRightClick() || event.getClickedBlock() == null) {
+ return;
+ }
+
+ if (event.getHand() != EquipmentSlot.HAND) {
+ return;
+ }
+
+ Player player = event.getPlayer();
+ ItemStack item = event.getItem();
+
+ if (item == null || !Quill.isItem(item)) {
+ return;
+ }
+
+ BlockState state = event.getClickedBlock().getState();
+ if (!(state instanceof Container container)) {
+ return;
+ }
+
+ InventoryType containerType = container.getInventory().getType();
+ if (!isValidInventoryType(containerType)) {
+ return;
+ }
+
+ event.setCancelled(true);
+ startQuillDialog(player, item, container);
+ }
+
+ ///
+ /// Dialog API
+ ///
+
+ private void startQuillDialog(Player player, ItemStack item, Container container) {
+ Locale locale = player.locale();
+
+ Component title = Component.text(SuhaylMessages.get("dialog.rename_container.title", locale))
+ .color(NamedTextColor.GOLD);
+
+ Component inputLabel = Component.text(SuhaylMessages.get("dialog.rename_container.input.label", locale))
+ .color(NamedTextColor.GRAY);
+
+ Component confirmButton = Component.text(SuhaylMessages.get("dialog.generic.button.confirm", locale))
+ .color(NamedTextColor.GREEN);
+ Component cancelButton = Component.text(SuhaylMessages.get("dialog.generic.button.cancel", locale))
+ .color(NamedTextColor.GRAY);
+
+ Dialog dialog = Dialog.create(builder -> builder.empty()
+ .base(DialogBase.builder(title)
+ .inputs(List.of(
+ DialogInput.text("label", inputLabel)
+ .build()
+ ))
+ .build()
+ )
+ .type(DialogType.confirmation(
+ ActionButton.create(
+ confirmButton,
+ null,
+ 100,
+ DialogAction.customClick(
+ updateContainerLabel(player, item, container),
+ ClickCallback.Options.builder()
+ .uses(1)
+ .lifetime(ClickCallback.DEFAULT_LIFETIME)
+ .build()
+ )
+ ),
+ ActionButton.create(
+ cancelButton,
+ null,
+ 100,
+ null // closes the dialog
+ )
+ ))
+ );
+
+ player.showDialog(dialog);
+ }
+
+ private static DialogActionCallback updateContainerLabel(Player player, ItemStack item, Container container) {
+ return (view, audience) -> {
+ String label = view.getText("label");
+
+ if (audience instanceof Player && label != null) {
+ container.customName(Component.text(label));
+ container.update();
+
+ Quill.consumeDurability(item, player);
+ }
+ };
+ }
+
+ ///
+ /// Helper methods
+ ///
+
+ private boolean isValidInventoryType(InventoryType type) {
+ return switch (type) {
+ case CHEST, BARREL, SHULKER_BOX -> true;
+ default -> false;
+ };
+ }
+
+}
diff --git a/plugins/suhayl/src/main/resources/l10n/messages.properties b/plugins/suhayl/src/main/resources/l10n/messages.properties
index c4663c6..5ebc097 100644
--- a/plugins/suhayl/src/main/resources/l10n/messages.properties
+++ b/plugins/suhayl/src/main/resources/l10n/messages.properties
@@ -1,13 +1,22 @@
item.commandment_stick.name=Commandment Stick
item.commandment_stick.lore1=Right-click a Wandering Trader
item.commandment_stick.lore2=to give them instructions.
wandering_trader_menu.title=Trader Etiquette
wandering_trader_menu.options.leave=All business is done, you can leave.
wandering_trader_menu.options.banish=Come back later. No more trader this week.
wandering_trader_menu.options.silence=Shhh! Be quiet.
wandering_trader_menu.actions.left=The trader nods and drifts away...
wandering_trader_menu.actions.ban=Wandering traders are discouraged from visiting for a while.
wandering_trader_menu.actions.silenced=The trader goes quiet.
wandering_trader_menu.actions.unsilenced=The trader finds their voice again.
+
+dialog.generic.button.confirm=Confirm
+dialog.generic.button.cancel=Cancel
+
+dialog.rename_container.title=Write a label
+dialog.rename_container.input.label=Label
+
+item.quill.break.recycled=✒ The quill’s ink fades away, leaving only a feather.
+item.quill.break.normal=✒ The quill is torn and can’t be used anymore.
diff --git a/plugins/suhayl/src/main/resources/l10n/messages_en.properties b/plugins/suhayl/src/main/resources/l10n/messages_en.properties
index c4663c6..5ebc097 100644
--- a/plugins/suhayl/src/main/resources/l10n/messages_en.properties
+++ b/plugins/suhayl/src/main/resources/l10n/messages_en.properties
@@ -1,13 +1,22 @@
item.commandment_stick.name=Commandment Stick
item.commandment_stick.lore1=Right-click a Wandering Trader
item.commandment_stick.lore2=to give them instructions.
wandering_trader_menu.title=Trader Etiquette
wandering_trader_menu.options.leave=All business is done, you can leave.
wandering_trader_menu.options.banish=Come back later. No more trader this week.
wandering_trader_menu.options.silence=Shhh! Be quiet.
wandering_trader_menu.actions.left=The trader nods and drifts away...
wandering_trader_menu.actions.ban=Wandering traders are discouraged from visiting for a while.
wandering_trader_menu.actions.silenced=The trader goes quiet.
wandering_trader_menu.actions.unsilenced=The trader finds their voice again.
+
+dialog.generic.button.confirm=Confirm
+dialog.generic.button.cancel=Cancel
+
+dialog.rename_container.title=Write a label
+dialog.rename_container.input.label=Label
+
+item.quill.break.recycled=✒ The quill’s ink fades away, leaving only a feather.
+item.quill.break.normal=✒ The quill is torn and can’t be used anymore.
diff --git a/plugins/suhayl/src/main/resources/l10n/messages_fr.properties b/plugins/suhayl/src/main/resources/l10n/messages_fr.properties
index 29b103b..602ef11 100644
--- a/plugins/suhayl/src/main/resources/l10n/messages_fr.properties
+++ b/plugins/suhayl/src/main/resources/l10n/messages_fr.properties
@@ -1,13 +1,22 @@
item.commandment_stick.name=Bâton de commandement
item.commandment_stick.lore1=Permet de donner des instructions
item.commandment_stick.lore2=aux marchands ambulants
wandering_trader_menu.title=Marchand ambulant
wandering_trader_menu.options.leave=Toutes les affaires sont terminées, vous pouvez partir.
wandering_trader_menu.options.banish=Revenez plus tard, pas de marchand cette semaine.
wandering_trader_menu.options.silence=Chut ... silence !
wandering_trader_menu.actions.left=Le marchand hoche la tête et s'éloigne ...
wandering_trader_menu.actions.ban=Les marchands ambulants sont découragés de nous rendre visite cette semaine.
wandering_trader_menu.actions.silenced=§7Le marchand garde le silence.
wandering_trader_menu.actions.unsilenced=§7Le marchand parle à nouveau.
+
+dialog.generic.button.confirm=Écrire
+dialog.generic.button.cancel=Annuler
+
+dialog.rename_container.title=Inscription
+dialog.rename_container.input.label=Texte
+
+item.quill.break.recycled=✒ L’encre s’estompe doucement, ne subsiste qu’une plume.
+item.quill.break.normal=✒ La plume se brise et ne peut plus être utilisée.
diff --git a/plugins/suhayl/src/main/resources/resourcepack/assets/suhayl/lang/en_us.json b/plugins/suhayl/src/main/resources/resourcepack/assets/suhayl/lang/en_us.json
new file mode 100644
index 0000000..1fcf6d6
--- /dev/null
+++ b/plugins/suhayl/src/main/resources/resourcepack/assets/suhayl/lang/en_us.json
@@ -0,0 +1,5 @@
+{
+ "item.quill.name": "Quill",
+ "item.quill.lore1": "Right-click a container",
+ "item.quill.lore2": "to label it."
+}
diff --git a/plugins/suhayl/src/main/resources/resourcepack/assets/suhayl/lang/fr_fr.json b/plugins/suhayl/src/main/resources/resourcepack/assets/suhayl/lang/fr_fr.json
new file mode 100644
index 0000000..c3d256c
--- /dev/null
+++ b/plugins/suhayl/src/main/resources/resourcepack/assets/suhayl/lang/fr_fr.json
@@ -0,0 +1,5 @@
+{
+ "item.quill.name": "Plume",
+ "item.quill.lore1": "Permet d'écrire sur",
+ "item.quill.lore2": "un coffre ou un tonneau."
+}
diff --git a/plugins/suhayl/src/main/resources/resourcepack/pack.mcmeta b/plugins/suhayl/src/main/resources/resourcepack/pack.mcmeta
new file mode 100644
index 0000000..3032c21
--- /dev/null
+++ b/plugins/suhayl/src/main/resources/resourcepack/pack.mcmeta
@@ -0,0 +1,6 @@
+{
+ "pack": {
+ "pack_format": 64,
+ "description": "Localisation for Quilvaryn server quality of life tweaks."
+ }
+}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Oct 12, 09:15 (5 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3065639
Default Alt Text
(25 KB)

Event Timeline