From 2e4743a8d347239157bc8b9ec2984aa4370fc4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Gris?= Date: Sun, 29 Mar 2026 00:08:10 +0100 Subject: [PATCH 1/4] feat(Action): Send IMC message to mod Implements a new action type: `sendIMC` Example: a button to open the GTNH-Credits screen ```json { "action": { "type": "sendIMC", "modid": "gtnhcredits", "message": "openCredits" } } ``` --- .../configuration/GuiConfig.java | 6 +++++ .../lib/actions/ActionSendIMC.java | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java diff --git a/src/main/java/lumien/custommainmenu/configuration/GuiConfig.java b/src/main/java/lumien/custommainmenu/configuration/GuiConfig.java index dd42892..33500cd 100644 --- a/src/main/java/lumien/custommainmenu/configuration/GuiConfig.java +++ b/src/main/java/lumien/custommainmenu/configuration/GuiConfig.java @@ -30,6 +30,7 @@ import lumien.custommainmenu.lib.actions.ActionOpenLink; import lumien.custommainmenu.lib.actions.ActionQuit; import lumien.custommainmenu.lib.actions.ActionRefresh; +import lumien.custommainmenu.lib.actions.ActionSendIMC; import lumien.custommainmenu.lib.actions.IAction; import lumien.custommainmenu.lib.texts.IText; import lumien.custommainmenu.lib.texts.TextResourceLocation; @@ -410,6 +411,11 @@ private IAction getWantedAction(JsonObject actionObject) { if (actionType.equalsIgnoreCase("openFolder")) { return new ActionOpenFolder(actionObject.get("folderName").getAsString()); } + if (actionType.equalsIgnoreCase("sendIMC")) { + return new ActionSendIMC( + actionObject.get("modid").getAsString(), + actionObject.get("message").getAsString()); + } return null; } diff --git a/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java b/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java new file mode 100644 index 0000000..8d49cd1 --- /dev/null +++ b/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java @@ -0,0 +1,25 @@ +package lumien.custommainmenu.lib.actions; + +import cpw.mods.fml.common.event.FMLInterModComms; +import lumien.custommainmenu.CustomMainMenu; +import lumien.custommainmenu.gui.GuiCustom; + +/** + * CMM action that sends an IMC runtime message to a target mod when performed. Config: {@code "action": {"type": + * "sendIMC", "modid": "targetmodid", "message": "someKey"}} + */ +public class ActionSendIMC implements IAction { + + private final String targetModId; + private final String message; + + public ActionSendIMC(String targetModId, String message) { + this.targetModId = targetModId; + this.message = message; + } + + @Override + public void perform(Object source, GuiCustom menu) { + FMLInterModComms.sendRuntimeMessage(CustomMainMenu.INSTANCE, targetModId, message, ""); + } +} From 18d165f310393b1e4977fbaec33a52fe03803b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Gris?= Date: Sun, 29 Mar 2026 01:50:56 +0100 Subject: [PATCH 2/4] impr(IMC): Use the Forge Event-Bus --- .../custommainmenu/events/SendIMCEvent.java | 18 ++++++++++++++++++ .../lib/actions/ActionSendIMC.java | 9 +++++---- 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 src/main/java/lumien/custommainmenu/events/SendIMCEvent.java diff --git a/src/main/java/lumien/custommainmenu/events/SendIMCEvent.java b/src/main/java/lumien/custommainmenu/events/SendIMCEvent.java new file mode 100644 index 0000000..47079b3 --- /dev/null +++ b/src/main/java/lumien/custommainmenu/events/SendIMCEvent.java @@ -0,0 +1,18 @@ +package lumien.custommainmenu.events; + +import cpw.mods.fml.common.eventhandler.Event; + +/** + * Fired on {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS} when a CMM button with action type + * {@code "sendIMC"} is clicked. + */ +public class SendIMCEvent extends Event { + + public final String modId; + public final String message; + + public SendIMCEvent(String modId, String message) { + this.modId = modId; + this.message = message; + } +} diff --git a/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java b/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java index 8d49cd1..3daf9eb 100644 --- a/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java +++ b/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java @@ -1,11 +1,12 @@ package lumien.custommainmenu.lib.actions; -import cpw.mods.fml.common.event.FMLInterModComms; -import lumien.custommainmenu.CustomMainMenu; +import net.minecraftforge.common.MinecraftForge; + +import lumien.custommainmenu.events.SendIMCEvent; import lumien.custommainmenu.gui.GuiCustom; /** - * CMM action that sends an IMC runtime message to a target mod when performed. Config: {@code "action": {"type": + * CMM action that fires a {@link SendIMCEvent} on the Forge event bus when performed. Config: {@code "action": {"type": * "sendIMC", "modid": "targetmodid", "message": "someKey"}} */ public class ActionSendIMC implements IAction { @@ -20,6 +21,6 @@ public ActionSendIMC(String targetModId, String message) { @Override public void perform(Object source, GuiCustom menu) { - FMLInterModComms.sendRuntimeMessage(CustomMainMenu.INSTANCE, targetModId, message, ""); + MinecraftForge.EVENT_BUS.post(new SendIMCEvent(targetModId, message)); } } From 3d7d6f242815a205051f367de113d7217dfc4c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Gris?= Date: Sun, 29 Mar 2026 13:16:53 +0200 Subject: [PATCH 3/4] event rename --- .../events/{SendIMCEvent.java => ActionIMCEvent.java} | 4 ++-- .../lumien/custommainmenu/lib/actions/ActionSendIMC.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) rename src/main/java/lumien/custommainmenu/events/{SendIMCEvent.java => ActionIMCEvent.java} (78%) diff --git a/src/main/java/lumien/custommainmenu/events/SendIMCEvent.java b/src/main/java/lumien/custommainmenu/events/ActionIMCEvent.java similarity index 78% rename from src/main/java/lumien/custommainmenu/events/SendIMCEvent.java rename to src/main/java/lumien/custommainmenu/events/ActionIMCEvent.java index 47079b3..640f9dd 100644 --- a/src/main/java/lumien/custommainmenu/events/SendIMCEvent.java +++ b/src/main/java/lumien/custommainmenu/events/ActionIMCEvent.java @@ -6,12 +6,12 @@ * Fired on {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS} when a CMM button with action type * {@code "sendIMC"} is clicked. */ -public class SendIMCEvent extends Event { +public class ActionIMCEvent extends Event { public final String modId; public final String message; - public SendIMCEvent(String modId, String message) { + public ActionIMCEvent(String modId, String message) { this.modId = modId; this.message = message; } diff --git a/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java b/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java index 3daf9eb..afb7836 100644 --- a/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java +++ b/src/main/java/lumien/custommainmenu/lib/actions/ActionSendIMC.java @@ -2,12 +2,12 @@ import net.minecraftforge.common.MinecraftForge; -import lumien.custommainmenu.events.SendIMCEvent; +import lumien.custommainmenu.events.ActionIMCEvent; import lumien.custommainmenu.gui.GuiCustom; /** - * CMM action that fires a {@link SendIMCEvent} on the Forge event bus when performed. Config: {@code "action": {"type": - * "sendIMC", "modid": "targetmodid", "message": "someKey"}} + * CMM action that fires a {@link ActionIMCEvent} on the Forge event bus when performed. Config: {@code "action": + * {"type": "sendIMC", "modid": "targetmodid", "message": "someKey"}} */ public class ActionSendIMC implements IAction { @@ -21,6 +21,6 @@ public ActionSendIMC(String targetModId, String message) { @Override public void perform(Object source, GuiCustom menu) { - MinecraftForge.EVENT_BUS.post(new SendIMCEvent(targetModId, message)); + MinecraftForge.EVENT_BUS.post(new ActionIMCEvent(targetModId, message)); } } From bb7320b282f073de7af2dd1f475296450b26ebb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Gris?= Date: Sun, 29 Mar 2026 14:27:01 +0200 Subject: [PATCH 4/4] docs: add mainmenu.schema.json for IDE validation Provides a JSON Schema (draft-07) for mainmenu.json, fixing two gaps in the SchemaStore schema: the alignment field now accepts custom alignment keys defined in the "alignments" section, and the sendIMC action type is documented with its required modid and message properties. The file lives at the repo root and is not bundled in the mod jar. Reference it from a mainmenu.json with: "$schema": "https://raw.githubusercontent.com/GTNewHorizons/Custom-Main-Menu/master/mainmenu.schema.json" --- mainmenu.schema.json | 638 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 638 insertions(+) create mode 100644 mainmenu.schema.json diff --git a/mainmenu.schema.json b/mainmenu.schema.json new file mode 100644 index 0000000..c9a9a66 --- /dev/null +++ b/mainmenu.schema.json @@ -0,0 +1,638 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/GTNewHorizons/Custom-Main-Menu/master/mainmenu.schema.json", + "title": "GTNH Custom Main Menu Schema", + "description": "A schema describing the structure of the JSON configuration files used by the GTNH fork of the Custom Main Menu Minecraft mod.", + "type": "object", + "additionalProperties": true, + "definitions": { + "size": { + "type": "object", + "description": "A definition for the size of an element.", + "properties": { + "width": { + "type": "integer", + "description": "The width of the element in pixels." + }, + "height": { + "type": "integer", + "description": "The height of the element in pixels." + } + } + }, + "position": { + "type": "object", + "description": "A definition for the position of an element.", + "properties": { + "posX": { + "type": "integer", + "description": "The offset on the X-axis of the element on the screen from the alignment position.\nFor example: if the alignment is set to 'top_center' and the posX is set to 0, the element's left edge will be aligned with the center of the screen.\nIf posY is also set to 0, the element's top edge will be at the top of the screen." + }, + "posY": { + "type": "integer", + "description": "The offset on the Y-axis of the element on the screen from the alignment position.\nFor example: if the alignment is set to 'top_center' and the posX is set to 0, the element's left edge will be aligned with the center of the screen.\nIf posY is also set to 0, the element's top edge will be at the top of the screen." + } + } + }, + "rect": { + "type": "object", + "description": "A definition for a rectangular area. Can be used to define the position and size of buttons, images, and other elements.", + "allOf": [ + { + "$ref": "#/definitions/size" + }, + { + "$ref": "#/definitions/position", + "required": ["posX", "posY"] + } + ] + }, + "alignment": { + "type": "object", + "properties": { + "alignment": { + "description": "The alignment of the element relative to the screen. Can be a built-in value or a custom alignment key defined in the \"alignments\" section.", + "anyOf": [ + { + "type": "string", + "enum": [ + "top_right", + "top_left", + "top_center", + "right_center", + "left_center", + "center", + "button", + "bottom_right", + "bottom_left", + "bottom_center" + ] + }, + { + "type": "string", + "description": "Custom alignment key defined in the \"alignments\" section." + } + ] + } + } + }, + "image": { + "type": "object", + "description": "An image definition.", + "allOf": [ + { + "$ref": "#/definitions/rect" + }, + { + "$ref": "#/definitions/alignment" + }, + { + "type": "object", + "description": "Image-specific properties.", + "required": ["image"], + "properties": { + "image": { + "type": "string", + "description": "An image resource identifier representing the image to be displayed." + }, + "hoverImage": { + "type": "string", + "description": "An image resource identifier representing the image to be displayed when the mouse hovers over the image." + }, + "slideshow": { + "$ref": "#/definitions/slideshow" + } + } + } + ] + }, + "slideshow": { + "type": "object", + "description": "Defines the image as a slideshow, which cycles through various images, having a fading transition between them.", + "required": ["images", "displayDuration", "fadeDuration"], + "properties": { + "images": { + "type": "array", + "description": "A list of An image resource identifiers representing the images to be displayed in the slideshow.", + "items": { + "type": "string" + } + }, + "displayDuration": { + "type": "integer", + "description": "The duration in Minecraft ticks that each image in the slideshow is displayed for before transitioning to the next." + }, + "fadeDuration": { + "type": "integer", + "description": "The duration in Minecraft ticks that the transition between images in the slideshow lasts for." + }, + "shuffle": { + "type": "boolean", + "description": "Whether the order of the images should be shuffled each time Minecraft runs." + }, + "synced": { + "type": "boolean", + "description": "Synced is a property for slideshows, panoramas and splash texts on the current menu.\n\nIf it is set to true, instead of creating a new slideshow/panorama/splash text instance each time, the current menu will use the same one as the main menu. Therefore the panorama and/or the slideshow will continue to run where they left off when switching GUIs, and the splash text will stay the same.\n\nNotice that this property should only be set on the GUIs you want synced to the main menu, not on the main menu itself. Also if the main menu doesn't have a slideshow/panorama/splash text but you set it to sync in another menu, your game will probably crash.\n\nNotice that synced only works on a background slideshow, it will have no effect on an image that is a slideshow." + } + } + }, + "button": { + "type": "object", + "description": "A button definition. Buttons execute actions when clicked, which can be: opening a GUI (including custom ones), connecting to a server, opening a link, or loading a world.", + "allOf": [ + { + "$ref": "#/definitions/rect" + }, + { + "$ref": "#/definitions/alignment" + }, + { + "type": "object", + "description": "Button-specific properties.", + "required": ["text"], + "properties": { + "text": { + "type": "string", + "description": "A text resource identifier representing the text to be displayed on the button. Can be an empty string - this is useful when you want to create an 'icon button' through the 'texture' property." + }, + "hoverText": { + "type": "string", + "description": "A text resource identifier representing the text to be displayed on the button when the mouse hovers over it." + }, + "normalTextColor": { + "type": "integer", + "description": "The color of the text on the button. Has to be a hexadecimal color value represented as a decimal number." + }, + "hoverTextColor": { + "type": "integer", + "description": "The color of the text on the button when the mouse hovers over it. Has to be a hexadecimal color value represented as a decimal number." + }, + "textOffsetX": { + "type": "integer", + "description": "The offset on the X-axis of the text inside the button." + }, + "textOffsetY": { + "type": "integer", + "description": "The offset on the Y-axis of the text inside the button." + }, + "texture": { + "type": "string", + "description": "An image resource identifier representing the image to be displayed on the button i.e. the button's texture/background image. The image has to contain a normal and a hovered version of the button, one on top of the other." + }, + "imageWidth": { + "type": "integer", + "description": "The width of the button's texture/background image in pixels. By default it is the same width as the button." + }, + "imageHeight": { + "type": "integer", + "description": "The height of the button's texture/background image in pixels. By default it is the same height as the button." + }, + "pressSound": { + "type": "string", + "description": "An audio resource identifier representing the sound to be played when the button is pressed." + }, + "hoverSound": { + "type": "string", + "description": "An audio resource identifier representing the sound to be played when the mouse hovers over the button." + }, + "tooltip": { + "type": "string", + "description": "A text resource identifier representing the text to be displayed in a tooltip when the mouse hovers over the button." + }, + "action": { + "$ref": "#/definitions/buttonAction" + }, + "wrappedButton": { + "type": "string", + "description": "The ID of a button added by another mod.\n\nCustom Main Menu removes all buttons added by other mods because they don't fit the schema used by CMM.\n\nUsing Wrapped Buttons you can create buttons that mimic the functionality of those removed buttons, with the added capability of being able to define and customize them like any other CMM button.\n\nFor them to work you need to find out the button ID of the button you want to re-add - look into your latest FML client log and search for 'wrapped button'. All removed mod buttons are logged with their respective button ID." + } + } + } + ] + }, + "buttonAction": { + "type": "object", + "description": "The action to be executed when the button is clicked.", + "properties": { + "type": { + "anyOf": [ + { + "type": "string", + "const": "openLink", + "description": "Opens a link in the default browser." + }, + { + "type": "string", + "const": "openGui", + "description": "Opens a GUI. Can also open a custom GUI." + }, + { + "type": "string", + "const": "connectToServer", + "description": "Connects to a server." + }, + { + "type": "string", + "const": "loadWorld", + "description": "Loads a world." + }, + { + "type": "string", + "const": "openFolder", + "description": "Opens a folder." + }, + { + "type": "string", + "const": "quit", + "description": "Quits the game." + }, + { + "type": "string", + "const": "refresh", + "description": "Refreshes the current menu." + }, + { + "type": "string", + "const": "sendIMC", + "description": "Fires an ActionIMCEvent on MinecraftForge.EVENT_BUS. Mods subscribe to this event to handle the message." + } + ] + } + }, + "allOf": [ + { + "if": { + "required": ["type"], + "properties": { "type": { "const": "openLink" } } + }, + "then": { + "required": ["link"], + "properties": { + "link": { + "type": "string", + "description": "The URL to be opened." + } + } + } + }, + { + "if": { + "required": ["type"], + "properties": { "type": { "const": "openGui" } } + }, + "then": { + "required": ["gui"], + "properties": { + "gui": { + "type": "string", + "description": "The name of the GUI to be opened. Can also be a custom GUI ID.", + "enum": [ + "mods", + "singleplayer", + "singleplayer.createworld", + "multiplayer", + "options", + "languages", + "options.resourcepacks", + "options.snooper", + "options.sounds", + "options.video", + "options.controls", + "options.multiplayer" + ] + } + } + } + }, + { + "if": { + "required": ["type"], + "properties": { "type": { "const": "connectToServer" } } + }, + "then": { + "required": ["ip"], + "properties": { + "ip": { + "type": "string", + "description": "The IP address of the server to connect to." + } + } + } + }, + { + "if": { + "required": ["type"], + "properties": { "type": { "const": "loadWorld" } } + }, + "then": { + "required": ["dirName"], + "properties": { + "dirName": { + "type": "string", + "description": "The name of the directory the save is located in (in the saves folder)." + }, + "saveName": { + "type": "string", + "description": "Not really necessary, but might appear as the name of the save in certain dialogs while loading the world." + } + } + } + }, + { + "if": { + "required": ["type"], + "properties": { "type": { "const": "openFolder" } } + }, + "then": { + "required": ["folderName"], + "properties": { + "folderName": { + "type": "string", + "description": "The name of the folder to be opened (with the .minecraft folder as the root)." + } + } + } + }, + { + "if": { + "required": ["type"], + "properties": { "type": { "const": "sendIMC" } } + }, + "then": { + "required": ["modid", "message"], + "properties": { + "modid": { + "type": "string", + "description": "The mod ID of the target mod that will receive the ActionIMCEvent." + }, + "message": { + "type": "string", + "description": "The message string passed to the ActionIMCEvent." + } + } + } + } + ] + }, + "text": { + "type": "string", + "description": "A text resource identifier representing the text to be displayed." + }, + "label": { + "type": "object", + "description": "A label definition. Labels are used to display text on the screen.", + "allOf": [ + { + "$ref": "#/definitions/size" + }, + { + "$ref": "#/definitions/alignment" + }, + { + "type": "object", + "description": "Label-specific properties.", + "required": ["text"], + "properties": { + "text": { + "type": "string", + "description": "A text resource identifier representing the text to be displayed." + }, + "hoverText": { + "type": "string", + "description": "A text resource identifier representing the text to be displayed when the mouse hovers over it." + }, + "fontSize": { + "type": "integer", + "description": "The multiplier of the font size. 2 would be twice as big, 0.5 would be half as big, etc. The default font size is 1." + }, + "color": { + "type": "integer", + "description": "The color of the text. Has to be a hexadecimal color value represented as a decimal number." + }, + "hoverColor": { + "type": "integer", + "description": "The color of the text when the mouse hovers over it. Has to be a hexadecimal color value represented as a decimal number." + }, + "anchor": { + "type": "string", + "description": "The anchor of the text. Makes the text left, center, or right aligned.", + "enum": ["start", "middle", "end"] + }, + "pressSound": { + "type": "string", + "description": "An audio resource identifier representing a sound to play when the label is pressed." + }, + "hoverSound": { + "type": "string", + "description": "An audio resource identifier representing a sound to play when the mouse hovers over the label." + } + } + } + ] + }, + "background": { + "description": "A regular background of the current menu. Can be a static image, a slideshow, or the default background of eg. the options menu.\n\nNotice that you cannot have both a background image and a panorama at the same time.", + "oneOf": [ + { + "type": "object", + "required": ["image"], + "properties": { + "image": { + "type": "string", + "description": "An image resource identifier representing an an image to be displayed." + }, + "mode": { + "type": "string", + "description": "The image sizing/positioning mode.", + "anyOf": [ + { + "type": "string", + "const": "fill", + "description": "The image is upscaled to cover the entire screen. The aspect ratio of the image is preserved, so parts of the image might be cut off. This mode will not produce any black bars." + }, + { + "type": "string", + "const": "stretch", + "description": "The image is stretched to cover the entire screen. The aspect ratio of the image is not preserved, so the image might look distorted. This mode will not produce any black bars." + }, + { + "type": "string", + "const": "center", + "description": "The image is simple placed on the center of the screen. The aspect ratio of the image is preserved, as well as the original size of the image. This mode will produce black bars on the sides of the image if the image is not wide and tall enough to cover the entire screen." + }, + { + "type": "string", + "const": "tile", + "description": "The image is tiled to cover the entire screen. The aspect ratio of the image is preserved, as well as the original size of the image. This mode will not produce any black bars." + } + ] + }, + "slideshow": { + "$ref": "#/definitions/slideshow" + } + } + }, + { + "type": "string", + "description": "The default background of the vanilla options menu (dirt).", + "const": "options" + } + ] + }, + "panorama": { + "type": "object", + "description": "A panorama background of the current menu, made up of 6 images. \n\nNotice that you cannot have both a background image and a panorama at the same time", + "properties": { + "images": { + "description": "Either a list of image resource identifiers representing images to be displayed in the panorama, or a single image resource identifier in the form of a string.", + "oneOf": [ + { + "type": "array", + "description": "A list of image resource identifiers representing images to be displayed in the panorama.", + "items": { + "type": "string" + }, + "maxItems": 6, + "minItems": 6 + }, + { + "type": "string", + "description": "An image resource identifier. The provided image will be used for all 6 panorama slides.\n\nIf an image resource identifier containing '%c' is provided, then any occurrences of '%c' in the string will be replaced with the current index of the image (0-5), for eg. 'panorama_%c.png' will be replaced with 'panorama_0.png', 'panorama_1.png', etc. at runtime\n\nThis is useful when you don't want to individually specify the resource path for each image in the panorama, but instead want to use a naming convention for the images, for eg. 'panorama_0.png', 'panorama_1.png', etc." + } + ] + }, + "blur": { + "type": "boolean", + "description": "Whether the panorama should be blurred." + }, + "gradient": { + "type": "boolean", + "description": "Whether the panorama should have a top-to-bottom white-to-back gradient overlay." + }, + "animate": { + "type": "boolean", + "description": "Whether the panorama should spin like normal." + }, + "animationSpeed": { + "type": "integer", + "description": "The integer multiple of the speed of the panorama animation. 1 is the default speed, 2 is double the speed, -1 makes it play in reverse, etc." + }, + "position": { + "type": "integer", + "description": "At which position the panorama should start from (or stay at, if 'animate' is false)." + }, + "synced": { + "type": "boolean", + "description": "Synced is a property for slideshows, panoramas and splash texts on the current menu.\n\nIf it is set to true, instead of creating a new slideshow/panorama/splash text instance each time, the current menu will use the same one as the main menu. Therefore the panorama and/or the slideshow will continue to run where they left off when switching GUIs, and the splash text will stay the same.\n\nNotice that this property should only be set on the GUIs you want synced to the main menu, not on the main menu itself. Also if the main menu doesn't have a slideshow/panorama/splash text but you set it to sync in another menu, your game will probably crash.\n\nNotice that synced only works on a background slideshow, it will have no effect on an image that is a slideshow." + } + } + }, + "splashText": { + "type": "object", + "description": "A splash text definition. Splash texts are the random text that appears on the main menu.", + "allOf": [ + { + "$ref": "#/definitions/position", + "required": ["posX", "posY"] + }, + { + "$ref": "#/definitions/alignment" + }, + { + "type": "object", + "description": "Splash text-specific properties.", + "properties": { + "color": { + "type": "integer", + "description": "The color of the text. Has to be a hexadecimal color value represented as a decimal number." + }, + "texts": { + "type": "string", + "description": "A text resource identifier representing the text to be displayed. Separate splash texts are separated by newlines." + }, + "synced": { + "type": "boolean", + "description": "Synced is a property for slideshows, panoramas and splash texts on the current menu.\n\nIf it is set to true, instead of creating a new slideshow/panorama/splash text instance each time, the current menu will use the same one as the main menu. Therefore the panorama and/or the slideshow will continue to run where they left off when switching GUIs, and the splash text will stay the same.\n\nNotice that this property should only be set on the GUIs you want synced to the main menu, not on the main menu itself. Also if the main menu doesn't have a slideshow/panorama/splash text but you set it to sync in another menu, your game will probably crash.\n\nNotice that synced only works on a background slideshow, it will have no effect on an image that is a slideshow." + } + } + } + ] + } + }, + "properties": { + "$schema": { + "type": "string" + }, + "version": { + "type": "integer", + "minimum": 1, + "description": "Schema version. Increment when making backwards-incompatible changes so readers can detect format mismatches." + }, + "images": { + "type": "object", + "description": "A dictionary of image definitions which specify images to be displayed on the current menu.", + "patternProperties": { + "^.*$": { + "$ref": "#/definitions/image" + } + }, + "additionalProperties": false + }, + "buttons": { + "type": "object", + "description": "A dictionary of button definitions which specify buttons to be displayed on the current menu.", + "patternProperties": { + "^.*$": { + "$ref": "#/definitions/button" + } + }, + "additionalProperties": false + }, + "labels": { + "type": "object", + "description": "A dictionary of label definitions which specify text labels to be displayed on the current menu.", + "patternProperties": { + "^.*$": { + "$ref": "#/definitions/label" + } + }, + "additionalProperties": false + }, + "other": { + "type": "object", + "description": "A dictionary of special properties such as splash texts, backgrounds, and panoramas.", + "allOf": [ + { + "properties": { + "splash-text": { + "$ref": "#/definitions/splashText" + } + } + }, + { + "properties": { + "background": { + "$ref": "#/definitions/background" + } + } + }, + { + "properties": { + "panorama": { + "$ref": "#/definitions/panorama" + } + } + }, + { + "not": { + "anyOf": [ + { + "required": ["background", "panorama"] + } + ] + } + } + ] + } + } +} \ No newline at end of file