diff --git a/build.gradle b/build.gradle index ef50236..737dcf8 100644 --- a/build.gradle +++ b/build.gradle @@ -4,14 +4,17 @@ plugins { } group = 'fr.openmc.riftengine' -version = '0.5-SNAPSHOT' +version = '0.6-SNAPSHOT' repositories { mavenCentral() + + // * ProtocolLib + maven {url "https://repo.dmulloy2.net/repository/public/"} // * GeyserMC maven {url "https://repo.opencollab.dev/main/"} // * PaperMC - maven { url = "https://repo.papermc.io/repository/maven-public/" } + maven {url = "https://repo.papermc.io/repository/maven-public/" } // * ItemsAdder maven {url "https://maven.devs.beer/"} } @@ -20,8 +23,10 @@ dependencies { paperweight.paperDevBundle "${minecraftVersion}.build.${paperVersion}" // Dependancies + compileOnly "net.dmulloy2:ProtocolLib:${protocolLibVersion}" compileOnly "beer.devs:itemsadder-api:${itemsAdderVersion}" compileOnly "org.geysermc.geyser:api:${geyserApiVersion}" + compileOnly "org.geysermc.floodgate:api:${floodgateApiVersion}" compileOnly files("libs/OpenMC.jar") implementation "org.jetbrains:annotations:${jetbrainsAnnotationsVersion}" diff --git a/gradle.properties b/gradle.properties index 05b0013..8257d71 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,8 +6,10 @@ minecraftVersion = 26.3 paperVersion = 180-stable # Dependencies versions +protocolLibVersion = 5.4.0 itemsAdderVersion = 4.0.18-beta-10 geyserApiVersion = 2.10.0-SNAPSHOT +floodgateApiVersion = 2.2.5-SNAPSHOT jetbrainsAnnotationsVersion = 26.1.0 lombokVersion = 1.18.46 diff --git a/libs/OpenMC.jar b/libs/OpenMC.jar index 1821607..d5c2c2a 100644 Binary files a/libs/OpenMC.jar and b/libs/OpenMC.jar differ diff --git a/src/main/java/fr/openmc/riftengine/core/RiftLog.java b/src/main/java/fr/openmc/riftengine/core/RiftLog.java index 610f10c..a0b9b16 100644 --- a/src/main/java/fr/openmc/riftengine/core/RiftLog.java +++ b/src/main/java/fr/openmc/riftengine/core/RiftLog.java @@ -11,7 +11,6 @@ public enum RiftLog { IMAGE_NOT_FOUND("Image introuvable pour {} dans le path {} (skip)", LogType.ERROR), ERROR_READING("Erreur de lecture pour {} (skip) : ", LogType.ERROR), ICON_TYPE_NOT_RECOGNIZED("Icon type {} : n'est pas reconnu", LogType.ERROR), - DETECTED_AS_MENU_GUI("Glyph {} detécté comme MENU_GUI, il ne sera donc pas en glyph, vu que les menus sont géré autrement", LogType.WARN), ICON_SKIPPED("Image manquante pour {} emoji(s)/icon(s) sur {}.", LogType.INFO), DETECTED_AS("{} ({}x{}) détecté comme {}", LogType.INFO), SYMBOL_KEY_NOT_FOUND("Clé {} introuvable dans {}.", LogType.WARN), diff --git a/src/main/java/fr/openmc/riftengine/core/converter/ConverterManager.java b/src/main/java/fr/openmc/riftengine/core/converter/ConverterManager.java index 6443402..7e642f4 100644 --- a/src/main/java/fr/openmc/riftengine/core/converter/ConverterManager.java +++ b/src/main/java/fr/openmc/riftengine/core/converter/ConverterManager.java @@ -1,5 +1,6 @@ package fr.openmc.riftengine.core.converter; +import com.comphenix.protocol.ProtocolLibrary; import fr.openmc.core.OMCRegistry; import fr.openmc.core.bootstrap.integration.OMCLogger; import fr.openmc.core.utils.FilesUtils; @@ -11,6 +12,8 @@ import fr.openmc.riftengine.core.converter.writers.PackWriter; import fr.openmc.riftengine.core.converter.writers.blocks.BlocksMappingWriter; import fr.openmc.riftengine.core.converter.writers.blocks.TerrainTextureJsonWriter; +import fr.openmc.riftengine.core.converter.writers.glyph.chestgui.ChestGuiTextureWriter; +import fr.openmc.riftengine.core.converter.writers.glyph.chestgui.ChestScreenWriter; import fr.openmc.riftengine.core.converter.writers.glyph.font.FontWriter; import fr.openmc.riftengine.core.converter.writers.glyph.icons.IconsWriter; import fr.openmc.riftengine.core.converter.writers.glyph.icons.SymbolWriter; @@ -28,6 +31,7 @@ import fr.openmc.riftengine.core.converter.writers.tooltip.textures.TooltipTextureWriter; import fr.openmc.riftengine.core.converter.writers.translations.TranslationInjector; import fr.openmc.riftengine.core.converter.writers.ui.ScoreboardUiWriter; +import fr.openmc.riftengine.core.listeners.ChestGuiTitleListener; import fr.openmc.riftengine.core.resolvers.items.ItemResourceResolver; import fr.openmc.riftengine.core.resolvers.mcmeta.animation.AnimationMcMetaResolver; import fr.openmc.riftengine.core.resolvers.mcmeta.gui.GuiMcMetaResolver; @@ -74,6 +78,9 @@ public ConverterManager(RiftPlugin plugin) { register("Icônes ItemsAdder", new IconsWriter(itemsAdderContents)); register("Mappings des symboles", new SymbolWriter()); + register("Textures des Chest GUI", new ChestGuiTextureWriter()); + register("Génération du JSON UI pour les Chest GUI", new ChestScreenWriter()); + register("Textures des items", new ItemsTextureJsonWriter(items, itemResolver)); register("Fichiers de textures", new ItemsTextureWriter(items, itemResolver)); register("Mappings des items", new ItemsMappingWriter(items, itemResolver)); @@ -116,6 +123,11 @@ public Path generateConvertedPack() throws Exception { ZipUtils.unzip(javaPackPath, javaExtractDir); + ProtocolLibrary.getProtocolManager().addPacketListener( + new ChestGuiTitleListener(javaExtractDir, + getItemsAdderContents(RiftPlugin.getInstance()).getParent(), + RiftPlugin.getInstance())); + for (PackWriter writer : writers) { writer.write(bedrockBuildDir, javaExtractDir); } diff --git a/src/main/java/fr/openmc/riftengine/core/converter/writers/blocks/BlocksMappingWriter.java b/src/main/java/fr/openmc/riftengine/core/converter/writers/blocks/BlocksMappingWriter.java index deae140..8eab87e 100644 --- a/src/main/java/fr/openmc/riftengine/core/converter/writers/blocks/BlocksMappingWriter.java +++ b/src/main/java/fr/openmc/riftengine/core/converter/writers/blocks/BlocksMappingWriter.java @@ -5,11 +5,11 @@ import fr.openmc.riftengine.api.scanner.items.ItemEntry; import fr.openmc.riftengine.api.scanner.items.entry.behaviours.IABehaviour; import fr.openmc.riftengine.api.scanner.items.entry.behaviours.block.BlocksBehaviour; +import fr.openmc.riftengine.api.utils.IdentifierUtils; import fr.openmc.riftengine.core.RiftPlugin; import fr.openmc.riftengine.core.converter.writers.PackWriter; import fr.openmc.riftengine.core.resolvers.items.ItemResourceResolver; import fr.openmc.riftengine.core.resolvers.items.ResolvedItemResource; -import fr.openmc.riftengine.core.utils.IdentifierUtils; import fr.openmc.riftengine.core.utils.PathUtils; import java.nio.file.Files; diff --git a/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/chestgui/ChestGuiTextureWriter.java b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/chestgui/ChestGuiTextureWriter.java new file mode 100644 index 0000000..f87273f --- /dev/null +++ b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/chestgui/ChestGuiTextureWriter.java @@ -0,0 +1,20 @@ +package fr.openmc.riftengine.core.converter.writers.glyph.chestgui; + +import fr.openmc.riftengine.core.converter.writers.PackWriter; +import fr.openmc.riftengine.core.utils.ImageUtils; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.nio.file.Path; + +public class ChestGuiTextureWriter implements PackWriter { + @Override + public void write(Path bedrockRootPath, Path javaRootPath) throws IOException { + for (ResolvedChestGui chestGui : ChestScreenWriter.chestGuis) { + BufferedImage src = ImageUtils.read(chestGui.javaTexturePath(javaRootPath)); + Path target = bedrockRootPath.resolve(chestGui.bedrockTexturePath(javaRootPath)); + + ImageUtils.writePng(ImageUtils.center(src), target); + } + } +} diff --git a/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/chestgui/ChestScreenWriter.java b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/chestgui/ChestScreenWriter.java new file mode 100644 index 0000000..3ee86fd --- /dev/null +++ b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/chestgui/ChestScreenWriter.java @@ -0,0 +1,128 @@ +package fr.openmc.riftengine.core.converter.writers.glyph.chestgui; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import fr.openmc.core.utils.JsonUtils; +import fr.openmc.riftengine.core.converter.writers.PackWriter; +import fr.openmc.riftengine.core.utils.ImageUtils; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public class ChestScreenWriter implements PackWriter { + public static final List chestGuis = new ArrayList<>(); + private static final String OUTPUT_FILE = "ui/chest_screen.json"; + public static final String PREFIX = "rift"; + private final String namespace = "chest"; + + private final String TEMPLATE_CHEST_SCREEN = """ + { + "namespace": , + + "chest_label": { + "type": "label", + "layer": 2, + "offset": [7, -1], + "size": ["90%", "default"], + "anchor_from": "top_left", + "anchor_to": "top_left", + "text": "$container_title", + "color": "$title_text_color", + "localize": "$localize_title", + "enable_profanity_filter": true, + "$atext": "$container_title", + "visible": "($atext - ':' = $atext)" + } + } + """; + + @Override + public void write(Path bedrockRootPath, Path javaRootPath) throws IOException { + JsonObject root = JsonUtils.parseJson(TEMPLATE_CHEST_SCREEN + .replace("", namespace) + .replace("", PREFIX)); + + this.handleChestGui(javaRootPath, root); + this.handlePanelTopHalf(root); + + + Path outputFile = bedrockRootPath.resolve(OUTPUT_FILE); + this.writeJsonFile(outputFile, root); + } + + private final String TEMPLATE_CHEST_GUI = """ + { + "type": "image", + "texture": "", + "size": [, ], + "keep_ratio": false, + "offset": [, ], + "anchor_from": "top_middle", + "anchor_to": "top_middle", + "layer": 4, + "$atext": "$container_title", + "visible": "" + } + """; + + private void handleChestGui(Path javaRootPath, JsonObject root) throws IOException { + for (ResolvedChestGui chestGui : chestGuis) { + BufferedImage src = ImageUtils.read(chestGui.javaTexturePath(javaRootPath)); + BufferedImage centered = ImageUtils.center(src); + + int shift = ImageUtils.centerShiftY(src); + int offsetY = 5 - chestGui.entry().yPosition() - shift; + + int gridLeft = ImageUtils.findGridLeft(centered); + int offsetX = gridLeft == -1 ? 0 : 7 - gridLeft - (176 - centered.getWidth()) / 2; + + root.add(PREFIX + "_" + chestGui.key(), JsonUtils.parseJson(TEMPLATE_CHEST_GUI + .replace("", chestGui.bedrockTexturePath(javaRootPath).toString()) + .replace("", String.valueOf(chestGui.width())) + .replace("", String.valueOf(chestGui.height())) + .replace("", String.valueOf(offsetY)) + .replace("", String.valueOf(offsetX)) + .replace("", + "(not ($atext - '" + PREFIX + ":" + chestGui.key() + "' = $atext))"))); + } + } + + private final String TEMPLATE_PANEL_TOP_HALF = """ + { + "modifications": [ + { + "array_name": "controls", + "operation": "insert_front", + "value": [] + } + ] + } + """; + + private void handlePanelTopHalf(JsonObject root) { + JsonObject panelTopHalf = JsonUtils.parseJson(TEMPLATE_PANEL_TOP_HALF); + + JsonArray modifications = panelTopHalf.getAsJsonArray("modifications"); + + for (JsonElement modification : modifications) { + if (!(modification instanceof JsonObject obj)) continue; + + JsonArray value = obj.getAsJsonArray("value"); + + for (ResolvedChestGui chestGui : chestGuis) { + JsonObject chestGuiValue = new JsonObject(); + chestGuiValue.add(PREFIX + "_" + chestGui.key() + + "@" + namespace + "." + PREFIX + "_" + chestGui.key(), new JsonObject()); + value.add(chestGuiValue); + } + } + + for (String prefix : new String[] {"large_chest", "small_chest"}) { + root.add(prefix + "_panel_top_half", panelTopHalf); + } + } +} diff --git a/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/chestgui/ResolvedChestGui.java b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/chestgui/ResolvedChestGui.java new file mode 100644 index 0000000..ace32c7 --- /dev/null +++ b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/chestgui/ResolvedChestGui.java @@ -0,0 +1,20 @@ +package fr.openmc.riftengine.core.converter.writers.glyph.chestgui; + +import fr.openmc.riftengine.api.scanner.icons.IconEntry; +import fr.openmc.riftengine.core.utils.PathUtils; + +import java.nio.file.Path; + +public record ResolvedChestGui(IconEntry entry, int width, int height) { + public String key() { + return entry.key(); + } + + public Path javaTexturePath(Path javaRootPath) { + return entry.path().apply(javaRootPath); + } + + public Path bedrockTexturePath(Path javaRootPath) { + return PathUtils.getPathFromRoot(javaTexturePath(javaRootPath), "textures") ; + } +} diff --git a/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/font/FontWriter.java b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/font/FontWriter.java index 4e21cec..6b0527b 100644 --- a/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/font/FontWriter.java +++ b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/font/FontWriter.java @@ -4,10 +4,10 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import fr.openmc.riftengine.api.utils.IdentifierUtils; import fr.openmc.riftengine.core.RiftRegistry; import fr.openmc.riftengine.core.converter.writers.PackWriter; import fr.openmc.riftengine.core.registry.glyphs.types.FontGlyph; -import fr.openmc.riftengine.core.utils.IdentifierUtils; import fr.openmc.riftengine.core.utils.ScanUtils; import java.io.File; diff --git a/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/icons/IconsWriter.java b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/icons/IconsWriter.java index b864955..e47a51e 100644 --- a/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/icons/IconsWriter.java +++ b/src/main/java/fr/openmc/riftengine/core/converter/writers/glyph/icons/IconsWriter.java @@ -7,6 +7,8 @@ import fr.openmc.riftengine.core.RiftPlugin; import fr.openmc.riftengine.core.RiftRegistry; import fr.openmc.riftengine.core.converter.writers.PackWriter; +import fr.openmc.riftengine.core.converter.writers.glyph.chestgui.ChestScreenWriter; +import fr.openmc.riftengine.core.converter.writers.glyph.chestgui.ResolvedChestGui; import fr.openmc.riftengine.core.registry.glyphs.GlyphsRegistry; import fr.openmc.riftengine.core.registry.glyphs.types.IconGlyph; @@ -77,7 +79,7 @@ public void write(Path bedrockRootPath, Path javaRootPath) throws IOException { } if (type.equals(IconsType.MENU_GUI)) { - RiftLog.DETECTED_AS_MENU_GUI.send(entry.namespacedId()); + ChestScreenWriter.chestGuis.add(new ResolvedChestGui(entry, image.getWidth(), image.getHeight())); continue; } diff --git a/src/main/java/fr/openmc/riftengine/core/converter/writers/items/ItemsTextureWriter.java b/src/main/java/fr/openmc/riftengine/core/converter/writers/items/ItemsTextureWriter.java index cd9dffa..834f51c 100644 --- a/src/main/java/fr/openmc/riftengine/core/converter/writers/items/ItemsTextureWriter.java +++ b/src/main/java/fr/openmc/riftengine/core/converter/writers/items/ItemsTextureWriter.java @@ -1,10 +1,10 @@ package fr.openmc.riftengine.core.converter.writers.items; import fr.openmc.riftengine.api.scanner.items.ItemEntry; +import fr.openmc.riftengine.api.utils.IdentifierUtils; import fr.openmc.riftengine.core.converter.writers.PackWriter; import fr.openmc.riftengine.core.resolvers.items.ItemResourceResolver; import fr.openmc.riftengine.core.resolvers.items.ResolvedItemResource; -import fr.openmc.riftengine.core.utils.IdentifierUtils; import java.io.IOException; import java.nio.file.Path; @@ -26,7 +26,6 @@ public void write(Path bedrockRootPath, Path javaRootPath) throws IOException { for (ResolvedItemResource resource : resources) { if (resource.isVanilla()) continue; - Path outputFile = bedrockRootPath.resolve(IdentifierUtils.toBedrockTexturePath(resource.bedrockTexturePath())); this.copyFile(resource.sourcePath(), outputFile); } diff --git a/src/main/java/fr/openmc/riftengine/core/converter/writers/tooltip/textures/TooltipTextureWriter.java b/src/main/java/fr/openmc/riftengine/core/converter/writers/tooltip/textures/TooltipTextureWriter.java index b53c515..02e70e2 100644 --- a/src/main/java/fr/openmc/riftengine/core/converter/writers/tooltip/textures/TooltipTextureWriter.java +++ b/src/main/java/fr/openmc/riftengine/core/converter/writers/tooltip/textures/TooltipTextureWriter.java @@ -1,13 +1,13 @@ package fr.openmc.riftengine.core.converter.writers.tooltip.textures; import fr.openmc.riftengine.api.scanner.items.ItemEntry; +import fr.openmc.riftengine.api.utils.IdentifierUtils; import fr.openmc.riftengine.core.RiftLog; import fr.openmc.riftengine.core.converter.writers.PackWriter; import fr.openmc.riftengine.core.resolvers.mcmeta.gui.GuiMcMetaResolver; import fr.openmc.riftengine.core.resolvers.mcmeta.gui.ResolvedGuiMcMeta; import fr.openmc.riftengine.core.resolvers.tooltip.ResolvedTooltipResource; import fr.openmc.riftengine.core.resolvers.tooltip.TooltipResourceResolver; -import fr.openmc.riftengine.core.utils.IdentifierUtils; import java.io.IOException; import java.nio.file.Path; @@ -15,11 +15,6 @@ import java.util.List; import java.util.Map; - -// - ecrire les textures dans le resourcepack bedrock -// * faire un scanner pour savoir les frames, fps, et tt chose qui sont relié entre les textures et ui_common.json -// - allouer un glyph pour chaque "type" de tooltip + le mettre dans l'item name + demander reload ia -// - ecrire le ui/ui_common.json (une giga template que j'adapte en fonction des textures) public class TooltipTextureWriter implements PackWriter { private final List items; private final GuiMcMetaResolver guiResolver; diff --git a/src/main/java/fr/openmc/riftengine/core/listeners/ChestGuiTitleListener.java b/src/main/java/fr/openmc/riftengine/core/listeners/ChestGuiTitleListener.java new file mode 100644 index 0000000..2b6a007 --- /dev/null +++ b/src/main/java/fr/openmc/riftengine/core/listeners/ChestGuiTitleListener.java @@ -0,0 +1,74 @@ +package fr.openmc.riftengine.core.listeners; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import fr.openmc.core.OMCRegistry; +import fr.openmc.riftengine.api.utils.IdentifierUtils; +import fr.openmc.riftengine.core.converter.writers.glyph.chestgui.ChestScreenWriter; +import fr.openmc.riftengine.core.utils.FloodgateUtils; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class ChestGuiTitleListener extends PacketAdapter { + private final Set offsetCaracter; + private final Map cacheUnicode; + + public ChestGuiTitleListener(Path javaRootPath, Path itemsAdderDataPath, Plugin plugin) throws IOException { + super(plugin, ListenerPriority.LOWEST, PacketType.Play.Server.OPEN_WINDOW); + this.offsetCaracter = OMCRegistry.SCANNERS.OFFSET_CARACTER.scan(javaRootPath); + this.cacheUnicode = OMCRegistry.SCANNERS.CARACTER_UNICODE_CACHE.scan(itemsAdderDataPath); + } + + @Override + public void onPacketSending(PacketEvent event) { + Player player = event.getPlayer(); + if (!FloodgateUtils.isBedrock(player)) return; + + PacketContainer packet = event.getPacket(); + WrappedChatComponent title = packet.getChatComponents().read(0); + if (title == null) return; + + String raw = PlainTextComponentSerializer.plainText() + .serialize(GsonComponentSerializer.gson().deserialize(title.getJson())); + + // * si l'inv est fait en sorte que le title se resolve au client ex. §r§f:offset_-48::city_template3x9: + // * sinon on nettoie le string pour savoir si il contient un offset, donc un potentiel menu + if (raw.contains(":offset_")) { + String[] parts = raw.split("::"); + if (parts.length < 2) return; + + String menuName = parts[1].replace(":", ""); + packet.getChatComponents().write(0, WrappedChatComponent.fromText(ChestScreenWriter.PREFIX + ":" + menuName)); + } else { + boolean hasOffset = raw.chars() + .mapToObj(c -> (char) c) + .anyMatch(offsetCaracter::contains); + + if (!hasOffset) return; + + // * on supprime les offsets et les caracteres basiques pour ne garder que le caractere du menu + String cleaned = raw.chars() + .mapToObj(c -> String.valueOf((char) c)) + .filter(c -> c.length() == 1 && !offsetCaracter.contains(c.charAt(0))) + .collect(Collectors.joining()) + .replaceAll("§[0-9a-fk-or]", ""); + + char menuChar = cleaned.charAt(0); + + packet.getChatComponents().write(0, WrappedChatComponent.fromText( + ChestScreenWriter.PREFIX + ":" + IdentifierUtils.removeNamespace(cacheUnicode.get(menuChar)))); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/riftengine/core/registry/glyphs/GlyphsRegistry.java b/src/main/java/fr/openmc/riftengine/core/registry/glyphs/GlyphsRegistry.java index 56e82fb..a49b086 100644 --- a/src/main/java/fr/openmc/riftengine/core/registry/glyphs/GlyphsRegistry.java +++ b/src/main/java/fr/openmc/riftengine/core/registry/glyphs/GlyphsRegistry.java @@ -11,10 +11,10 @@ public class GlyphsRegistry extends Registry public static final int GRID_SIZE = 16; public static final int MAX_PER_PAGE = GRID_SIZE * GRID_SIZE; - private final List SLOT_GLYPH = new ArrayList<>(List.of( + public static final List SLOT_GLYPH = new ArrayList<>(List.of( "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7")); - public static final String TOOLTIP_PAGE = "F8"; + public static final String OTHER_PAGE = "F8"; // tooltip, gui ... tout ceux qui ont juste besoin d'etre identifié private int nextPageIndex = 0; public String nextGlyphPage() { diff --git a/src/main/java/fr/openmc/riftengine/core/registry/glyphs/types/TooltipGlyph.java b/src/main/java/fr/openmc/riftengine/core/registry/glyphs/types/TooltipGlyph.java index 25b12e8..2d3754f 100644 --- a/src/main/java/fr/openmc/riftengine/core/registry/glyphs/types/TooltipGlyph.java +++ b/src/main/java/fr/openmc/riftengine/core/registry/glyphs/types/TooltipGlyph.java @@ -10,7 +10,7 @@ public class TooltipGlyph extends Glyph { private final ResolvedTooltipResource tooltipResource; public TooltipGlyph(String namespacedId, int row, int col, ResolvedTooltipResource tooltipResource) { - super(namespacedId, GlyphsRegistry.TOOLTIP_PAGE, row, col); + super(namespacedId, GlyphsRegistry.OTHER_PAGE, row, col); this.tooltipResource = tooltipResource; } } \ No newline at end of file diff --git a/src/main/java/fr/openmc/riftengine/core/resolvers/items/ItemResourceResolver.java b/src/main/java/fr/openmc/riftengine/core/resolvers/items/ItemResourceResolver.java index 01078be..ccf6b59 100644 --- a/src/main/java/fr/openmc/riftengine/core/resolvers/items/ItemResourceResolver.java +++ b/src/main/java/fr/openmc/riftengine/core/resolvers/items/ItemResourceResolver.java @@ -1,9 +1,9 @@ package fr.openmc.riftengine.core.resolvers.items; import fr.openmc.riftengine.api.scanner.items.ItemEntry; +import fr.openmc.riftengine.api.utils.IdentifierUtils; import fr.openmc.riftengine.core.RiftLog; import fr.openmc.riftengine.core.registry.resolver.AbstractResolver; -import fr.openmc.riftengine.core.utils.IdentifierUtils; import fr.openmc.riftengine.core.utils.PathUtils; import java.nio.file.Path; diff --git a/src/main/java/fr/openmc/riftengine/core/utils/FloodgateUtils.java b/src/main/java/fr/openmc/riftengine/core/utils/FloodgateUtils.java new file mode 100644 index 0000000..4984d8f --- /dev/null +++ b/src/main/java/fr/openmc/riftengine/core/utils/FloodgateUtils.java @@ -0,0 +1,10 @@ +package fr.openmc.riftengine.core.utils; + +import org.bukkit.entity.Player; +import org.geysermc.floodgate.api.FloodgateApi; + +public class FloodgateUtils { + public static boolean isBedrock(Player player) { + return FloodgateApi.getInstance().isFloodgatePlayer(player.getUniqueId()); + } +} diff --git a/src/main/java/fr/openmc/riftengine/core/utils/IdentifierUtils.java b/src/main/java/fr/openmc/riftengine/core/utils/IdentifierUtils.java deleted file mode 100644 index b167d4d..0000000 --- a/src/main/java/fr/openmc/riftengine/core/utils/IdentifierUtils.java +++ /dev/null @@ -1,100 +0,0 @@ -package fr.openmc.riftengine.core.utils; - -import java.nio.file.Path; - -public class IdentifierUtils { - /** - * Normalise un identifiant (qui n'a pas un namespace devant - * @param id l'id (font/default.png, minecraft:font/default.png) - * @return l'id final - */ - public static String normalizeId(String id) { - return normalizeId(id, "minecraft"); - } - - /** - * Normalise un identifiant (qui n'a pas un namespace devant - * @param id l'id (font/default.png, minecraft:font/default.png) - * @param defaultNamespace le namespace par défaut à utiliser, si on est dans un fichier d'items adder par ex - * @return l'id final - */ - public static String normalizeId(String id, String defaultNamespace) { - if (id.split(":").length == 2) return id; - - return defaultNamespace + ":" + id; - } - - public static String removeNamespace(String namespacedId) { - String[] splited = namespacedId.split(":"); - if (splited.length != 2) return namespacedId; - - return splited[1]; - } - - /** - * Résout un identifiant en un chemin de fichier dans les assets - */ - public static Path resolveTextureId(Path rootPath, String id) { - String normalizedId = normalizeId(id); - String[] split = normalizedId.split(":", 2); - - String namespace; - String texturePath; - - if (split.length == 2) { - namespace = split[0]; - texturePath = split[1]; - } else { - namespace = "minecraft"; - texturePath = split[0]; - } - - if (!texturePath.endsWith(".png")) { - texturePath += ".png"; - } - - return rootPath - .resolve("assets") - .resolve(namespace) - .resolve("textures") - .resolve(texturePath); - } - - /** - * Résout un identifiant en un chemin de fichier dans les assets pour les models - */ - public static Path resolveModelId(Path rootPath, String id) { - String normalizedId = normalizeId(id); - String[] split = normalizedId.split(":", 2); - - String namespace; - String modelPath; - - if (split.length == 2) { - namespace = split[0]; - modelPath = split[1]; - } else { - namespace = "minecraft"; - modelPath = split[0]; - } - - if (!modelPath.endsWith(".json")) { - modelPath += ".json"; - } - - return rootPath - .resolve("assets") - .resolve(namespace) - .resolve("models") - .resolve(modelPath); - } - - public static String toBedrockTexturePath(String javaPath) { - if (javaPath.startsWith("textures/item/")) - return "textures/items/" + javaPath.substring("textures/item/".length()); - if (javaPath.startsWith("textures/block/")) - return "textures/blocks/" + javaPath.substring("textures/block/".length()); - - return javaPath; - } -} diff --git a/src/main/java/fr/openmc/riftengine/core/utils/ImageUtils.java b/src/main/java/fr/openmc/riftengine/core/utils/ImageUtils.java new file mode 100644 index 0000000..91ba915 --- /dev/null +++ b/src/main/java/fr/openmc/riftengine/core/utils/ImageUtils.java @@ -0,0 +1,111 @@ +package fr.openmc.riftengine.core.utils; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public final class ImageUtils { + public static BufferedImage read(Path path) throws IOException { + return ImageIO.read(path.toFile()); + } + + public static void writePng(BufferedImage image, Path target) throws IOException { + Files.createDirectories(target.getParent()); + ImageIO.write(image, "png", target.toFile()); + } + + public static BufferedImage center(BufferedImage src) { + return center(src, src.getWidth(), src.getHeight()); + } + + public static BufferedImage center(BufferedImage src, int canvasW, int canvasH) { + int minX = src.getWidth(), minY = src.getHeight(), maxX = -1, maxY = -1; + + // * detecte les zones transparentes + for (int y = 0; y < src.getHeight(); y++) { + for (int x = 0; x < src.getWidth(); x++) { + if ((src.getRGB(x, y) >>> 24) != 0) { + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x > maxX) maxX = x; + if (y > maxY) maxY = y; + } + } + } + + if (maxX < 0) return src; + + int contentW = maxX - minX + 1; + int contentH = maxY - minY + 1; + int offsetX = (canvasW - contentW) / 2; + int offsetY = (canvasH - contentH) / 2; + + BufferedImage result = new BufferedImage(canvasW, canvasH, BufferedImage.TYPE_INT_ARGB); + for (int y = 0; y < contentH; y++) { + for (int x = 0; x < contentW; x++) { + result.setRGB(offsetX + x, offsetY + y, src.getRGB(minX + x, minY + y)); + } + } + return result; + } + + /** + * Grossomodo calcule la valeur y ou y'a une zone transparentes + */ + public static int centerShiftY(BufferedImage src) { + int minY = -1; + int maxY = -1; + + for (int y = 0; y < src.getHeight(); y++) { + for (int x = 0; x < src.getWidth(); x++) { + if ((src.getRGB(x, y) >>> 24) != 0) { + if (minY == -1) minY = y; + maxY = y; + break; + } + } + } + + if (minY == -1) return 0; + + int contentH = maxY - minY + 1; + return (src.getHeight() - contentH) / 2 - minY; + } + + public static int findGridLeft(BufferedImage img) { + int w = img.getWidth(), h = img.getHeight(); + + long[] edge = new long[w]; + for (int x = 1; x < w; x++) { + long s = 0; + for (int y = 0; y < h; y++) s += Math.abs(lum(img, x, y) - lum(img, x - 1, y)); + edge[x] = s; + } + + long[] score = new long[w]; + long best = -1; + int bestX = -1; + for (int p = 1; p + 162 < w; p++) { + long s = 0; + for (int k = 0; k <= 9; k++) s += edge[p + k * 18]; + score[p] = s; + if (s > best) { best = s; bestX = p; } + } + if (bestX == -1) return -1; + + long rival = 0; + for (int p = 1; p + 162 < w; p++) { + int d = Math.floorMod(p - bestX, 18); + if (Math.min(d, 18 - d) > 2) rival = Math.max(rival, score[p]); + } + return best >= rival * 1.15 ? bestX : -1; + } + + private static int lum(BufferedImage img, int x, int y) { + int argb = img.getRGB(x, y); + if ((argb >>> 24) == 0) return 0; + return (((argb >> 16) & 255) + ((argb >> 8) & 255) + (argb & 255)) / 3; + } +} diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml index 70b0652..060d616 100644 --- a/src/main/resources/paper-plugin.yml +++ b/src/main/resources/paper-plugin.yml @@ -14,5 +14,8 @@ dependencies: load: BEFORE required: true Geyser-Spigot: + load: BEFORE + required: true + floodgate: load: BEFORE required: true \ No newline at end of file