diff --git a/.gitignore b/.gitignore index a646fdda..7d83d789 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ bin .metadata .classpath .project +.vscode # idea out diff --git a/.vscode/launch.json b/.vscode/launch.json index eb37a34b..d6ad3a9c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "projectName": "CRN 1.20.1", "cwd": "${workspaceFolder}\\run", "vmArgs": "-Dforge.logging.console.level\u003ddebug -Dforge.logging.markers\u003dREGISTRIES \"-DlegacyClassPath.file\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build\\classpath\\runClient_minecraftClasspath.txt\" -Dmixin.env.remapRefMap\u003dtrue \"-Dmixin.env.refMapRemappingFile\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build/createSrgToMcp/output.srg\" \"-Dnet.minecraftforge.gradle.GradleStart.srg.srg-mcp\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build\\createSrgToMcp\\output.srg\" -DignoreList\u003dbootstraplauncher,securejarhandler,asm-commons,asm-util,asm-analysis,asm-tree,asm,JarJarFileSystems,client-extra,fmlcore,javafmllanguage,lowcodelanguage,mclanguage,forge- -DmergeModules\u003djna-5.10.0.jar,jna-platform-5.10.0.jar -Dforge.enabledGameTestNamespaces\u003dcreaterailwaysnavigator -Dforge.enableGameTest\u003dtrue -Djava.net.preferIPv6Addresses\u003dsystem -p C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\cpw.mods\\bootstraplauncher\\1.1.2\\c546e00443d8432cda6baa1c860346980742628\\bootstraplauncher-1.1.2.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\cpw.mods\\securejarhandler\\2.1.10\\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\\securejarhandler-2.1.10.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-commons\\9.5\\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\\asm-commons-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-util\\9.5\\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\\asm-util-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-analysis\\9.5\\490bacc77de7cbc0be1a30bb3471072d705be4a4\\asm-analysis-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-tree\\9.5\\fd33c8b6373abaa675be407082fdfda35021254a\\asm-tree-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm\\9.5\\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\\asm-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\net.minecraftforge\\JarJarFileSystems\\0.3.19\\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\\JarJarFileSystems-0.3.19.jar --add-modules ALL-MODULE-PATH --add-opens java.base/java.util.jar\u003dcpw.mods.securejarhandler --add-opens java.base/java.lang.invoke\u003dcpw.mods.securejarhandler --add-exports java.base/sun.security.util\u003dcpw.mods.securejarhandler --add-exports jdk.naming.dns/com.sun.jndi.dns\u003djava.naming -XX:HeapDumpPath\u003dMojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump", - "args": "--launchTarget forgeclientuserdev --version MOD_DEV --assetIndex 5 --assetsDir C:\\Users\\julia\\.gradle\\caches\\forge_gradle\\assets --gameDir . --fml.forgeVersion 47.2.0 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mixin.config createrailwaysnavigator.mixin.json", + "args": "--launchTarget forgeclientuserdev --version MOD_DEV --assetIndex 5 --assetsDir C:\\Users\\julia\\.gradle\\caches\\forge_gradle\\assets --gameDir . --fml.forgeVersion 47.2.0 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mixin.config createrailwaysnavigator.mixins.json", "env": { "MOD_CLASSES": "createrailwaysnavigator%%${workspaceFolder}\\build\\resources\\main;createrailwaysnavigator%%${workspaceFolder}\\build\\classes\\java\\main", "MCP_MAPPINGS": "parchment_2023.09.03-1.20.1" @@ -24,7 +24,7 @@ "projectName": "CRN 1.20.1", "cwd": "${workspaceFolder}\\run-data", "vmArgs": "-Dforge.logging.console.level\u003ddebug -Dforge.logging.markers\u003dREGISTRIES \"-DlegacyClassPath.file\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build\\classpath\\runData_minecraftClasspath.txt\" -Dmixin.env.remapRefMap\u003dtrue \"-Dmixin.env.refMapRemappingFile\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build/createSrgToMcp/output.srg\" \"-Dnet.minecraftforge.gradle.GradleStart.srg.srg-mcp\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build\\createSrgToMcp\\output.srg\" -DignoreList\u003dbootstraplauncher,securejarhandler,asm-commons,asm-util,asm-analysis,asm-tree,asm,JarJarFileSystems,client-extra,fmlcore,javafmllanguage,lowcodelanguage,mclanguage,forge- -DmergeModules\u003djna-5.10.0.jar,jna-platform-5.10.0.jar -Djava.net.preferIPv6Addresses\u003dsystem -p C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\cpw.mods\\bootstraplauncher\\1.1.2\\c546e00443d8432cda6baa1c860346980742628\\bootstraplauncher-1.1.2.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\cpw.mods\\securejarhandler\\2.1.10\\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\\securejarhandler-2.1.10.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-commons\\9.5\\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\\asm-commons-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-util\\9.5\\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\\asm-util-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-analysis\\9.5\\490bacc77de7cbc0be1a30bb3471072d705be4a4\\asm-analysis-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-tree\\9.5\\fd33c8b6373abaa675be407082fdfda35021254a\\asm-tree-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm\\9.5\\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\\asm-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\net.minecraftforge\\JarJarFileSystems\\0.3.19\\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\\JarJarFileSystems-0.3.19.jar --add-modules ALL-MODULE-PATH --add-opens java.base/java.util.jar\u003dcpw.mods.securejarhandler --add-opens java.base/java.lang.invoke\u003dcpw.mods.securejarhandler --add-exports java.base/sun.security.util\u003dcpw.mods.securejarhandler --add-exports jdk.naming.dns/com.sun.jndi.dns\u003djava.naming", - "args": "--launchTarget forgedatauserdev --assetIndex 5 --assetsDir C:\\Users\\julia\\.gradle\\caches\\forge_gradle\\assets --gameDir . --fml.forgeVersion 47.2.0 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mod createrailwaysnavigator --all --output \"C:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\src\\generated\\resources\" --existing \"C:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\src\\main\\resources\" --mixin.config createrailwaysnavigator.mixin.json", + "args": "--launchTarget forgedatauserdev --assetIndex 5 --assetsDir C:\\Users\\julia\\.gradle\\caches\\forge_gradle\\assets --gameDir . --fml.forgeVersion 47.2.0 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mod createrailwaysnavigator --all --output \"C:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\src\\generated\\resources\" --existing \"C:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\src\\main\\resources\" --mixin.config createrailwaysnavigator.mixins.json", "env": { "MOD_CLASSES": "createrailwaysnavigator%%${workspaceFolder}\\build\\resources\\main;createrailwaysnavigator%%${workspaceFolder}\\build\\classes\\java\\main", "MCP_MAPPINGS": "parchment_2023.09.03-1.20.1" @@ -39,7 +39,7 @@ "projectName": "CRN 1.20.1", "cwd": "${workspaceFolder}\\run", "vmArgs": "-Dforge.logging.console.level\u003ddebug -Dforge.logging.markers\u003dREGISTRIES \"-DlegacyClassPath.file\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build\\classpath\\runGameTestServer_minecraftClasspath.txt\" -Dmixin.env.remapRefMap\u003dtrue \"-Dmixin.env.refMapRemappingFile\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build/createSrgToMcp/output.srg\" \"-Dnet.minecraftforge.gradle.GradleStart.srg.srg-mcp\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build\\createSrgToMcp\\output.srg\" -DignoreList\u003dbootstraplauncher,securejarhandler,asm-commons,asm-util,asm-analysis,asm-tree,asm,JarJarFileSystems,client-extra,fmlcore,javafmllanguage,lowcodelanguage,mclanguage,forge- -DmergeModules\u003djna-5.10.0.jar,jna-platform-5.10.0.jar -Dforge.enabledGameTestNamespaces\u003dcreaterailwaysnavigator -Djava.net.preferIPv6Addresses\u003dsystem -p C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\cpw.mods\\bootstraplauncher\\1.1.2\\c546e00443d8432cda6baa1c860346980742628\\bootstraplauncher-1.1.2.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\cpw.mods\\securejarhandler\\2.1.10\\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\\securejarhandler-2.1.10.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-commons\\9.5\\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\\asm-commons-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-util\\9.5\\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\\asm-util-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-analysis\\9.5\\490bacc77de7cbc0be1a30bb3471072d705be4a4\\asm-analysis-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-tree\\9.5\\fd33c8b6373abaa675be407082fdfda35021254a\\asm-tree-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm\\9.5\\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\\asm-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\net.minecraftforge\\JarJarFileSystems\\0.3.19\\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\\JarJarFileSystems-0.3.19.jar --add-modules ALL-MODULE-PATH --add-opens java.base/java.util.jar\u003dcpw.mods.securejarhandler --add-opens java.base/java.lang.invoke\u003dcpw.mods.securejarhandler --add-exports java.base/sun.security.util\u003dcpw.mods.securejarhandler --add-exports jdk.naming.dns/com.sun.jndi.dns\u003djava.naming", - "args": "--launchTarget forgegametestserveruserdev --gameDir . --fml.forgeVersion 47.2.0 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mixin.config createrailwaysnavigator.mixin.json", + "args": "--launchTarget forgegametestserveruserdev --gameDir . --fml.forgeVersion 47.2.0 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mixin.config createrailwaysnavigator.mixins.json", "env": { "MOD_CLASSES": "createrailwaysnavigator%%${workspaceFolder}\\build\\resources\\main;createrailwaysnavigator%%${workspaceFolder}\\build\\classes\\java\\main", "MCP_MAPPINGS": "parchment_2023.09.03-1.20.1" @@ -54,7 +54,7 @@ "projectName": "CRN 1.20.1", "cwd": "${workspaceFolder}\\run", "vmArgs": "-Dforge.logging.console.level\u003ddebug -Dforge.logging.markers\u003dREGISTRIES \"-DlegacyClassPath.file\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build\\classpath\\runServer_minecraftClasspath.txt\" -Dmixin.env.remapRefMap\u003dtrue \"-Dmixin.env.refMapRemappingFile\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build/createSrgToMcp/output.srg\" \"-Dnet.minecraftforge.gradle.GradleStart.srg.srg-mcp\u003dC:\\Users\\julia\\Documents\\Forge Modding\\CreateRailwaysNavigator\\CRN 1.20.1\\build\\createSrgToMcp\\output.srg\" -DignoreList\u003dbootstraplauncher,securejarhandler,asm-commons,asm-util,asm-analysis,asm-tree,asm,JarJarFileSystems,client-extra,fmlcore,javafmllanguage,lowcodelanguage,mclanguage,forge- -DmergeModules\u003djna-5.10.0.jar,jna-platform-5.10.0.jar -Dforge.enabledGameTestNamespaces\u003dcreaterailwaysnavigator -Dforge.enableGameTest\u003dtrue -Djava.net.preferIPv6Addresses\u003dsystem -p C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\cpw.mods\\bootstraplauncher\\1.1.2\\c546e00443d8432cda6baa1c860346980742628\\bootstraplauncher-1.1.2.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\cpw.mods\\securejarhandler\\2.1.10\\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\\securejarhandler-2.1.10.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-commons\\9.5\\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\\asm-commons-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-util\\9.5\\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\\asm-util-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-analysis\\9.5\\490bacc77de7cbc0be1a30bb3471072d705be4a4\\asm-analysis-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm-tree\\9.5\\fd33c8b6373abaa675be407082fdfda35021254a\\asm-tree-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm\\9.5\\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\\asm-9.5.jar;C:\\Users\\julia\\.gradle\\caches\\modules-2\\files-2.1\\net.minecraftforge\\JarJarFileSystems\\0.3.19\\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\\JarJarFileSystems-0.3.19.jar --add-modules ALL-MODULE-PATH --add-opens java.base/java.util.jar\u003dcpw.mods.securejarhandler --add-opens java.base/java.lang.invoke\u003dcpw.mods.securejarhandler --add-exports java.base/sun.security.util\u003dcpw.mods.securejarhandler --add-exports jdk.naming.dns/com.sun.jndi.dns\u003djava.naming", - "args": "--launchTarget forgeserveruserdev --gameDir . --fml.forgeVersion 47.2.0 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --nogui --mixin.config createrailwaysnavigator.mixin.json", + "args": "--launchTarget forgeserveruserdev --gameDir . --fml.forgeVersion 47.2.0 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --nogui --mixin.config createrailwaysnavigator.mixins.json", "env": { "MOD_CLASSES": "createrailwaysnavigator%%${workspaceFolder}\\build\\resources\\main;createrailwaysnavigator%%${workspaceFolder}\\build\\classes\\java\\main", "MCP_MAPPINGS": "parchment_2023.09.03-1.20.1" diff --git a/.vscode/settings.json b/.vscode/settings.json index c6fe6583..aeaa85fc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "java.configuration.updateBuildConfiguration": "automatic", - "java.compile.nullAnalysis.mode": "disabled" + "java.compile.nullAnalysis.mode": "disabled", + "commentTranslate.hover.enabled": false } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 8ba62fe1..3163655d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx6G org.gradle.daemon=false -mod_version = 0.3.0-beta +mod_version = 0.4.0-beta mod_root_path = de.mrjulsen.crn minecraft_version=1.20.1 diff --git a/src/main/java/de/mrjulsen/crn/Constants.java b/src/main/java/de/mrjulsen/crn/Constants.java index d3291db1..2733478e 100644 --- a/src/main/java/de/mrjulsen/crn/Constants.java +++ b/src/main/java/de/mrjulsen/crn/Constants.java @@ -2,6 +2,7 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.UUID; import com.google.gson.Gson; @@ -21,10 +22,11 @@ public class Constants { public static final Component TEXT_TRUE = Utils.translate("gui." + ModMain.MOD_ID + ".common.true"); public static final Component TEXT_FALSE = Utils.translate("gui." + ModMain.MOD_ID + ".common.false"); public static final Component TEXT_SERVER_ERROR = Utils.translate("gui." + ModMain.MOD_ID + ".common.server_error"); - public static final String TEXT_SEARCH = Utils.translate("common." + ModMain.MOD_ID + ".search").getString(); + public static final Component TEXT_SEARCH = Utils.translate("gui." + ModMain.MOD_ID + ".common.search"); public static final Gson GSON = new Gson(); public static final DateFormat DATE_FORMAT = new SimpleDateFormat(); public static final int TIME_SHIFT = 6000; + public static final UUID ZERO_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000"); public static final int COLOR_ON_TIME = 0x1AEA5F; public static final int COLOR_DELAYED = 0xFF4242; diff --git a/src/main/java/de/mrjulsen/crn/ModMain.java b/src/main/java/de/mrjulsen/crn/ModMain.java index 34def721..32d0ee5d 100644 --- a/src/main/java/de/mrjulsen/crn/ModMain.java +++ b/src/main/java/de/mrjulsen/crn/ModMain.java @@ -1,14 +1,26 @@ package de.mrjulsen.crn; import com.mojang.logging.LogUtils; +import com.simibubi.create.foundation.data.CreateRegistrate; +import com.simibubi.create.foundation.item.ItemDescription; +import com.simibubi.create.foundation.item.KineticStats; +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.item.TooltipModifier; +import de.mrjulsen.crn.block.AdvancedDisplayBlock; import de.mrjulsen.crn.config.ModClientConfig; import de.mrjulsen.crn.config.ModCommonConfig; -import de.mrjulsen.crn.item.ModItems; -import de.mrjulsen.crn.item.creativemodetab.ModCreativeModeTab; import de.mrjulsen.crn.network.NetworkManager; import de.mrjulsen.crn.proxy.ClientInitWrapper; import de.mrjulsen.crn.proxy.ServerInit; +import de.mrjulsen.crn.registry.ModBlockEntities; +import de.mrjulsen.crn.registry.ModBlocks; +import de.mrjulsen.crn.registry.ModCreativeModeTab; +import de.mrjulsen.crn.registry.ModExtras; +import de.mrjulsen.crn.registry.ModItems; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.ModLoadingContext; @@ -16,27 +28,53 @@ import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import javax.annotation.Nullable; + import org.slf4j.Logger; @Mod(ModMain.MOD_ID) public final class ModMain { - // The value here should match an entry in the META-INF/mods.toml file public static final String MOD_ID = "createrailwaysnavigator"; - - // Directly reference a slf4j logger public static final Logger LOGGER = LogUtils.getLogger(); + + public static final CreateRegistrate REGISTRATE = CreateRegistrate.create(MOD_ID); + + @Nullable + public static KineticStats create(Item item) { + if (item instanceof BlockItem blockItem) { + Block block = blockItem.getBlock(); + if (block instanceof AdvancedDisplayBlock) { + return new KineticStats(block); + } + } + return null; + } + + static { + ModMain.REGISTRATE.setTooltipModifierFactory(item -> + new ItemDescription.Modifier(item, TooltipHelper.Palette.STANDARD_CREATE) + .andThen(TooltipModifier.mapNull(ModMain.create(item))) + ); + } public ModMain() { IEventBus eventBus = FMLJavaModLoadingContext.get().getModEventBus(); - eventBus.addListener(ServerInit::setup); - eventBus.addListener(ClientInitWrapper::setup); + ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ModClientConfig.SPEC, MOD_ID + "-client.toml"); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModCommonConfig.SPEC, MOD_ID + "-common.toml"); - ModItems.register(eventBus); + eventBus.addListener(ServerInit::setup); + eventBus.addListener(ClientInitWrapper::setup); + + REGISTRATE.registerEventListeners(eventBus); + + ModBlocks.register(); + ModItems.register(); + ModBlockEntities.register(); ModCreativeModeTab.register(eventBus); NetworkManager.create(); + ModExtras.register(); MinecraftForge.EVENT_BUS.register(this); } } diff --git a/src/main/java/de/mrjulsen/crn/block/AbstractAdvancedDisplayBlock.java b/src/main/java/de/mrjulsen/crn/block/AbstractAdvancedDisplayBlock.java new file mode 100644 index 00000000..ca615b03 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/AbstractAdvancedDisplayBlock.java @@ -0,0 +1,308 @@ +package de.mrjulsen.crn.block; + +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.utility.Iterate; + +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ClientWrapper; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.crn.data.ESide; +import de.mrjulsen.crn.registry.ModBlockEntities; +import de.mrjulsen.crn.util.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.ticks.LevelTickAccess; + +public abstract class AbstractAdvancedDisplayBlock extends Block implements IWrenchable, IBE { + + public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING; + public static final EnumProperty SIDE = EnumProperty.create("side", ESide.class); + + public static final BooleanProperty UP = BooleanProperty.create("up"); + public static final BooleanProperty DOWN = BooleanProperty.create("down"); + + public AbstractAdvancedDisplayBlock(Properties properties) { + super(properties); + + this.registerDefaultState(this.stateDefinition.any() + .setValue(UP, false) + .setValue(DOWN, false) + .setValue(FACING, Direction.NORTH) + .setValue(SIDE, ESide.FRONT) + ); + } + + @Override + public BlockState rotate(BlockState pState, Rotation pRotation) { + return pState.setValue(FACING, pRotation.rotate(pState.getValue(FACING))); + } + + @Override + @SuppressWarnings("deprecation") + public BlockState mirror(BlockState pState, Mirror pMirror) { + return pState.rotate(pMirror.getRotation(pState.getValue(FACING))); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder); + pBuilder.add(UP, DOWN, FACING, SIDE); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + Direction face = context.getClickedFace(); + BlockPos clickedPos = context.getClickedPos(); + BlockPos placedOnPos = clickedPos.relative(face.getOpposite()); + Level level = context.getLevel(); + BlockState blockState = level.getBlockState(placedOnPos); + BlockState stateForPlacement = this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); + + if ((blockState.getBlock() != this) || (context.getPlayer() != null && context.getPlayer().isShiftKeyDown())) { + stateForPlacement = super.getStateForPlacement(context).setValue(FACING, context.getHorizontalDirection().getOpposite()); + } else { + Direction otherFacing = blockState.getValue(FACING); + stateForPlacement = stateForPlacement.setValue(FACING, otherFacing); + } + + return updateColumn(level, clickedPos, stateForPlacement, true); + } + + private BlockState updateColumn(Level level, BlockPos pos, BlockState state, boolean present) { + MutableBlockPos currentPos = new MutableBlockPos(); + Axis axis = getConnectionAxis(state); + + for (Direction connection : Iterate.directionsInAxis(Axis.Y)) { + boolean connect = true; + + Move: for (Direction movement : Iterate.directionsInAxis(axis)) { + currentPos.set(pos); + for (int i = 0; i < 1000; i++) { + if (!level.isLoaded(currentPos)) + break; + + BlockPos otherPos = currentPos.relative(connection); + BlockState other1 = currentPos.equals(pos) ? state : level.getBlockState(currentPos); + BlockState other2 = level.getBlockState(otherPos); + boolean col1 = canConnect(level, pos, state, other1); + boolean col2 = canConnect(level, pos, state, other2); + currentPos.move(movement); + + if (!col1 && !col2) + break; + if (col1 && col2) + continue; + + connect = false; + break Move; + } + } + state = setConnection(state, connection, connect); + } + return state; + } + + @Override + public void onPlace(BlockState pState, Level pLevel, BlockPos pPos, BlockState pOldState, boolean pIsMoving) { + if (pOldState.getBlock() == this) + return; + LevelTickAccess blockTicks = pLevel.getBlockTicks(); + if (!blockTicks.hasScheduledTick(pPos, this)) + pLevel.scheduleTick(pPos, this, 1); + + updateNeighbours(pState, pLevel, pPos); + + if (pLevel.isClientSide) { + withBlockEntityDo(pLevel, pPos, be -> be.getController().getRenderer().update(pLevel, pPos, pState, be, EUpdateReason.BLOCK_CHANGED)); + } + } + + public void updateNeighbours(BlockState pState, Level pLevel, BlockPos pPos) { + Direction leftDirection = pState.getValue(HorizontalDirectionalBlock.FACING).getClockWise(); + BlockPos relPos = pPos.relative(leftDirection); + if (updateNeighbour(pState, pLevel, pPos, relPos)) { + return; + } + relPos = pPos.relative(Direction.UP); + if (updateNeighbour(pState, pLevel, pPos, relPos)) { + return; + } + relPos = pPos.relative(leftDirection.getOpposite()); + if (updateNeighbour(pState, pLevel, pPos, relPos)) { + return; + } + relPos = pPos.relative(Direction.DOWN); + if (updateNeighbour(pState, pLevel, pPos, relPos)) { + return; + } + } + + @Override + public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, RandomSource pRandom) { + if (pState.getBlock() != this) + return; + BlockPos belowPos = pPos.relative(Direction.fromAxisAndDirection(getConnectionAxis(pState), AxisDirection.NEGATIVE)); + BlockState belowState = pLevel.getBlockState(belowPos); + if (!canConnect(pLevel, pPos, pState, belowState)) + KineticBlockEntity.switchToBlockState(pLevel, pPos, updateColumn(pLevel, pPos, pState, true)); + withBlockEntityDo(pLevel, pPos, AdvancedDisplayBlockEntity::updateControllerStatus); + } + + @Override + public BlockState updateShape(BlockState state, Direction pDirection, BlockState pNeighborState, LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + return updatedShapeInner(state, pDirection, pNeighborState, pLevel, pCurrentPos, pNeighborPos); + } + + private BlockState updatedShapeInner(BlockState state, Direction pDirection, BlockState pNeighborState, LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + if (!canConnect(pLevel, pCurrentPos, state, pNeighborState)) + return setConnection(state, pDirection, false); + if (pDirection.getAxis() == getConnectionAxis(state)) + return withPropertiesOf(pNeighborState); + return setConnection(state, pDirection, getConnection(pNeighborState, pDirection.getOpposite())); + } + + protected boolean canConnect(LevelAccessor level, BlockPos pos, BlockState state, BlockState other) { + return other.getBlock() == this && state.getValue(FACING) == other.getValue(FACING); + } + + public abstract boolean canConnectWithBlock(Level level, BlockPos selfPos, BlockPos otherPos); + + protected Axis getConnectionAxis(BlockState state) { + return state.getValue(FACING).getClockWise().getAxis(); + } + + public static boolean getConnection(BlockState state, Direction side) { + BooleanProperty property = side == Direction.DOWN ? DOWN : side == Direction.UP ? UP : null; + return property != null && state.getValue(property); + } + + public static BlockState setConnection(BlockState state, Direction side, boolean connect) { + BooleanProperty property = side == Direction.DOWN ? DOWN : side == Direction.UP ? UP : null; + if (property != null) + state = state.setValue(property, connect); + + return state; + } + + @SuppressWarnings("deprecation") + @Override + public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { + super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving); + if (pIsMoving || pNewState.getBlock() == this) + return; + for (Direction d : Iterate.directionsInAxis(getConnectionAxis(pState))) { + BlockPos relative = pPos.relative(d); + BlockState adjacent = pLevel.getBlockState(relative); + if (canConnect(pLevel, pPos, pState, adjacent)) + KineticBlockEntity.switchToBlockState(pLevel, relative, updateColumn(pLevel, relative, adjacent, false)); + } + } + + @Override + public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pHit) { + + ItemStack heldItem = pPlayer.getItemInHand(pHand); + AdvancedDisplayBlockEntity blockEntity = ((AdvancedDisplayBlockEntity)pLevel.getBlockEntity(pPos)).getController(); + + DyeColor dye = DyeColor.getColor(heldItem); + if (dye != null) { + pLevel.playSound(null, pPos, SoundEvents.DYE_USE, SoundSource.BLOCKS, 1.0F, 1.0F); + blockEntity.applyToAll(be -> { + be.setColor(dye == DyeColor.ORANGE ? 0xFF9900 : dye.getMapColor().col); + be.notifyUpdate(); + }); + return InteractionResult.SUCCESS; + } + + if (heldItem.is(Items.GLOW_INK_SAC)) { + pLevel.playSound(null, pPos, SoundEvents.GLOW_INK_SAC_USE, SoundSource.BLOCKS, 1.0F, 1.0F); + blockEntity.applyToAll(be -> { + be.setGlowing(true); + be.notifyUpdate(); + }); + return InteractionResult.SUCCESS; + } + + return InteractionResult.FAIL; + } + + private boolean updateNeighbour(BlockState pState, Level pLevel, BlockPos pPos, BlockPos neighbourPos) { + if (pLevel.getBlockState(neighbourPos).is(this) && pLevel.getBlockEntity(neighbourPos) instanceof AdvancedDisplayBlockEntity otherBe && pLevel.getBlockEntity(pPos) instanceof AdvancedDisplayBlockEntity be) { + be.setColor(otherBe.getColor()); + be.setGlowing(otherBe.isGlowing()); + be.setDisplayType(otherBe.getDisplayType()); + be.setInfoType(otherBe.getInfoType()); + be.notifyUpdate(); + if (pLevel.isClientSide) { + be.getController().getRenderer().update(pLevel, neighbourPos, pState, otherBe, EUpdateReason.BLOCK_CHANGED); + } + + pLevel.setBlockAndUpdate(pPos, pState.setValue(SIDE, pLevel.getBlockState(neighbourPos).getValue(SIDE))); + return true; + } + return false; + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + Level level = context.getLevel(); + if (level.isClientSide && level.getBlockEntity(context.getClickedPos()) instanceof AdvancedDisplayBlockEntity be) { + AdvancedDisplayBlockEntity controller = be.getController(); + if (controller != null) { + ClientWrapper.showAdvancedDisplaySettingsScreen(controller); + return InteractionResult.SUCCESS; + } + } + return InteractionResult.FAIL; + } + + @Override + public RenderShape getRenderShape(BlockState pState) { + return RenderShape.MODEL; + } + + @Override + public Class getBlockEntityClass() { + return AdvancedDisplayBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return ModBlockEntities.ADVANCED_DISPLAY_BLOCK_ENTITY.get(); + } + + public abstract Pair getRenderOffset(Level level, BlockState blockState, BlockPos pos); + /** First value: Front side, Second value: Back side */ public abstract Pair getRenderZOffset(Level level, BlockState blockState, BlockPos pos); + public abstract Pair getRenderAspectRatio(Level level, BlockState blockState, BlockPos pos); +} diff --git a/src/main/java/de/mrjulsen/crn/block/AdvancedDisplayBlock.java b/src/main/java/de/mrjulsen/crn/block/AdvancedDisplayBlock.java new file mode 100644 index 00000000..cd4c1dc8 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/AdvancedDisplayBlock.java @@ -0,0 +1,33 @@ +package de.mrjulsen.crn.block; + +import de.mrjulsen.crn.util.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public class AdvancedDisplayBlock extends AbstractAdvancedDisplayBlock { + + public AdvancedDisplayBlock(Properties properties) { + super(properties.noOcclusion()); + } + + @Override + public boolean canConnectWithBlock(Level level, BlockPos selfPos, BlockPos otherPos) { + return true; + } + + @Override + public Pair getRenderAspectRatio(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(1.0F, 1.0F); + } + + @Override + public Pair getRenderOffset(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(0.0f, 0.0f); + } + + @Override + public Pair getRenderZOffset(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(16.05f, 16.05f); + } +} diff --git a/src/main/java/de/mrjulsen/crn/block/AdvancedDisplayBoardBlock.java b/src/main/java/de/mrjulsen/crn/block/AdvancedDisplayBoardBlock.java new file mode 100644 index 00000000..e50c8927 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/AdvancedDisplayBoardBlock.java @@ -0,0 +1,46 @@ +package de.mrjulsen.crn.block; + +import de.mrjulsen.crn.util.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class AdvancedDisplayBoardBlock extends AbstractAdvancedDisplayBlock { + + private static final VoxelShape SHAPE_SN = Block.box(0, 0, 3, 16, 16, 13); + private static final VoxelShape SHAPE_EW = Block.box(3, 0, 0, 13, 16, 16); + + public AdvancedDisplayBoardBlock(Properties properties) { + super(properties); + } + + @Override + public boolean canConnectWithBlock(Level level, BlockPos selfPos, BlockPos otherPos) { + return true; + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return pState.getValue(FACING) == Direction.NORTH || pState.getValue(FACING) == Direction.SOUTH ? SHAPE_SN : SHAPE_EW; + } + + @Override + public Pair getRenderAspectRatio(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(1.0F, 1.0F); + } + + @Override + public Pair getRenderOffset(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(0.0f, 0.0f); + } + + @Override + public Pair getRenderZOffset(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(13.05f, 13.05f); + } +} diff --git a/src/main/java/de/mrjulsen/crn/block/AdvancedDisplayPanelBlock.java b/src/main/java/de/mrjulsen/crn/block/AdvancedDisplayPanelBlock.java new file mode 100644 index 00000000..3865d91c --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/AdvancedDisplayPanelBlock.java @@ -0,0 +1,51 @@ +package de.mrjulsen.crn.block; + +import java.util.Map; +import de.mrjulsen.crn.util.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class AdvancedDisplayPanelBlock extends AbstractAdvancedDisplayBlock { + + private static final Map SHAPES = Map.of( + Direction.NORTH, Block.box(0, 0, 13, 16, 16, 16), + Direction.EAST, Block.box(0, 0, 0, 3, 16, 16), + Direction.SOUTH, Block.box(0, 0, 0, 16, 16, 3), + Direction.WEST, Block.box(13, 0, 0, 16, 16, 16) + ); + + public AdvancedDisplayPanelBlock(Properties properties) { + super(properties); + } + + @Override + public boolean canConnectWithBlock(Level level, BlockPos selfPos, BlockPos otherPos) { + return true; + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return SHAPES.get(pState.getValue(FACING)); + } + + @Override + public Pair getRenderAspectRatio(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(1.0F, 1.0F); + } + + @Override + public Pair getRenderOffset(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(0.0f, 0.0f); + } + + @Override + public Pair getRenderZOffset(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(3.05f, 16.05f); + } +} diff --git a/src/main/java/de/mrjulsen/crn/block/AdvancedDisplaySmallBlock.java b/src/main/java/de/mrjulsen/crn/block/AdvancedDisplaySmallBlock.java new file mode 100644 index 00000000..7709376d --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/AdvancedDisplaySmallBlock.java @@ -0,0 +1,93 @@ +package de.mrjulsen.crn.block; + +import java.util.Map; +import de.mrjulsen.crn.util.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.Half; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class AdvancedDisplaySmallBlock extends AbstractAdvancedDisplayBlock { + + public static final EnumProperty HALF = BlockStateProperties.HALF; + + private static final Map> SHAPES = Map.of( + Direction.SOUTH, Map.of( + Half.BOTTOM, Block.box(0, 0, 0, 16, 8, 8), + Half.TOP, Block.box(0, 8, 0, 16, 16, 8) + ), + Direction.WEST, Map.of( + Half.BOTTOM, Block.box(8, 0, 0, 16, 8, 16), + Half.TOP, Block.box(8, 8, 0, 16, 16, 16) + ), + Direction.NORTH, Map.of( + Half.BOTTOM, Block.box(0, 0, 8, 16, 8, 16), + Half.TOP, Block.box(0, 8, 8, 16, 16, 16) + ), + Direction.EAST, Map.of( + Half.BOTTOM, Block.box(0, 0, 0, 8, 8, 16), + Half.TOP, Block.box(0, 8, 0, 8, 16, 16) + ) + ); + + public AdvancedDisplaySmallBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(HALF, Half.BOTTOM)); + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return SHAPES.get(pState.getValue(FACING)).get(pState.getValue(HALF)); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + BlockState stateForPlacement = super.getStateForPlacement(pContext); + Direction direction = pContext.getClickedFace(); + if (direction == Direction.UP) + return stateForPlacement; + if (direction == Direction.DOWN || (pContext.getClickLocation().y - pContext.getClickedPos().getY() > 0.5D)) + return stateForPlacement.setValue(HALF, Half.TOP); + return stateForPlacement; + } + + @Override + public boolean canConnectWithBlock(Level level, BlockPos selfPos, BlockPos otherPos) { + return level.getBlockState(otherPos).getBlock() instanceof AdvancedDisplaySmallBlock && level.getBlockState(selfPos).getValue(HALF) == level.getBlockState(otherPos).getValue(HALF); + } + + @Override + protected boolean canConnect(LevelAccessor level, BlockPos pos, BlockState state, BlockState other) { + return super.canConnect(level, pos, state, other) && state.getValue(HALF) == other.getValue(HALF); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(HALF)); + } + + @Override + public Pair getRenderAspectRatio(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(1.0F, 0.5F); + } + + @Override + public Pair getRenderOffset(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(0.0f, blockState.getValue(HALF) == Half.BOTTOM ? 8.0F : 0.0F); + } + + @Override + public Pair getRenderZOffset(Level level, BlockState blockState, BlockPos pos) { + return Pair.of(8.05f, 16.05f); + } +} diff --git a/src/main/java/de/mrjulsen/crn/block/TrainStationClockBlock.java b/src/main/java/de/mrjulsen/crn/block/TrainStationClockBlock.java new file mode 100644 index 00000000..989a213e --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/TrainStationClockBlock.java @@ -0,0 +1,96 @@ +package de.mrjulsen.crn.block; + +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.IBE; + +import de.mrjulsen.crn.Constants; +import de.mrjulsen.crn.block.be.TrainStationClockBlockEntity; +import de.mrjulsen.crn.config.ModClientConfig; +import de.mrjulsen.crn.registry.ModBlockEntities; +import de.mrjulsen.mcdragonlib.DragonLibConstants; +import de.mrjulsen.mcdragonlib.utils.TimeUtils; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class TrainStationClockBlock extends Block implements IWrenchable, IBE { + + public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING; + + private static final VoxelShape SHAPE_SN = Block.box(0, 0, 4, 16, 16, 12); + private static final VoxelShape SHAPE_EW = Block.box(4, 0, 0, 12, 16, 16); + + public TrainStationClockBlock(Properties properties) { + super(properties); + + this.registerDefaultState(this.stateDefinition.any() + .setValue(FACING, Direction.NORTH) + ); + } + + @Override + public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pHit) { + pPlayer.displayClientMessage(Utils.translate("gui.createrailwaysnavigator.time", TimeUtils.parseTime((int)(pLevel.getDayTime() % DragonLibConstants.TICKS_PER_DAY + Constants.TIME_SHIFT), ModClientConfig.TIME_FORMAT.get())), true); + return InteractionResult.SUCCESS; + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return pState.getValue(FACING) == Direction.NORTH || pState.getValue(FACING) == Direction.SOUTH ? SHAPE_SN : SHAPE_EW; + } + + @Override + public BlockState rotate(BlockState pState, Rotation pRotation) { + return pState.setValue(FACING, pRotation.rotate(pState.getValue(FACING))); + } + + @Override + @SuppressWarnings("deprecation") + public BlockState mirror(BlockState pState, Mirror pMirror) { + return pState.rotate(pMirror.getRotation(pState.getValue(FACING))); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder); + pBuilder.add(FACING); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); + } + + @Override + public RenderShape getRenderShape(BlockState pState) { + return RenderShape.MODEL; + } + + @Override + public Class getBlockEntityClass() { + return TrainStationClockBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return ModBlockEntities.TRAIN_STATION_CLOCK_BLOCK_ENTITY.get(); + } +} diff --git a/src/main/java/de/mrjulsen/crn/block/be/AdvancedDisplayBlockEntity.java b/src/main/java/de/mrjulsen/crn/block/be/AdvancedDisplayBlockEntity.java new file mode 100644 index 00000000..406e7005 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/be/AdvancedDisplayBlockEntity.java @@ -0,0 +1,681 @@ +package de.mrjulsen.crn.block.be; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import javax.annotation.Nullable; + +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.trains.display.FlapDisplayBlock; +import com.simibubi.create.content.trains.entity.CarriageContraption; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import de.mrjulsen.crn.block.AbstractAdvancedDisplayBlock; +import de.mrjulsen.crn.block.AdvancedDisplaySmallBlock; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.IBERInstance; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.crn.data.CarriageData; +import de.mrjulsen.crn.data.EDisplayInfo; +import de.mrjulsen.crn.data.EDisplayType; +import de.mrjulsen.crn.data.IBlockEntitySerializable; +import de.mrjulsen.crn.data.DeparturePrediction.TrainExitSide; +import de.mrjulsen.crn.data.EDisplayType.EDisplayTypeDataSource; +import de.mrjulsen.crn.data.TrainStationAlias.StationInfo; +import de.mrjulsen.crn.data.DeparturePrediction.SimpleDeparturePrediction; +import de.mrjulsen.crn.network.InstanceManager; +import de.mrjulsen.crn.network.NetworkManager; +import de.mrjulsen.crn.network.packets.cts.TrainDataRequestPacket; +import de.mrjulsen.crn.network.packets.cts.TrainDataRequestPacket.TrainData; +import de.mrjulsen.crn.util.Cache; +import de.mrjulsen.crn.util.Pair; +import de.mrjulsen.crn.util.Tripple; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; + +public class AdvancedDisplayBlockEntity extends SmartBlockEntity implements + IMultiblockBlockEntity, + IContraptionBlockEntity, + IBERInstance, + IBlockEntitySerializable, + IColorableBlockEntity +{ + private static final String NBT_XSIZE = "XSize"; + private static final String NBT_YSIZE = "YSize"; + private static final String NBT_CONTROLLER = "IsController"; + private static final String NBT_COLOR = "Color"; + private static final String NBT_GLOWING = "Glowing"; + private static final String NBT_INFO_TYPE = "InfoType"; + private static final String NBT_DISPLAY_TYPE = "DisplayType"; + private static final String NBT_PREDICTIONS = "Predictions"; + private static final String NBT_NEXT_DEPARTURE_STOPOVERS = "NextStopovers"; + private static final String NBT_FILTER = "Filter"; + private static final String NBT_LAST_REFRESH_TIME = "LastRefreshed"; + private static final String NBT_PLATFORM_WIDTH = "PlatformWidth"; + private static final String NBT_TRAIN_NAME_WIDTH = "TrainNameWidth"; + + public static final byte MAX_XSIZE = 16; + public static final byte MAX_YSIZE = 16; + + // DATA + private byte xSize = 1; + private byte ySize = 1; + private boolean isController; + private List predictions; + private List nextDepartureStopovers; + private String stationNameFilter; + private StationInfo stationInfo; + private byte trainNameWidth; + private byte platformWidth; + + // USER SETTINGS + private int color = DyeColor.WHITE.getTextColor(); + private boolean glowing = false; + private EDisplayInfo infoType = EDisplayInfo.SIMPLE; + private EDisplayType displayType = EDisplayType.TRAIN_DESTINATION; + + + // CLIENT DISPLAY ONLY - this data is not saved! + private long lastRefreshedTime; + private TrainData trainData = TrainData.empty(); + private CarriageData carriageData = new CarriageData(0, Direction.NORTH, false); + + // OTHER + private int syncTicks = 0; + private final Cache> renderer = new Cache<>(() -> new AdvancedDisplayRenderInstance(this)); + + public final Cache relativeExitDirection = new Cache<>(() -> { + if (getCarriageData() == null || !getTrainData().getNextStop().isPresent() || !(getBlockState().getBlock() instanceof AbstractAdvancedDisplayBlock)) { + return TrainExitSide.UNKNOWN; + } + TrainExitSide side = getTrainData().getNextStop().get().exitSide(); + Direction blockFacing = getBlockState().getValue(HorizontalDirectionalBlock.FACING); + if (!carriageData.isOppositeDirection()) { + blockFacing = blockFacing.getOpposite(); + } + + TrainExitSide result = side; + if (getCarriageData().assemblyDirection() == blockFacing) { + result = result.getOpposite(); + } else if (getCarriageData().assemblyDirection().getOpposite() != blockFacing) { + result = TrainExitSide.UNKNOWN; + } + return result; + }); + + public final Cache> renderOffset = new Cache<>(() -> { + if (getBlockState().getBlock() instanceof AbstractAdvancedDisplayBlock block) { + return block.getRenderOffset(level, getBlockState(), worldPosition); + } + return Tripple.of(0.0F, 0.0F); + }); + + public final Cache> renderZOffset = new Cache<>(() -> { + if (getBlockState().getBlock() instanceof AbstractAdvancedDisplayBlock block) { + return block.getRenderZOffset(level, getBlockState(), worldPosition); + } + return Tripple.of(0.0F, 0.0F); + }); + + public final Cache> renderAspectRatio = new Cache<>(() -> { + if (getBlockState().getBlock() instanceof AbstractAdvancedDisplayBlock block) { + Pair raw = block.getRenderAspectRatio(level, getBlockState(), worldPosition); + float scale = 1.0f / Math.min(raw.getFirst(), raw.getSecond()); + return Pair.of(raw.getFirst() * scale, raw.getSecond() * scale); + } + return Pair.of(1.0F, 1.0F); + }); + + public final Cache renderScale = new Cache<>(() -> { + return 1.0F / Math.max(this.renderAspectRatio.get().getFirst(), this.renderAspectRatio.get().getSecond()); + }); + + + + public AdvancedDisplayBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + reset(); + } + + public TrainData getTrainData() { + return trainData; + } + + public CarriageData getCarriageData() { + return carriageData; + } + + public long getLastRefreshedTime() { + return lastRefreshedTime; + } + + public byte getTrainNameWidth() { + return trainNameWidth; + } + + public byte getPlatformWidth() { + return platformWidth; + } + + public byte getXSize() { + return xSize; + } + + public byte getXSizeScaled() { + return (byte)(getXSize() * renderAspectRatio.get().getFirst()); + } + + public byte getYSize() { + return ySize; + } + + public byte getYSizeScaled() { + return (byte)(getYSize() * renderAspectRatio.get().getSecond()); + } + + public boolean isController() { + return isController; + } + + @Override + public int getColor() { + return color; + } + + @Override + public boolean isGlowing() { + return glowing; + } + + public EDisplayInfo getInfoType() { + return infoType; + } + + public EDisplayType getDisplayType() { + return displayType; + } + + @Override + public byte getMaxWidth() { + return MAX_XSIZE; + } + + @Override + public byte getMaxHeight() { + return MAX_YSIZE; + } + + @Override + public byte getWidth() { + return xSize; + } + + @Override + public byte getHeight() { + return ySize; + } + + @Override + public Class getBlockType() { + return AbstractAdvancedDisplayBlock.class; + } + + @Override + public Class getBlockEntityType() { + return AdvancedDisplayBlockEntity.class; + } + + public List getPredictions() { + return predictions; + } + + public List getNextDepartureStopovers() { + return nextDepartureStopovers; + } + + public boolean isPlatformFixed() { + return !stationNameFilter.contains("*"); + } + + public StationInfo getStationInfo() { + return stationInfo; + } + + public String getStationNameFilter() { + return stationNameFilter; + } + + public boolean isSingleLine() { + if (!(getBlockState().getBlock() instanceof AbstractAdvancedDisplayBlock)) { + return false; + } + + return getBlockState().getBlock() instanceof AdvancedDisplaySmallBlock || !( + (getDisplayType() == EDisplayType.PASSENGER_INFORMATION && getInfoType() == EDisplayInfo.INFORMATIVE) || + (getDisplayType() == EDisplayType.PLATFORM && getInfoType() == EDisplayInfo.DETAILED) || + (getDisplayType() == EDisplayType.PLATFORM && getInfoType() == EDisplayInfo.INFORMATIVE) + ); + } + + public int getPlatformInfoLinesCount() { + switch (getInfoType()) { + default: + case SIMPLE: + return 32; + case DETAILED: + return getYSize() * 3 - 1; + case INFORMATIVE: + return getYSize() * 3 - 2; + } + } + + public void setColor(int color) { + this.color = color; + if (level.isClientSide) { + getRenderer().update(level, worldPosition, getBlockState(), this, EUpdateReason.BLOCK_CHANGED); + } + } + + public void setGlowing(boolean glowing) { + this.glowing = glowing; + if (level.isClientSide) { + getRenderer().update(level, worldPosition, getBlockState(), this, EUpdateReason.BLOCK_CHANGED); + } + } + + public void setInfoType(EDisplayInfo type) { + this.infoType = type; + if (level.isClientSide) { + getRenderer().update(level, worldPosition, getBlockState(), this, EUpdateReason.BLOCK_CHANGED); + } + } + + public void setDisplayType(EDisplayType type) { + this.displayType = type; + if (level.isClientSide) { + getRenderer().update(level, worldPosition, getBlockState(), this, EUpdateReason.BLOCK_CHANGED); + } + } + + public void setDepartureData(List predictions, List nextDepartureStopovers, String stationNameFilter, StationInfo staionInfo, long lastRefreshedTime, byte platformWidth, byte trainNameWidth) { + this.predictions = predictions.stream().sorted(Comparator.comparingInt(x -> x.departureTicks())).toList(); + this.stationNameFilter = stationNameFilter; + this.stationInfo = staionInfo; + this.nextDepartureStopovers = nextDepartureStopovers; + this.lastRefreshedTime = lastRefreshedTime; + this.platformWidth = platformWidth; + this.trainNameWidth = trainNameWidth; + } + + @Override + public boolean connectable(BlockGetter getter, BlockPos a, BlockPos b) { + if (getter == null || a == null || b == null) { + return false; + } + + if (getter.getBlockEntity(a) instanceof AdvancedDisplayBlockEntity be1 && getter.getBlockEntity(b) instanceof AdvancedDisplayBlockEntity be2 && be1.getBlockState().getBlock() instanceof AbstractAdvancedDisplayBlock block1 && be2.getBlockState().getBlock() instanceof AbstractAdvancedDisplayBlock block2) { + return block1 == block2 && + be1.getDisplayType() == be2.getDisplayType() && + be1.getInfoType() == be2.getInfoType() && + be1.getBlockState().getValue(AbstractAdvancedDisplayBlock.SIDE) == be2.getBlockState().getValue(AbstractAdvancedDisplayBlock.SIDE) && + be1.getBlockState().getValue(AbstractAdvancedDisplayBlock.FACING) == be2.getBlockState().getValue(AbstractAdvancedDisplayBlock.FACING) && + block1.canConnectWithBlock(level, a, b) && block2.canConnectWithBlock(level, b, a) && + (!a.above().equals(b) || (be1.getBlockState().getValue(AbstractAdvancedDisplayBlock.UP) && !be1.isSingleLine())) && + (!a.below().equals(b) || (be1.getBlockState().getValue(AbstractAdvancedDisplayBlock.DOWN) && !be1.isSingleLine())) + ; + } + return false; + } + + public AdvancedDisplayBlockEntity getController() { + if (isController()) + return this; + + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof AbstractAdvancedDisplayBlock)) + return null; + + MutableBlockPos pos = getBlockPos().mutable(); + Direction side = blockState.getValue(AbstractAdvancedDisplayBlock.FACING).getClockWise(); + + for (int i = 0; i < getMaxWidth(); i++) { + if (connectable(level, pos, pos.relative(side))) { + pos.move(side); + continue; + } + + BlockEntity found = level.getBlockEntity(pos); + if (found instanceof AdvancedDisplayBlockEntity flap && flap.isController) + return flap; + + break; + } + + for (int i = 0; i < getMaxHeight(); i++) { + if (connectable(level, pos, pos.relative(Direction.UP))) { + pos.move(Direction.UP); + continue; + } + + BlockEntity found = level.getBlockEntity(pos); + if (found instanceof AdvancedDisplayBlockEntity flap && flap.isController) + return flap; + + break; + } + + return null; + } + + public void copyFrom(AdvancedDisplayBlockEntity other) { + if (getColor() == other.getColor() && + getInfoType() == other.getInfoType() && + getDisplayType() == other.getDisplayType() && + isGlowing() == other.isGlowing() + ) { + return; + } + + color = other.getColor(); + glowing = other.isGlowing(); + displayType = other.getDisplayType(); + infoType = other.getInfoType(); + notifyUpdate(); + } + + public void reset() { + predictions = List.of(); + nextDepartureStopovers = List.of(); + stationNameFilter = ""; + platformWidth = -1; + trainNameWidth = 16; + stationInfo = StationInfo.empty(); + } + + public void updateControllerStatus() { + + if (level.isClientSide) { + return; + } + + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof AbstractAdvancedDisplayBlock)) + return; + + Direction leftDirection = blockState.getValue(AbstractAdvancedDisplayBlock.FACING).getClockWise(); + boolean shouldBeController = !connectable(level, worldPosition, worldPosition.relative(leftDirection)) && !connectable(level, worldPosition, worldPosition.above()); + + byte newXSize = 1; + byte newYSize = 1; + + if (shouldBeController) { + for (int xOffset = 1; xOffset < getMaxWidth(); xOffset++) { + BlockPos relPos = worldPosition.relative(leftDirection.getOpposite(), xOffset); + if (level.getBlockState(relPos) != blockState) { + break; + } + + newXSize++; + } + + if (!isSingleLine()) { + for (int yOffset = 0; yOffset < getMaxHeight(); yOffset++) { + BlockPos downPos = worldPosition.relative(Direction.DOWN, yOffset); + + for (int i = 0; i < newXSize; i++) { + BlockPos relPos = downPos.relative(leftDirection.getOpposite(), i); + if (level.getBlockEntity(relPos) instanceof AdvancedDisplayBlockEntity be && be != this) { + be.copyFrom(this); + } + } + + if (!connectable(level, downPos, downPos.below())) { + break; + } + newYSize++; + } + } + } + + if (isController == shouldBeController && newXSize == xSize && newYSize == ySize) + return; + + isController = shouldBeController; + xSize = newXSize; + ySize = newYSize; + + if (!isController) { + reset(); + } + notifyUpdate(); + } + + @Override + public void tick() { + if (level.isClientSide) { + getRenderer().tick(level, getBlockPos(), getBlockState(), this); + } + + super.tick(); + + if (getDisplayType().getSource() != EDisplayTypeDataSource.PLATFORM) { + return; + } + + syncTicks++; + if ((syncTicks %= 100) == 0) { + if (level.isClientSide) { + boolean shouldUpdate = getPredictions().size() > 0; + + if (shouldUpdate) { + getRenderer().update(level, getBlockPos(), getBlockState(), this, EUpdateReason.DATA_CHANGED); + } + } + } + } + + @Override + public void lazyTick() { + super.lazyTick(); + updateControllerStatus(); + } + + @Override + public void contraptionTick(Level level, BlockPos pos, BlockState state, Contraption contraption) { + getRenderer().tick(level, pos, state, this); + + if (!isController()) { + return; + } + + if (getDisplayType().getSource() != EDisplayTypeDataSource.TRAIN_INFORMATION) { + return; + } + + syncTicks++; + if ((syncTicks %= 100) == 0) { + CarriageContraption carriage = (CarriageContraption)contraption; + long id = InstanceManager.registerClientTrainDataResponseAction((data, refreshTime) -> { + if (data == null) { + return; + } + boolean shouldUpdate = false; + if (trainData != null && trainData.getNextStop().isPresent() && data.getNextStop().isPresent()) { + SimpleDeparturePrediction prediction = trainData.getNextStop().get(); + + shouldUpdate = !trainData.trainName().equals(data.trainName()) || + !prediction.scheduleTitle().equals(data.predictions().get(0).scheduleTitle()) || + !prediction.stationTagName().equals(data.predictions().get(0).stationTagName()) || + trainData.getNextStop().get().exitSide() != data.getNextStop().get().exitSide() || + (getInfoType() == EDisplayInfo.INFORMATIVE && getDisplayType() == EDisplayType.PASSENGER_INFORMATION && trainData.getNextStop().get().departureTicks() + lastRefreshedTime != data.getNextStop().get().departureTicks() + refreshTime) // It's not clean but it works ... for now + ; + } + this.lastRefreshedTime = refreshTime; + this.trainData = data; + this.carriageData = new CarriageData(((CarriageContraptionEntity)carriage.entity).carriageIndex, carriage.getAssemblyDirection(), data.isOppositeDirection()); + this.relativeExitDirection.clear(); + + if (shouldUpdate) { + getRenderer().update(level, pos, state, this, EUpdateReason.DATA_CHANGED); + } + }); + NetworkManager.getInstance().sendToServer(Minecraft.getInstance().getConnection().getConnection(), new TrainDataRequestPacket(id, ((CarriageContraptionEntity)carriage.entity).trainId, true)); + } + } + + @Override + protected void write(CompoundTag pTag, boolean clientPacket) { + super.write(pTag, clientPacket); + pTag.putByte(NBT_XSIZE, getXSize()); + pTag.putByte(NBT_YSIZE, getYSize()); + pTag.putInt(NBT_COLOR, getColor()); + pTag.putBoolean(NBT_CONTROLLER, isController()); + pTag.putInt(NBT_INFO_TYPE, getInfoType().getId()); + pTag.putInt(NBT_DISPLAY_TYPE, getDisplayType().getId()); + pTag.putString(NBT_FILTER, getStationNameFilter()); + pTag.putBoolean(NBT_GLOWING, isGlowing()); + pTag.putLong(NBT_LAST_REFRESH_TIME, getLastRefreshedTime()); + pTag.putByte(NBT_PLATFORM_WIDTH, getPlatformWidth()); + pTag.putByte(NBT_TRAIN_NAME_WIDTH, getTrainNameWidth()); + + getStationInfo().writeNbt(pTag); + + if (getPredictions() != null && !getPredictions().isEmpty()) { + ListTag list = new ListTag(); + list.addAll(getPredictions().stream().map(x -> x.toNbt()).toList()); + pTag.put(NBT_PREDICTIONS, list); + } + + if (getNextDepartureStopovers() != null && !getNextDepartureStopovers().isEmpty()) { + ListTag stopovers = new ListTag(); + stopovers.addAll(getNextDepartureStopovers().stream().map(x -> StringTag.valueOf(x)).toList()); + pTag.put(NBT_NEXT_DEPARTURE_STOPOVERS, stopovers); + } + } + + @Override + public void read(CompoundTag pTag, boolean clientPacket) { + boolean updateClient = false; + if (level != null && getBlockState() != null && level.isClientSide) { + if ( + isController() != pTag.getBoolean(NBT_CONTROLLER) || + getXSize() != pTag.getByte(NBT_XSIZE) || + getYSize() != pTag.getByte(NBT_YSIZE) || + getPlatformWidth() != pTag.getByte(NBT_PLATFORM_WIDTH) || + getTrainNameWidth() != pTag.getByte(NBT_TRAIN_NAME_WIDTH) || + (getPredictions().isEmpty() ^ !pTag.contains(NBT_PREDICTIONS)) + ) { + updateClient = true; + } + } + + super.read(pTag, clientPacket); + + StationInfo info = StationInfo.fromNbt(pTag); + + xSize = pTag.getByte(NBT_XSIZE); + ySize = pTag.getByte(NBT_YSIZE); + color = pTag.getInt(NBT_COLOR); + glowing = pTag.getBoolean(NBT_GLOWING); + isController = pTag.getBoolean(NBT_CONTROLLER); + infoType = EDisplayInfo.getTypeById(pTag.getInt(NBT_INFO_TYPE)); + displayType = EDisplayType.getTypeById(pTag.getInt(NBT_DISPLAY_TYPE)); + setDepartureData( + pTag.contains(NBT_PREDICTIONS) ? new ArrayList<>(pTag.getList(NBT_PREDICTIONS, Tag.TAG_COMPOUND).stream().map(x -> SimpleDeparturePrediction.fromNbt((CompoundTag)x)).toList()) : new ArrayList<>(), + pTag.contains(NBT_NEXT_DEPARTURE_STOPOVERS) ? pTag.getList(NBT_NEXT_DEPARTURE_STOPOVERS, Tag.TAG_STRING).stream().map(x -> ((StringTag)x).getAsString()).toList() : new ArrayList<>(), + pTag.getString(NBT_FILTER), + info, + pTag.getLong(NBT_LAST_REFRESH_TIME), + pTag.getByte(NBT_PLATFORM_WIDTH), + pTag.getByte(NBT_TRAIN_NAME_WIDTH) + ); + + if (updateClient) { + getRenderer().update(level, worldPosition, getBlockState(), this, EUpdateReason.BLOCK_CHANGED); + } + } + + @Override + public CompoundTag serialize() { + CompoundTag nbt = new CompoundTag(); + nbt.putInt(NBT_INFO_TYPE, getInfoType().getId()); + nbt.putInt(NBT_DISPLAY_TYPE, getDisplayType().getId()); + return nbt; + } + + @Override + public void deserialize(CompoundTag nbt) { + infoType = EDisplayInfo.getTypeById(nbt.getInt(NBT_INFO_TYPE)); + displayType = EDisplayType.getTypeById(nbt.getInt(NBT_DISPLAY_TYPE)); + } + + @Override + public AABB getRenderBoundingBox() { + AABB aabb = new AABB(worldPosition); + if (!isController) + return aabb; + Vec3i normal = getDirection().getClockWise().getNormal(); + return aabb.expandTowards(normal.getX() * getXSize(), -getYSize(), normal.getZ() * getXSize()); + } + + public Direction getDirection() { + return getBlockState().getOptionalValue(FlapDisplayBlock.HORIZONTAL_FACING) + .orElse(Direction.SOUTH) + .getOpposite(); + } + + @Nullable + @Override + public ClientboundBlockEntityDataPacket getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this, BlockEntity::getUpdateTag); + } + + @Override + public CompoundTag getUpdateTag() { + return this.saveWithFullMetadata(); + } + + @Override + public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) { + this.load(pkt.getTag()); + this.level.markAndNotifyBlock(this.worldPosition, this.level.getChunkAt(this.worldPosition), this.getBlockState(), this.getBlockState(), 3, 512); + } + + @Override + public IBlockEntityRendererInstance getRenderer() { + return renderer.get(); + } + + @Override + protected AABB createRenderBoundingBox() { + AABB aabb = new AABB(worldPosition); + if (!isController) + return aabb; + Vec3i normal = getDirection().getClockWise().getNormal(); + return aabb.expandTowards(normal.getX() * xSize, -ySize, normal.getZ() * xSize); + } + + @Override + public void addBehaviours(List behaviours) {} + +} \ No newline at end of file diff --git a/src/main/java/de/mrjulsen/crn/block/be/IColorableBlockEntity.java b/src/main/java/de/mrjulsen/crn/block/be/IColorableBlockEntity.java new file mode 100644 index 00000000..17b5aaad --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/be/IColorableBlockEntity.java @@ -0,0 +1,6 @@ +package de.mrjulsen.crn.block.be; + +public interface IColorableBlockEntity { + int getColor(); + boolean isGlowing(); +} diff --git a/src/main/java/de/mrjulsen/crn/block/be/IContraptionBlockEntity.java b/src/main/java/de/mrjulsen/crn/block/be/IContraptionBlockEntity.java new file mode 100644 index 00000000..5a4d09d9 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/be/IContraptionBlockEntity.java @@ -0,0 +1,19 @@ +package de.mrjulsen.crn.block.be; + +import com.simibubi.create.content.contraptions.Contraption; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public interface IContraptionBlockEntity { + /** + * Client-side only! + * @param level + * @param pos + * @param state + * @param contraption + */ + void contraptionTick(Level level, BlockPos pos, BlockState state, Contraption contraption); +} diff --git a/src/main/java/de/mrjulsen/crn/block/be/IMultiblockBlockEntity.java b/src/main/java/de/mrjulsen/crn/block/be/IMultiblockBlockEntity.java new file mode 100644 index 00000000..f4df6c86 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/be/IMultiblockBlockEntity.java @@ -0,0 +1,61 @@ +package de.mrjulsen.crn.block.be; + +import java.util.function.Consumer; + +import de.mrjulsen.crn.ModMain; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +@SuppressWarnings("unchecked") +public interface IMultiblockBlockEntity, B extends Block> { + + byte getWidth(); + byte getHeight(); + byte getMaxWidth(); + byte getMaxHeight(); + boolean isController(); + Class getBlockType(); + Class getBlockEntityType(); + + default T getBlockEntityCasted(Level level, BlockPos otherpos) { + if (!getBlockEntityType().isInstance(level.getBlockEntity(otherpos))) { + return null; + } + return getBlockEntityType().cast(level.getBlockEntity(otherpos)); + } + + boolean connectable(BlockGetter getter, BlockPos a, BlockPos b); + + default void applyToAll(Consumer apply) { + T be = (T)this; + + BlockState blockState = be.getBlockState(); + if (!getBlockType().isInstance(blockState.getBlock())) { + return; + } + + MutableBlockPos pos = be.getBlockPos().mutable(); + Direction side = blockState.getValue(HorizontalDirectionalBlock.FACING).getCounterClockWise(); + + for (int i = 0; i < getWidth() && i < getMaxWidth(); i++) { + BlockPos newPos = pos.relative(side, i); + for (int j = 0; j < getHeight() && j < getMaxHeight(); j++) { + BlockPos newPos2 = newPos.relative(Direction.DOWN, j); + T otherBlockEntity = getBlockEntityCasted(be.getLevel(), newPos2); + if (otherBlockEntity != null) { + apply.accept(otherBlockEntity); + } else { + ModMain.LOGGER.error(String.format("BlockEntity at %s does not exist!", newPos2)); + } + } + } + + } +} diff --git a/src/main/java/de/mrjulsen/crn/block/be/TrainStationClockBlockEntity.java b/src/main/java/de/mrjulsen/crn/block/be/TrainStationClockBlockEntity.java new file mode 100644 index 00000000..2da23d90 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/be/TrainStationClockBlockEntity.java @@ -0,0 +1,32 @@ +package de.mrjulsen.crn.block.be; + +import java.util.List; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import de.mrjulsen.crn.client.ber.TrainStationClockRenderer; +import de.mrjulsen.crn.client.ber.base.IBERInstance; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance; +import de.mrjulsen.crn.util.Cache; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class TrainStationClockBlockEntity extends SmartBlockEntity implements IBERInstance { + + private final Cache> renderer = new Cache<>(() -> new TrainStationClockRenderer(this)); + + public TrainStationClockBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public IBlockEntityRendererInstance getRenderer() { + return renderer.get(); + } + +} \ No newline at end of file diff --git a/src/main/java/de/mrjulsen/crn/block/connected/AdvancedDisplayCTBehaviour.java b/src/main/java/de/mrjulsen/crn/block/connected/AdvancedDisplayCTBehaviour.java new file mode 100644 index 00000000..9c9f572d --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/connected/AdvancedDisplayCTBehaviour.java @@ -0,0 +1,32 @@ +package de.mrjulsen.crn.block.connected; + +import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; +import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; + +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +public class AdvancedDisplayCTBehaviour extends ConnectedTextureBehaviour.Base { + + protected CTSpriteShiftEntry shift; + + public AdvancedDisplayCTBehaviour(CTSpriteShiftEntry shift) { + this.shift = shift; + } + + @Override + public CTSpriteShiftEntry getShift(BlockState state, Direction direction, TextureAtlasSprite sprite) { + return shift; + } + + @Override + public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos, Direction face, Direction primaryOffset, Direction secondaryOffset) { + return reader.getBlockEntity(pos) instanceof AdvancedDisplayBlockEntity blockEntity && blockEntity.connectable(reader, pos, otherPos); + } + +} + diff --git a/src/main/java/de/mrjulsen/crn/block/connected/AdvancedDisplaySmallCTBehaviour.java b/src/main/java/de/mrjulsen/crn/block/connected/AdvancedDisplaySmallCTBehaviour.java new file mode 100644 index 00000000..98ed6f15 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/connected/AdvancedDisplaySmallCTBehaviour.java @@ -0,0 +1,119 @@ +package de.mrjulsen.crn.block.connected; + +import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; +import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; + +import de.mrjulsen.crn.block.AbstractAdvancedDisplayBlock; +import de.mrjulsen.crn.block.AdvancedDisplaySmallBlock; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; + +public class AdvancedDisplaySmallCTBehaviour extends ConnectedTextureBehaviour.Base { + protected CTSpriteShiftEntry topShift; + protected CTSpriteShiftEntry layerShift; + + public AdvancedDisplaySmallCTBehaviour(CTSpriteShiftEntry layerShift) { + this(layerShift, null); + } + + public AdvancedDisplaySmallCTBehaviour(CTSpriteShiftEntry layerShift, CTSpriteShiftEntry topShift) { + this.layerShift = layerShift; + this.topShift = topShift; + } + + @Override + public CTSpriteShiftEntry getShift(BlockState state, Direction direction, TextureAtlasSprite sprite) { + boolean b = false; + switch (state.getValue(AbstractAdvancedDisplayBlock.SIDE)) { + case BOTH: + b = state.getValue(HorizontalDirectionalBlock.FACING).getAxis() == direction.getAxis(); + break; + case BACK: + b = state.getValue(HorizontalDirectionalBlock.FACING).getOpposite() == direction; + break; + default: + b = state.getValue(HorizontalDirectionalBlock.FACING) == direction; + break; + } + return b ? layerShift : null; + } + + @Override + public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos, Direction face, Direction primaryOffset, Direction secondaryOffset) { + if (other.getBlock() != state.getBlock()) { + return false; + } + if (other.getValue(HorizontalDirectionalBlock.FACING) != state.getValue(HorizontalDirectionalBlock.FACING)) { + return false; + } + if (other.getValue(AbstractAdvancedDisplayBlock.SIDE) != state.getValue(AbstractAdvancedDisplayBlock.SIDE)) { + return false; + } + if (other.getValue(AdvancedDisplaySmallBlock.HALF) != state.getValue(AdvancedDisplaySmallBlock.HALF)) { + return false; + } + + return true; + } + + @Override + protected boolean isBeingBlocked(BlockState state, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos, Direction face) { + return (state.getValue(HorizontalDirectionalBlock.FACING) == face && super.isBeingBlocked(state, reader, pos, otherPos, face)); + } + + @Override + protected boolean reverseUVs(BlockState state, Direction face) { + Axis axis = state.getValue(HorizontalDirectionalBlock.FACING).getAxis(); + if (axis == Axis.X) + return face.getAxisDirection() == AxisDirection.NEGATIVE && face.getAxis() != Axis.X; + if (axis == Axis.Z) + return face != Direction.NORTH && face.getAxisDirection() != AxisDirection.POSITIVE; + return super.reverseUVs(state, face); + } + + @Override + protected boolean reverseUVsHorizontally(BlockState state, Direction face) { + return super.reverseUVsHorizontally(state, face); + } + + @Override + protected boolean reverseUVsVertically(BlockState state, Direction face) { + Axis axis = state.getValue(HorizontalDirectionalBlock.FACING).getAxis(); + if (axis == Axis.X && face == Direction.NORTH) + return false; + if (axis == Axis.Z && face == Direction.WEST) + return false; + return super.reverseUVsVertically(state, face); + } + + @Override + protected Direction getUpDirection(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face) { + Axis axis = state.getValue(HorizontalDirectionalBlock.FACING).getAxis(); + if (axis == Axis.Y) + return super.getUpDirection(reader, pos, state, face); + boolean alongX = axis == Axis.X; + if (face.getAxis().isVertical() && alongX) + return super.getUpDirection(reader, pos, state, face).getClockWise(); + if (face.getAxis() == axis || face.getAxis().isVertical()) + return super.getUpDirection(reader, pos, state, face); + return Direction.fromAxisAndDirection(axis, alongX ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE); + } + + @Override + protected Direction getRightDirection(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face) { + Axis axis = state.getValue(HorizontalDirectionalBlock.FACING).getAxis(); + if (axis == Axis.Y) + return super.getRightDirection(reader, pos, state, face); + if (face.getAxis().isVertical() && axis == Axis.X) + return super.getRightDirection(reader, pos, state, face).getClockWise(); + if (face.getAxis() == axis || face.getAxis().isVertical()) + return super.getRightDirection(reader, pos, state, face); + return Direction.fromAxisAndDirection(Axis.Y, face.getAxisDirection()); + } +} diff --git a/src/main/java/de/mrjulsen/crn/block/display/AdvancedDisplaySource.java b/src/main/java/de/mrjulsen/crn/block/display/AdvancedDisplaySource.java new file mode 100644 index 00000000..ad000e4f --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/display/AdvancedDisplaySource.java @@ -0,0 +1,96 @@ +package de.mrjulsen.crn.block.display; + +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.source.DisplaySource; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.content.trains.station.StationBlockEntity; +import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; +import com.simibubi.create.foundation.utility.Lang; + +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.MutableComponent; + +public class AdvancedDisplaySource extends DisplaySource { + + public static final String NBT_ADVANCED_DISPLAY = "AdvancedDisplay"; + public static final String NBT_FILTER = "Filter"; + public static final String NBT_TRAIN_NAME_WIDTH = "TrainNameWidth"; + public static final String NBT_PLATFORM_WIDTH = "PlatformWidth"; + + @Override + public List provideText(DisplayLinkContext context, DisplayTargetStats stats) { + return EMPTY; + } + + @Override + public List> provideFlapDisplayText(DisplayLinkContext context, DisplayTargetStats stats) { + context.sourceConfig().putBoolean(NBT_ADVANCED_DISPLAY, true); + return List.of(); + } + + @Override + protected String getTranslationKey() { + return "advanced_display"; + } + + @Override + public void populateData(DisplayLinkContext context) { + CompoundTag conf = context.sourceConfig(); + + if (!conf.contains(NBT_TRAIN_NAME_WIDTH)) + conf.putInt(NBT_TRAIN_NAME_WIDTH, 16); + if (!conf.contains(NBT_PLATFORM_WIDTH)) + conf.putInt(NBT_PLATFORM_WIDTH, -1); + + if (conf.contains(NBT_FILTER)) + return; + if (!(context.getSourceBlockEntity() instanceof StationBlockEntity stationBe)) + return; + + GlobalStation station = stationBe.getStation(); + if (station == null) + return; + + conf.putString(NBT_FILTER, station.name); + } + + @Override + public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineBuilder builder, boolean isFirstLine) { + if (isFirstLine) { + builder.addTextInput(0, 137, (e, t) -> { + e.setValue(""); + t.withTooltip(ImmutableList.of(Lang.translateDirect("display_source.station_summary.filter") + .withStyle(s -> s.withColor(0x5391E1)), + Lang.translateDirect("gui.schedule.lmb_edit") + .withStyle(ChatFormatting.DARK_GRAY, ChatFormatting.ITALIC))); + }, NBT_FILTER); + return; + } + + builder.addScrollInput(0, 40, (si, l) -> { + si.titled(Utils.translate("gui.createrailwaysnavigator.display_source.advanced_display.train_name_width")) + .addHint(Utils.translate("gui.createrailwaysnavigator.display_source.advanced_display.train_name_width.description")) + .withRange(0, 65) + .withShiftStep(4); + si.setState(16); + l.withSuffix("px"); + }, NBT_TRAIN_NAME_WIDTH); + + builder.addScrollInput(44, 40, (si, l) -> { + si.titled(Utils.translate("gui.createrailwaysnavigator.display_source.advanced_display.platform_width")) + .addHint(Utils.translate("gui.createrailwaysnavigator.display_source.advanced_display.platform_width.description")) + .withRange(-1, 65) + .withShiftStep(4); + si.setState(16); + l.withSuffix("px"); + }, NBT_PLATFORM_WIDTH); + + } + +} diff --git a/src/main/java/de/mrjulsen/crn/block/display/AdvancedDisplayTarget.java b/src/main/java/de/mrjulsen/crn/block/display/AdvancedDisplayTarget.java new file mode 100644 index 00000000..81b9f9fe --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/block/display/AdvancedDisplayTarget.java @@ -0,0 +1,112 @@ +package de.mrjulsen.crn.block.display; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayBoardTarget; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.display.GlobalTrainDisplayData; + +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.data.DeparturePrediction; +import de.mrjulsen.crn.data.GlobalSettingsManager; +import de.mrjulsen.crn.data.TrainStop; +import de.mrjulsen.crn.data.DeparturePrediction.SimpleDeparturePrediction; +import de.mrjulsen.crn.data.SimpleTrainSchedule; +import de.mrjulsen.crn.data.SimulatedTrainSchedule; +import de.mrjulsen.crn.util.TrainUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.AABB; + +public class AdvancedDisplayTarget extends DisplayBoardTarget { + + @Override + public void acceptFlapText(int line, List> text, DisplayLinkContext context) { + + CompoundTag nbt = context.sourceConfig(); + if (!nbt.contains(AdvancedDisplaySource.NBT_ADVANCED_DISPLAY)) { + return; + } + + String filter = context.sourceConfig().getString("Filter"); + + if (context.getTargetBlockEntity() instanceof AdvancedDisplayBlockEntity blockEntity) { + final AdvancedDisplayBlockEntity controller = blockEntity.getController(); + if (controller != null) { + List preds = GlobalTrainDisplayData.prepare(filter, controller.getPlatformInfoLinesCount()).stream().map(x -> new DeparturePrediction(x).simplify()).sorted(Comparator.comparingInt(x -> x.departureTicks())).toList(); + List stopovers = new ArrayList<>(); + + if (!preds.isEmpty()) { + SimpleDeparturePrediction pred = preds.iterator().next(); + SimulatedTrainSchedule sched = SimpleTrainSchedule.of(TrainUtils.getTrainStopsSorted(pred.trainId(), context.blockEntity().getLevel())).simulate(TrainUtils.getTrain(pred.trainId()), 0, pred.stationName()); + + List stops = new ArrayList<>(sched.getAllStops()); + boolean foundStart = false; + + if (!stops.isEmpty()) { + for (int i = 0; i < stops.size() - 1; i++) { + TrainStop x = stops.get(i); + if (foundStart) { + stopovers.add(x.getStationAlias().getAliasName().get()); + } + foundStart = foundStart || x.getPrediction().getStationName().equals(pred.stationName()); + } + } + } + + controller.setDepartureData( + preds, + stopovers, + filter, + GlobalSettingsManager.getInstance().getSettingsData().getAliasFor(filter).getInfoForStation(filter), + context.getTargetBlockEntity().getLevel().getDayTime(), + (byte)context.sourceConfig().getInt(AdvancedDisplaySource.NBT_PLATFORM_WIDTH), + (byte)context.sourceConfig().getInt(AdvancedDisplaySource.NBT_TRAIN_NAME_WIDTH) + ); + controller.sendData(); + } + } + } + + @Override + public boolean isReserved(int line, BlockEntity target, DisplayLinkContext context) { + return super.isReserved(line, target, context) || target instanceof AdvancedDisplayBlockEntity; + } + + @Override + public DisplayTargetStats provideStats(DisplayLinkContext context) { + AdvancedDisplayBlockEntity controller = getController(context); + if (controller == null) + return new DisplayTargetStats(1, 1, this); + return new DisplayTargetStats(1, 1, this); + } + + private AdvancedDisplayBlockEntity getController(DisplayLinkContext context) { + BlockEntity teIn = context.getTargetBlockEntity(); + if (!(teIn instanceof AdvancedDisplayBlockEntity be)) + return null; + return be.getController(); + } + + @Override + public AABB getMultiblockBounds(LevelAccessor level, BlockPos pos) { + AABB baseShape = super.getMultiblockBounds(level, pos); + BlockEntity be = level.getBlockEntity(pos); + + if (!(be instanceof AdvancedDisplayBlockEntity fdbe)) + return baseShape; + + AdvancedDisplayBlockEntity controller = fdbe.getController(); + if (controller == null) + return baseShape; + + Vec3i normal = controller.getDirection().getClockWise().getNormal(); + return baseShape.move(controller.getBlockPos().subtract(pos)).expandTowards(normal.getX() * (controller.getXSize() - 1), 1 - controller.getYSize(), normal.getZ() * (controller.getXSize() - 1)); + } +} \ No newline at end of file diff --git a/src/main/java/de/mrjulsen/crn/client/ClientWrapper.java b/src/main/java/de/mrjulsen/crn/client/ClientWrapper.java index faa08ac0..83b9bff7 100644 --- a/src/main/java/de/mrjulsen/crn/client/ClientWrapper.java +++ b/src/main/java/de/mrjulsen/crn/client/ClientWrapper.java @@ -3,7 +3,9 @@ import java.util.function.Supplier; import de.mrjulsen.crn.Constants; +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; import de.mrjulsen.crn.client.gui.overlay.RouteDetailsOverlayScreen; +import de.mrjulsen.crn.client.gui.screen.AdvancedDisplaySettingsScreen; import de.mrjulsen.crn.client.gui.screen.LoadingScreen; import de.mrjulsen.crn.client.gui.screen.NavigatorScreen; import de.mrjulsen.crn.client.gui.screen.RouteOverlaySettingsScreen; @@ -35,4 +37,8 @@ public static void showRouteOverlaySettingsGui(RouteDetailsOverlayScreen overlay public static void handleErrorMessagePacket(ServerErrorPacket packet, Supplier ctx) { Minecraft.getInstance().getToasts().addToast(new SystemToast(SystemToastIds.PERIODIC_NOTIFICATION, Constants.TEXT_SERVER_ERROR, Utils.text(packet.message))); } + + public static void showAdvancedDisplaySettingsScreen(AdvancedDisplayBlockEntity blockEntity) { + Minecraft.getInstance().setScreen(new AdvancedDisplaySettingsScreen(blockEntity)); + } } diff --git a/src/main/java/de/mrjulsen/crn/client/ber/AdvancedDisplayRenderInstance.java b/src/main/java/de/mrjulsen/crn/client/ber/AdvancedDisplayRenderInstance.java new file mode 100644 index 00000000..9f60fd95 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/AdvancedDisplayRenderInstance.java @@ -0,0 +1,169 @@ +package de.mrjulsen.crn.client.ber; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; + +import de.mrjulsen.crn.block.AbstractAdvancedDisplayBlock; +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.base.AbstractBlockEntityRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.variants.BERPassengerInfoDetailed; +import de.mrjulsen.crn.client.ber.variants.BERPassengerInfoInformative; +import de.mrjulsen.crn.client.ber.variants.BERPassengerInfoSimple; +import de.mrjulsen.crn.client.ber.variants.BERPlatformDetailed; +import de.mrjulsen.crn.client.ber.variants.BERPlatformInformative; +import de.mrjulsen.crn.client.ber.variants.BERPlatformSimple; +import de.mrjulsen.crn.client.ber.variants.BERRenderSubtypeBase; +import de.mrjulsen.crn.client.ber.variants.BERTrainDestinationDetailed; +import de.mrjulsen.crn.client.ber.variants.BERTrainDestinationInformative; +import de.mrjulsen.crn.client.ber.variants.BERTrainDestinationSimple; +import de.mrjulsen.crn.client.ber.variants.IBERRenderSubtype; +import de.mrjulsen.crn.data.EDisplayInfo; +import de.mrjulsen.crn.data.EDisplayType; +import de.mrjulsen.crn.data.ESide; +import de.mrjulsen.crn.data.EDisplayType.EDisplayTypeDataSource; +import de.mrjulsen.crn.util.Pair; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public class AdvancedDisplayRenderInstance extends AbstractBlockEntityRenderInstance { + + private Map>>> renderSubtypes; + + public Collection labels; + public BERText carriageIndexLabel; + public IBERRenderSubtype renderSubtype; + + private int lastXSize = 0; + private EDisplayType lastType; + private EDisplayInfo lastInfo; + + public AdvancedDisplayRenderInstance(AdvancedDisplayBlockEntity blockEntity) { + super(blockEntity); + } + + @Override + protected void preinit(AdvancedDisplayBlockEntity blockEntity) { + this.labels = new ArrayList<>(); + this.renderSubtypes = Map.of( + EDisplayType.TRAIN_DESTINATION, Map.of( + EDisplayInfo.SIMPLE, () -> new BERTrainDestinationSimple(), + EDisplayInfo.DETAILED, () -> new BERTrainDestinationDetailed(), + EDisplayInfo.INFORMATIVE, () -> new BERTrainDestinationInformative() + ), + EDisplayType.PASSENGER_INFORMATION, Map.of( + EDisplayInfo.SIMPLE, () -> new BERPassengerInfoSimple(), + EDisplayInfo.DETAILED, () -> new BERPassengerInfoDetailed(), + EDisplayInfo.INFORMATIVE, () -> new BERPassengerInfoInformative() + ), + EDisplayType.PLATFORM, Map.of( + EDisplayInfo.SIMPLE, () -> new BERPlatformSimple(), + EDisplayInfo.DETAILED, () -> new BERPlatformDetailed(), + EDisplayInfo.INFORMATIVE, () -> new BERPlatformInformative() + ) + ); + } + + public MutableComponent getStopoversString(AdvancedDisplayBlockEntity blockEntity) { + MutableComponent line = Utils.text(""); + + List stopovers = blockEntity.getDisplayType().getSource() == EDisplayTypeDataSource.TRAIN_INFORMATION ? + blockEntity.getTrainData().stopovers().stream().map(x -> x.stationTagName()).toList() : + blockEntity.getNextDepartureStopovers(); + + Iterator i = stopovers.iterator(); + boolean isFirst = true; + while (i.hasNext()) { + if (!isFirst) { + line = line.append(Utils.text(" ● ")); + } + line = line.append(Utils.text(i.next())); + isFirst = false; + } + return line; + } + + @Override + public void render(BlockEntityRendererContext context, AdvancedDisplayBlockEntity pBlockEntity, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay) { + + if (!pBlockEntity.isController()) { + return; + } + + final int light = pBlockEntity.isGlowing() ? LightTexture.FULL_BRIGHT : pPackedLight; + + if (pBlockEntity.getBlockState().getBlock() instanceof AbstractAdvancedDisplayBlock) { + + Pair offset = pBlockEntity.renderOffset.get(); + Pair zOffset = pBlockEntity.renderZOffset.get(); + float scale = pBlockEntity.renderScale.get(); + + if (pBlockEntity.getBlockState().getValue(AbstractAdvancedDisplayBlock.SIDE) == ESide.FRONT || pBlockEntity.getBlockState().getValue(AbstractAdvancedDisplayBlock.SIDE) == ESide.BOTH) { + pPoseStack.pushPose(); + pPoseStack.translate(offset.getFirst(), offset.getSecond(), zOffset.getFirst()); + pPoseStack.scale(scale, scale, 1); + renderSubtype.renderAdditional(context, pBlockEntity, this, pPartialTicks, pPoseStack, pBufferSource, light, pOverlay, false); + labels.forEach(x -> x.render(pPoseStack, pBufferSource, light)); + pPoseStack.popPose(); + } + if (pBlockEntity.getBlockState().getValue(AbstractAdvancedDisplayBlock.SIDE) == ESide.BACK || pBlockEntity.getBlockState().getValue(AbstractAdvancedDisplayBlock.SIDE) == ESide.BOTH) { + pPoseStack.pushPose(); + pPoseStack.mulPose(Axis.YP.rotationDegrees(180)); + pPoseStack.translate(-pBlockEntity.getXSize() * 16, 0, -16); + pPoseStack.translate(offset.getFirst(), offset.getSecond(), zOffset.getSecond()); + pPoseStack.scale(scale, scale, 1); + renderSubtype.renderAdditional(context, pBlockEntity, this, pPartialTicks, pPoseStack, pBufferSource, light, pOverlay, true); + labels.forEach(x -> x.render(pPoseStack, pBufferSource, light)); + pPoseStack.popPose(); + } + } + } + + @Override + public void tick(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity) { + renderSubtype.tick(level, pos, state, blockEntity, this); + labels.forEach(x -> x.tick()); + + if (blockEntity.getXSizeScaled() != lastXSize) { + update(level, pos, state, blockEntity, EUpdateReason.BLOCK_CHANGED); + } + lastXSize = blockEntity.getXSizeScaled(); + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, EUpdateReason reason) { + carriageIndexLabel = null; + EDisplayType type = blockEntity.getDisplayType(); + EDisplayInfo info = blockEntity.getInfoType(); + + if (lastType != type || lastInfo != info) { + if (renderSubtypes.containsKey(type)) { + Map>> selectedType = renderSubtypes.get(type); + if (selectedType.containsKey(info)) { + renderSubtype = selectedType.get(info).get(); + } + } + + if (renderSubtype == null) { + renderSubtype = new BERRenderSubtypeBase<>(); + } + } + + lastType = type; + lastInfo = info; + + renderSubtype.update(level, pos, state, blockEntity, this, reason); + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/TrainStationClockRenderer.java b/src/main/java/de/mrjulsen/crn/client/ber/TrainStationClockRenderer.java new file mode 100644 index 00000000..b5a660e8 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/TrainStationClockRenderer.java @@ -0,0 +1,50 @@ +package de.mrjulsen.crn.client.ber; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; + +import de.mrjulsen.crn.Constants; +import de.mrjulsen.crn.block.be.TrainStationClockBlockEntity; +import de.mrjulsen.crn.client.ber.base.AbstractBlockEntityRenderInstance; +import de.mrjulsen.crn.util.ModUtils; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; + +public class TrainStationClockRenderer extends AbstractBlockEntityRenderInstance { + + public TrainStationClockRenderer(TrainStationClockBlockEntity blockEntity) { + super(blockEntity); + } + + @Override + public void render(BlockEntityRendererContext context, TrainStationClockBlockEntity pBlockEntity, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay) { + + context.renderUtils().initRenderEngine(); + + float z = 3.2f; + + pPoseStack.translate(8, 8, 8 + z); + pPoseStack.pushPose(); + pPoseStack.mulPose(Axis.ZP.rotationDegrees(-90 + ModUtils.clockHandDegrees(pBlockEntity.getLevel().getDayTime() + Constants.TIME_SHIFT, 12000))); + context.renderUtils().fillColor(pBufferSource, pBlockEntity, 0xFF191919, pPoseStack, -0.5f, -0.5f, 0, 6, 1, pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), pPackedLight); + pPoseStack.popPose(); + + pPoseStack.pushPose(); + pPoseStack.mulPose(Axis.ZP.rotationDegrees(-90 + ModUtils.clockHandDegrees(pBlockEntity.getLevel().getDayTime() + Constants.TIME_SHIFT, 1000))); + context.renderUtils().fillColor(pBufferSource, pBlockEntity, 0xFF222222, pPoseStack, -0.5f, -0.5f, 0.1f, 7, 1, pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), pPackedLight); + pPoseStack.popPose(); + + pPoseStack.translate(0, 0, -z * 2); + pPoseStack.pushPose(); + pPoseStack.mulPose(Axis.ZN.rotationDegrees(-90 + ModUtils.clockHandDegrees(pBlockEntity.getLevel().getDayTime() + Constants.TIME_SHIFT, 12000))); + pPoseStack.mulPose(Axis.YP.rotationDegrees(180)); + context.renderUtils().fillColor(pBufferSource, pBlockEntity, 0xFF191919, pPoseStack, -0.5f, -0.5f, 0, 6, 1, pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), pPackedLight); + pPoseStack.popPose(); + + pPoseStack.pushPose(); + pPoseStack.mulPose(Axis.ZN.rotationDegrees(-90 + ModUtils.clockHandDegrees(pBlockEntity.getLevel().getDayTime() + Constants.TIME_SHIFT, 1000))); + pPoseStack.mulPose(Axis.YP.rotationDegrees(180)); + context.renderUtils().fillColor(pBufferSource, pBlockEntity, 0xFF222222, pPoseStack, -0.5f, -0.5f, 0.1f, 7, 1, pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), pPackedLight); + pPoseStack.popPose(); + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/base/AbstractBlockEntityRenderInstance.java b/src/main/java/de/mrjulsen/crn/client/ber/base/AbstractBlockEntityRenderInstance.java new file mode 100644 index 00000000..7ff32fbe --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/base/AbstractBlockEntityRenderInstance.java @@ -0,0 +1,14 @@ +package de.mrjulsen.crn.client.ber.base; + +import net.minecraft.world.level.block.entity.BlockEntity; + +public abstract class AbstractBlockEntityRenderInstance implements IBlockEntityRendererInstance { + + public AbstractBlockEntityRenderInstance(T blockEntity) { + preinit(blockEntity); + update(blockEntity.getLevel(), blockEntity.getBlockPos(), blockEntity.getBlockState(), blockEntity, EUpdateReason.INITIALIZED); + } + + protected void preinit(T blockEntity) {} + +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/base/BERText.java b/src/main/java/de/mrjulsen/crn/client/ber/base/BERText.java new file mode 100644 index 00000000..e35e24c2 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/base/BERText.java @@ -0,0 +1,349 @@ +package de.mrjulsen.crn.client.ber.base; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import com.mojang.blaze3d.font.GlyphInfo; +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.mixin.BakedGlyphAccessor; +import de.mrjulsen.crn.util.FontUtils; +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; +import net.minecraft.util.StringDecomposer; + +/** + * A text component designed for block entity rendering. It supports scissoring and scrolling text, e.g. for display boards. + */ +public class BERText { + + private static final byte CHAR_SIZE = 8; + + private final FontUtils fontUtils; + private final float xOffset; + private Supplier> textData; + + private float minX = 0; + private float maxX = Float.MAX_VALUE; + private float minStretchScale = 1.0f; + private float maxStretchScale = 1.0f; + private float maxWidth = Float.MAX_VALUE; + private boolean forceMaxWidth = false; + private float scrollSpeed = 0.0f; + private boolean centered = false; + private int color = 0xFFFFFFFF; + private int ticksPerPage = 200; + private int refreshRate = 0; + private Consumer onUpdate; + + private TextTransformation predefinedTextTransformation = null; + + // stored data + private TextDataCache cache; + private float scrollXOffset = 0.0f; + private int refreshTimer = 0; + private int currentTicks = 0; + private int currentIndex = 0; + private List texts; + + public BERText(FontUtils fontUtils, Component text, float xOffset) { + this.fontUtils = fontUtils; + this.textData = () -> List.of(text); + this.xOffset = xOffset; + } + + public BERText(FontUtils fontUtils, Supplier> texts, float xOffset) { + this.fontUtils = fontUtils; + this.textData = texts; + this.xOffset = xOffset; + } + + public BERText withStencil(float minX, float maxX) { + this.minX = minX; + this.maxX = maxX; + return this; + } + + public BERText withStretchScale(float minScale, float maxScale) { + this.minStretchScale = minScale; + this.maxStretchScale = maxScale; + return this; + } + + public BERText withMaxWidth(float maxWidth, boolean force) { + this.maxWidth = maxWidth; + this.forceMaxWidth = force; + return this; + } + + public BERText withIsCentered(boolean b) { + this.centered = b; + return this; + } + + public BERText withCanScroll(boolean b, float scrollingSpeed) { + this.scrollSpeed = b ? scrollingSpeed : 0; + return this; + } + + public BERText withColor(int color) { + this.color = color; + return this; + } + + public BERText withTicksPerPage(int ticks) { + this.ticksPerPage = ticks; + return this; + } + + /** + * The displayed text is updated every x ticks. If the value is less than or equal to 0, then the text will not be updated. + */ + public BERText withRefreshRate(int ticks) { + this.refreshRate = ticks; + return this; + } + + public BERText withPredefinedTextTransformation(TextTransformation transformation) { + this.predefinedTextTransformation = transformation; + return this; + } + + public BERText withUpdateFunc(Consumer onUpdate) { + this.onUpdate = onUpdate; + return this; + } + + public BERText build() { + fetchCurrentText(); + calc(false); + scrollXOffset = cache.maxWidthScaled(); + return this; + } + + public FontUtils getFontUtils() { + return fontUtils; + } + + private void fetchCurrentText() { + texts = textData.get(); + } + + public Component getCurrentText() { + return texts.get(currentIndex); + } + + public List getTexts() { + return texts; + } + + public int getTicksPerPage() { + return ticksPerPage; + } + + public float getXOffset() { + return xOffset; + } + + public float getMinX() { + return minX; + } + + public float getMaxX() { + return maxX; + } + + public float getMinStretchScale() { + return minStretchScale; + } + + public float getMaxStretchScale() { + return maxStretchScale; + } + + public float getMaxWidth() { + return maxWidth; + } + + public boolean forceMaxWidth() { + return forceMaxWidth; + } + + public boolean canScroll() { + return scrollSpeed > 0; + } + + public float getScrollSpeed() { + return scrollSpeed; + } + + public boolean isCentered() { + return centered; + } + + public float getTextWidth() { + return getFontUtils().font.width(getCurrentText()); + } + + public float getScaledTextWidth() { + return getTextWidth() * cache.textXScale(); + } + + public int getColor() { + return color; + } + + public void recalc() { + calc(false); + } + + protected void calc(boolean callUpdate) { + float textWidth = getFontUtils().font.width(getCurrentText()); + float rawXScale = getMaxWidth() / textWidth; + float finalXScale = de.mrjulsen.mcdragonlib.utils.Math.clamp(rawXScale, getMinStretchScale(), getMaxStretchScale()); + boolean mustScroll = rawXScale < getMinStretchScale(); + + if (forceMaxWidth() && mustScroll) { + finalXScale = getMaxStretchScale(); + } + + float minX = getMinX() / finalXScale; + float maxWidthScaled = getMaxWidth() / finalXScale; + float maxX = Math.min(forceMaxWidth() ? maxWidthScaled : Float.MAX_VALUE, getMaxX() / finalXScale); + float xOffset = getXOffset() + (isCentered() ? maxWidthScaled / 2 - textWidth / 2 : 0); + cache = new TextDataCache(finalXScale, minX, maxX, xOffset, maxWidthScaled, textWidth, forceMaxWidth() && mustScroll && canScroll()); + + if (callUpdate && onUpdate != null) { + onUpdate.accept(this); + } + } + + public void render(PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight) { + getFontUtils().reset(); + pPoseStack.pushPose(); { + if (predefinedTextTransformation != null) { + pPoseStack.translate(predefinedTextTransformation.x(), predefinedTextTransformation.y(), predefinedTextTransformation.z()); + pPoseStack.scale(predefinedTextTransformation.xScale(), predefinedTextTransformation.yScale(), 1); + } + + pPoseStack.pushPose(); { + pPoseStack.scale(cache.textXScale(), 1, 1); + renderTextInBounds(pPoseStack, getFontUtils(), pBufferSource, getCurrentText(), pPackedLight, cache.mustScroll ? scrollXOffset : cache.xOffset(), cache.minX(), cache.maxX(), getColor()); + } + pPoseStack.popPose(); + } + pPoseStack.popPose(); + } + + private void renderTextInBounds(PoseStack pPoseStack, FontUtils fontUtils, MultiBufferSource pBufferSource, Component text, int pPackedLight, float xOffset, float xLeft, float xRight, int color) { + if (xRight <= xLeft) { + return; + } + + pPoseStack.pushPose(); + pPoseStack.translate(xLeft + (xOffset > 0 ? xOffset : 0), 0, 0); + Font.StringRenderOutput sro = fontUtils.font.new StringRenderOutput(pBufferSource, 0, 0, color, false, pPoseStack.last().pose(), Font.DisplayMode.NORMAL, pPackedLight); + + float newX = xOffset; + float glyphTranslation = 0; + final float charSize = CHAR_SIZE + (text.getStyle().isBold() ? 1 : 0); + + for (int i = 0; i < text.getString().length(); i++) { + int charCode = text.getString().charAt(i); + GlyphInfo info = fontUtils.fontSet.getGlyphInfo(charCode, false); + float glyphWidth = info.getAdvance(text.getStyle().isBold()); + float oldX = newX; + newX += glyphWidth; + + if (newX > xLeft && oldX < xLeft) { + float diff = xLeft - oldX; + BakedGlyphAccessor glyph = fontUtils.getGlyphAccessor(charCode); + float glyphUVDiff = glyph.getU1() - glyph.getU0(); + float scale = (1.0f / charSize * diff); + float sub = glyphUVDiff * scale; + + fontUtils.pushUV(charCode); + glyph.setU0(glyph.getU0() + sub); + + pPoseStack.pushPose(); + float invScale = 1.0f - scale; + pPoseStack.scale(invScale, 1, 1); + Font.StringRenderOutput sro2 = fontUtils.font.new StringRenderOutput(pBufferSource, 0 , 0, color, false, pPoseStack.last().pose(), Font.DisplayMode.NORMAL, pPackedLight); + StringDecomposer.iterateFormatted(String.valueOf((char)charCode), text.getStyle(), sro2); + pPoseStack.popPose(); + fontUtils.popUV(charCode); + pPoseStack.translate(glyphWidth - (charSize * scale), 0, 0); + continue; + } else if (newX > xRight) { + float diff = newX - xRight; + float charRightSpace = charSize - glyphWidth; + float totalDiff = diff + charRightSpace; + + BakedGlyphAccessor glyph = fontUtils.getGlyphAccessor(charCode); + float glyphUVDiff = glyph.getU1() - glyph.getU0(); + float scale = (1.0f / charSize * totalDiff); + float sub = glyphUVDiff * scale; + + fontUtils.pushUV(charCode); + glyph.setU1(glyph.getU1() - sub); + pPoseStack.pushPose(); + float invScale = 1.0f - scale; + pPoseStack.scale(invScale, 1, 1); + pPoseStack.translate(glyphTranslation / invScale, 0, 0); + Font.StringRenderOutput sro2 = fontUtils.font.new StringRenderOutput(pBufferSource, 0, 0, color, false, pPoseStack.last().pose(), Font.DisplayMode.NORMAL, pPackedLight); + StringDecomposer.iterateFormatted(String.valueOf((char)charCode), text.getStyle(), sro2); + pPoseStack.popPose(); + fontUtils.popUV(charCode); + break; + } else if (oldX >= xLeft && newX <= xRight) { + StringDecomposer.iterateFormatted(String.valueOf((char)charCode), text.getStyle(), sro); + } else { + continue; + } + + glyphTranslation += glyphWidth; + } + pPoseStack.popPose(); + } + + public void tick() { + + if (refreshRate > 0) { + refreshTimer++; + if ((refreshTimer %= refreshRate) == 0) { + fetchCurrentText(); + calc(true); + } + } + + boolean multiText = getTexts().size() > 1; + + if (cache.mustScroll()) { + scrollXOffset -= getScrollSpeed() / this.getMaxStretchScale(); + if (scrollXOffset < -cache.textWidth()) { + scrollXOffset = cache.maxWidthScaled(); + + if (multiText) { + currentIndex++; + fetchCurrentText(); + currentIndex %= getTexts().size(); + calc(true); + } + } + } else if (multiText) { + currentTicks++; + if ((currentTicks %= getTicksPerPage()) == 0) { + currentIndex++; + fetchCurrentText(); + currentIndex %= getTexts().size(); + calc(true); + } + } + } + + protected static record TextDataCache(float textXScale, float minX, float maxX, float xOffset, float maxWidthScaled, float textWidth, boolean mustScroll) {} + public static record TextTransformation(float x, float y, float z, float xScale, float yScale) {} + +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/base/IBERInstance.java b/src/main/java/de/mrjulsen/crn/client/ber/base/IBERInstance.java new file mode 100644 index 00000000..52243e36 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/base/IBERInstance.java @@ -0,0 +1,7 @@ +package de.mrjulsen.crn.client.ber.base; + +import net.minecraft.world.level.block.entity.BlockEntity; + +public interface IBERInstance { + IBlockEntityRendererInstance getRenderer(); +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/base/IBlockEntityRendererInstance.java b/src/main/java/de/mrjulsen/crn/client/ber/base/IBlockEntityRendererInstance.java new file mode 100644 index 00000000..f4dbbedb --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/base/IBlockEntityRendererInstance.java @@ -0,0 +1,63 @@ +package de.mrjulsen.crn.client.ber.base; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.util.BERUtils; +import de.mrjulsen.crn.util.FontUtils; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Style; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public interface IBlockEntityRendererInstance { + + final FontUtils fontUtils = new FontUtils(Style.DEFAULT_FONT); + + /** + * The rendering method. + * @param context + * @param pBlockEntity + * @param pPartialTicks + * @param pPoseStack + * @param pBufferSource + * @param pPackedLight + * @param pOverlay + */ + void render(BlockEntityRendererContext context, T pBlockEntity, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay); + + /** + * Called every tick. Can be used for animations. + * @param level + * @param pos + * @param state + * @param blockEntity + */ + default void tick(Level level, BlockPos pos, BlockState state, T blockEntity) { } + + /** + * Called when the content of the BER changes. Can be used to perform recalculations only when necessary. + * @param level + * @param pos + * @param state + * @param blockEntity + */ + default void update(Level level, BlockPos pos, BlockState state, T blockEntity, EUpdateReason reason) { } + + default FontUtils getFontUtils() { + return fontUtils; + } + + /** + * Additional data from the default Block Entity Renderer. + */ + public static record BlockEntityRendererContext(BlockEntityRendererProvider.Context context, BERUtils renderUtils) {} + + public static enum EUpdateReason { + INITIALIZED, + DATA_CHANGED, + BLOCK_CHANGED + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/base/RotatableBlockEntityRenderer.java b/src/main/java/de/mrjulsen/crn/client/ber/base/RotatableBlockEntityRenderer.java new file mode 100644 index 00000000..fbc9ebf0 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/base/RotatableBlockEntityRenderer.java @@ -0,0 +1,44 @@ +package de.mrjulsen.crn.client.ber.base; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; + +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class RotatableBlockEntityRenderer extends SafeBlockEntityRenderer { + + protected final Font font; + + public RotatableBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + this.font = context.getFont(); + } + + @Override + protected final void renderSafe(T pBlockEntity, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay) { + BlockState blockState = pBlockEntity.getBlockState(); + + pPoseStack.pushPose(); + pPoseStack.translate(0.5D, 0, 0.5F); + pPoseStack.mulPose(Axis.YP.rotationDegrees( + blockState.getValue(HorizontalDirectionalBlock.FACING) == Direction.EAST || blockState.getValue(HorizontalDirectionalBlock.FACING) == Direction.WEST + ? blockState.getValue(HorizontalDirectionalBlock.FACING).getOpposite().toYRot() + : blockState.getValue(HorizontalDirectionalBlock.FACING).toYRot() + )); + pPoseStack.translate(-0.5f, 1, -0.5f); + pPoseStack.scale(0.0625f, -0.0625f, 0.0625f); + + renderBlock(pBlockEntity, pPartialTicks, pPoseStack, pBufferSource, pPackedLight, pOverlay); + + pPoseStack.popPose(); + + } + + protected abstract void renderBlock(T pBlockEntity, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay); +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/base/StaticBlockEntityRenderer.java b/src/main/java/de/mrjulsen/crn/client/ber/base/StaticBlockEntityRenderer.java new file mode 100644 index 00000000..e8029387 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/base/StaticBlockEntityRenderer.java @@ -0,0 +1,26 @@ +package de.mrjulsen.crn.client.ber.base; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.BlockEntityRendererContext; +import de.mrjulsen.crn.util.BERUtils; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class StaticBlockEntityRenderer> extends RotatableBlockEntityRenderer { + + private final BlockEntityRendererContext context; + + public StaticBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + super(context); + this.context = new BlockEntityRendererContext(context, new BERUtils()); + } + + @Override + protected void renderBlock(T pBlockEntity, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay) { + context.renderUtils().initRenderEngine(); + pBlockEntity.getRenderer().render(context, pBlockEntity, pPartialTicks, pPoseStack, pBufferSource, pPackedLight, pOverlay); + } + +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPassengerInfoDetailed.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPassengerInfoDetailed.java new file mode 100644 index 00000000..68166ff9 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPassengerInfoDetailed.java @@ -0,0 +1,203 @@ +package de.mrjulsen.crn.client.ber.variants; + +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.base.BERText.TextTransformation; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.BlockEntityRendererContext; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.crn.client.gui.ModGuiIcons; +import de.mrjulsen.crn.config.ModClientConfig; +import de.mrjulsen.crn.data.GlobalSettingsManager; +import de.mrjulsen.crn.data.DeparturePrediction.TrainExitSide; +import de.mrjulsen.crn.event.listeners.JourneyListener.State; +import de.mrjulsen.mcdragonlib.utils.TimeUtils; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; + +public class BERPassengerInfoDetailed implements IBERRenderSubtype { + + private State state = State.WHILE_TRAVELING; + + private static final String keyNextStop = "gui.createrailwaysnavigator.route_overview.next_stop"; + private static final String keyDate = "gui.createrailwaysnavigator.route_overview.date"; + + @Override + public boolean isSingleLined() { + return true; + } + + @Override + public void tick(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent) { + if (pBlockEntity.getTrainData() == null) { + return; + } + + boolean dirty = false; + + if (pBlockEntity.getTrainData().getNextStop().isPresent()) { + if (this.state != State.WHILE_NEXT_STOP && pBlockEntity.getTrainData().getNextStop().get().departureTicks() <= 0) { + this.state = State.WHILE_NEXT_STOP; + dirty = true; + } else if (this.state != State.BEFORE_NEXT_STOP && pBlockEntity.getTrainData().getNextStop().get().departureTicks() <= ModClientConfig.NEXT_STOP_ANNOUNCEMENT.get() && pBlockEntity.getTrainData().getNextStop().get().departureTicks() > 0) { + this.state = State.BEFORE_NEXT_STOP; + dirty = true; + } else if (this.state != State.WHILE_TRAVELING && pBlockEntity.getTrainData().getNextStop().get().departureTicks() > ModClientConfig.NEXT_STOP_ANNOUNCEMENT.get()) { + this.state = State.WHILE_TRAVELING; + dirty = true; + } + } + + if (dirty) { + update(level, pos, state, pBlockEntity, parent, EUpdateReason.DATA_CHANGED); + } + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + if (blockEntity.getTrainData() == null) { + return; + } + + parent.labels.clear(); + + switch (this.state) { + case BEFORE_NEXT_STOP: + updateAnnounceNextStop(level, pos, state, blockEntity, parent); + break; + case WHILE_NEXT_STOP: + updateWhileNextStop(level, pos, state, blockEntity, parent); + break; + default: + updateDefault(level, pos, state, blockEntity, parent); + break; + } + } + + @Override + public void renderAdditional(BlockEntityRendererContext context, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay, Boolean backSide) { + if (state == State.WHILE_NEXT_STOP || state == State.BEFORE_NEXT_STOP) { + context.renderUtils().initRenderEngine(); + TrainExitSide side = pBlockEntity.relativeExitDirection.get(); + float uv = 1.0f / 256.0f; + + if (backSide) { + side = side.getOpposite(); + } + + switch (side) { + case RIGHT: + context.renderUtils().renderTexture( + ModGuiIcons.ICON_LOCATION, + pBufferSource, + pBlockEntity, + pPoseStack, + pBlockEntity.getXSizeScaled() * 16 - 3 - 8, + 4, + 0, + 8, + 8, + uv * ModGuiIcons.ARROW_RIGHT.getU(), + uv * ModGuiIcons.ARROW_RIGHT.getV(), + uv * (ModGuiIcons.ARROW_RIGHT.getU() + ModGuiIcons.ICON_SIZE), + uv * (ModGuiIcons.ARROW_RIGHT.getV() + ModGuiIcons.ICON_SIZE), + pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), + (0xFF << 24) | (pBlockEntity.getColor()), + pPackedLight + ); + break; + case LEFT: + context.renderUtils().renderTexture( + ModGuiIcons.ICON_LOCATION, + pBufferSource, + pBlockEntity, + pPoseStack, + 3f, + 4, + 0, + 8, + 8, + uv * ModGuiIcons.ARROW_LEFT.getU(), + uv * ModGuiIcons.ARROW_LEFT.getV(), + uv * (ModGuiIcons.ARROW_LEFT.getU() + ModGuiIcons.ICON_SIZE), + uv * (ModGuiIcons.ARROW_LEFT.getV() + ModGuiIcons.ICON_SIZE), + pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), + (0xFF << 24) | (pBlockEntity.getColor()), + pPackedLight + ); + break; + default: + break; + } + } + } + + private void updateDefault(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + int displayWidth = blockEntity.getXSizeScaled(); + boolean isSingleBlock = blockEntity.getXSizeScaled() <= 1; + + float maxWidth = displayWidth * 16 - 6; + parent.labels.add(new BERText(parent.getFontUtils(), () -> List.of( + Utils.text(blockEntity.getTrainData().trainName()).append(" ").append(Utils.text(blockEntity.getTrainData().getNextStop().get().scheduleTitle())), + Utils.text("" + (int)Math.abs(Math.round(blockEntity.getTrainData().speed() * 20 * 3.6F))).append(" km/h"), + isSingleBlock ? + Utils.text(TimeUtils.parseTime((int)(blockEntity.getLevel().dayTime() % 24000), ModClientConfig.TIME_FORMAT.get())) : + Utils.translate(keyDate, blockEntity.getLevel().getDayTime() / 24000, TimeUtils.parseTime((int)(blockEntity.getLevel().dayTime() % 24000), ModClientConfig.TIME_FORMAT.get())) + ), 0) + .withIsCentered(true) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.75f, 0.75f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3, 5.5f, 0.0f, 1, 0.75f)) + .build() + ); + } + + private void updateAnnounceNextStop(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + int displayWidth = blockEntity.getXSizeScaled(); + TrainExitSide side = blockEntity.relativeExitDirection.get(); + + MutableComponent line = Utils.translate(keyNextStop, GlobalSettingsManager.getInstance().getSettingsData().getAliasFor(blockEntity.getTrainData().getNextStop().get().stationTagName()).getAliasName().get()); + float maxWidth = displayWidth * 16 - 6 - (side != TrainExitSide.UNKNOWN ? 10 : 0); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(true) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.75f, 0.75f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3 + (side == TrainExitSide.LEFT ? 10 : 0), 5.5f, 0.0f, 1, 0.75f)) + .build() + ); + } + + private void updateWhileNextStop(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + int displayWidth = blockEntity.getXSizeScaled(); + + TrainExitSide side = blockEntity.relativeExitDirection.get(); + MutableComponent line = Utils.text(GlobalSettingsManager.getInstance().getSettingsData().getAliasFor(blockEntity.getTrainData().getNextStop().get().stationTagName()).getAliasName().get()); + + float maxWidth = displayWidth * 16 - 6 - (side != TrainExitSide.UNKNOWN ? 10 : 0); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(true) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.75f, 0.75f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3 + (side == TrainExitSide.LEFT ? 10 : 0), 5.5f, 0.0f, 1, 0.75f)) + .build() + ); + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPassengerInfoInformative.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPassengerInfoInformative.java new file mode 100644 index 00000000..2795ba4e --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPassengerInfoInformative.java @@ -0,0 +1,524 @@ +package de.mrjulsen.crn.client.ber.variants; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.Constants; +import de.mrjulsen.crn.ModMain; +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.base.BERText.TextTransformation; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.BlockEntityRendererContext; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.crn.client.gui.ModGuiIcons; +import de.mrjulsen.crn.config.ModClientConfig; +import de.mrjulsen.crn.data.SimpleTrainConnection; +import de.mrjulsen.crn.data.DeparturePrediction.TrainExitSide; +import de.mrjulsen.crn.data.DeparturePrediction.SimpleDeparturePrediction; +import de.mrjulsen.crn.event.listeners.JourneyListener.State; +import de.mrjulsen.crn.network.InstanceManager; +import de.mrjulsen.crn.network.NetworkManager; +import de.mrjulsen.crn.network.packets.cts.NextConnectionsRequestPacket; +import de.mrjulsen.mcdragonlib.DragonLibConstants; +import de.mrjulsen.mcdragonlib.utils.TimeUtils; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; + +public class BERPassengerInfoInformative implements IBERRenderSubtype { + + private static final ResourceLocation TEXTURE = new ResourceLocation(ModMain.MOD_ID, "textures/gui/overview.png"); + private static final int TEX_ROUTE_PATH_U = 226; + private static final int TEX_ROUTE_PATH_H = 14; + private static final float PANEL_LINE_HEIGHT = 2.0f; + private static final float PANEL_Y_START = 5.75f; + private static final int NEXT_CONNECTIONS_MAX_ENTRIES_PER_PAGE = 3; + private static final int NEXT_CONNECTIONS_PAGE_TIMER = 100; + + private BERText timeLabel; + private BERText titleLabel; + private State state = State.WHILE_TRAVELING; + + // data + private List nextConnections; + private long nextConnectionsRefreshTime = 0; + private int nextConnectionsPage = 0; + private int nextConnectionsMaxPage = 0; + private int nextConnectionsTimer = 0; + + // Cache + private TrainExitSide lastKnownExitSide = TrainExitSide.UNKNOWN; + + private static final String keyNextStop = "gui.createrailwaysnavigator.route_overview.next_stop"; + private static final Component textNextConnections = Utils.translate("gui.createrailwaysnavigator.route_overview.next_connections").withStyle(ChatFormatting.BOLD); + + @Override + public boolean isSingleLined() { + return false; + } + + @SuppressWarnings("resource") + @Override + public void tick(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent) { + if (pBlockEntity.getTrainData() == null) { + return; + } + + boolean dirty = false; + + if (pBlockEntity.getTrainData().getNextStop().isPresent()) { + if (this.state != State.WHILE_NEXT_STOP && pBlockEntity.getTrainData().getNextStop().get().departureTicks() <= 0) { + this.state = State.WHILE_NEXT_STOP; + dirty = true; + } else if (this.state != State.BEFORE_NEXT_STOP && pBlockEntity.getTrainData().getNextStop().get().departureTicks() <= ModClientConfig.NEXT_STOP_ANNOUNCEMENT.get() && pBlockEntity.getTrainData().getNextStop().get().departureTicks() > 0) { + this.state = State.BEFORE_NEXT_STOP; + this.nextConnections = null; + long id = InstanceManager.registerClientNextConnectionsResponseAction((data, refreshTime) -> { + this.nextConnections = new ArrayList<>(data); + nextConnectionsPage = 0; + nextConnectionsTimer = 0; + nextConnectionsRefreshTime = refreshTime; + if (data != null && !data.isEmpty()) { + nextConnectionsMaxPage = (int)(nextConnections.size() / NEXT_CONNECTIONS_MAX_ENTRIES_PER_PAGE + (nextConnections.size() % NEXT_CONNECTIONS_MAX_ENTRIES_PER_PAGE == 0 ? 0 : 1)); + parent.labels.clear(); + updateNextConnections(level, pos, state, pBlockEntity, parent); + } + }); + NetworkManager.getInstance().sendToServer(Minecraft.getInstance().player.connection.getConnection(), new NextConnectionsRequestPacket(id, pBlockEntity.getTrainData().trainId(), pBlockEntity.getTrainData().getNextStop().get().stationTagName(), pBlockEntity.getTrainData().getNextStop().get().departureTicks())); + dirty = true; + } else if (this.state != State.WHILE_TRAVELING && pBlockEntity.getTrainData().getNextStop().get().departureTicks() > ModClientConfig.NEXT_STOP_ANNOUNCEMENT.get()) { + this.state = State.WHILE_TRAVELING; + dirty = true; + } + } + + if (this.state == State.BEFORE_NEXT_STOP && this.nextConnections != null && !this.nextConnections.isEmpty()) { + nextConnectionsTimer++; + if ((nextConnectionsTimer %= NEXT_CONNECTIONS_PAGE_TIMER) == 0) { + nextConnectionsPage++; + nextConnectionsPage %= nextConnectionsMaxPage; + + parent.labels.clear(); + updateNextConnections(level, pos, state, pBlockEntity, parent); + } + } + + if (this.state != State.WHILE_TRAVELING && lastKnownExitSide != pBlockEntity.relativeExitDirection.get()) { + dirty = true; + } + lastKnownExitSide = pBlockEntity.relativeExitDirection.get(); + + if (dirty) { + update(level, pos, state, pBlockEntity, parent, EUpdateReason.DATA_CHANGED); + } else { + generateTimeLabel(level, pos, state, pBlockEntity, parent); + } + + if (titleLabel != null) { + titleLabel.tick(); + } + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + if (blockEntity.getTrainData() == null) { + return; + } + + generateTitleBar(level, pos, state, blockEntity, parent); + + if (this.state == State.BEFORE_NEXT_STOP && this.nextConnections != null && !this.nextConnections.isEmpty()) { + return; + } + + parent.labels.clear(); + updateOverview(level, pos, state, blockEntity, parent); + } + + @Override + public void renderAdditional(BlockEntityRendererContext context, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay, Boolean backSide) { + + // render title bar + timeLabel.render(pPoseStack, pBufferSource, pPackedLight); + titleLabel.render(pPoseStack, pBufferSource, pPackedLight); + + context.renderUtils().initRenderEngine(); + context.renderUtils().fillColor(pBufferSource, pBlockEntity, (0xFF << 24) | (pBlockEntity.getColor() & 0x00FFFFFF), pPoseStack, 2.5f, 4.75f, 0.0f, pBlockEntity.getXSizeScaled() * 16 - 5, 0.25f, pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), pPackedLight); + float uv = 1.0f / 256.0f; + float y = 5f; + + if (notInService(pBlockEntity)) { + return; + } + + // Render route path + if (this.state != State.BEFORE_NEXT_STOP || nextConnections == null || nextConnections.isEmpty()) { + float tempH = PANEL_LINE_HEIGHT - 0.2857142f; + context.renderUtils().renderTexture( + TEXTURE, + pBufferSource, + pBlockEntity, + pPoseStack, + 8, + y, + 0.0f, + 1, + tempH, + uv * TEX_ROUTE_PATH_U, + uv * 2, + uv * (TEX_ROUTE_PATH_U + 7), + uv * (TEX_ROUTE_PATH_H), + pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), + 0xFFFFFFFF, + pPackedLight + ); + y += tempH; + for (int i = 0; i < 2 && i < pBlockEntity.getTrainData().stopovers().size(); i++) { + context.renderUtils().renderTexture( + TEXTURE, + pBufferSource, + pBlockEntity, + pPoseStack, + 8, + y, + 0.0f, + 1, + 2, + uv * TEX_ROUTE_PATH_U, + uv * TEX_ROUTE_PATH_H * 1, + uv * (TEX_ROUTE_PATH_U + 7), + uv * (TEX_ROUTE_PATH_H * 2), + pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), + 0xFFFFFFFF, + pPackedLight + ); + y += PANEL_LINE_HEIGHT; + } + + if (pBlockEntity.getTrainData().predictions().size() > 1) { + context.renderUtils().renderTexture( + TEXTURE, + pBufferSource, + pBlockEntity, + pPoseStack, + 8, + y, + 0.0f, + 1, + 2, + uv * TEX_ROUTE_PATH_U, + uv * TEX_ROUTE_PATH_H * 2, + uv * (TEX_ROUTE_PATH_U + 7), + uv * (TEX_ROUTE_PATH_H * 3), + pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), + 0xFFFFFFFF, + pPackedLight + ); + } + + } + + // EXIT ARROW + TrainExitSide side = pBlockEntity.relativeExitDirection.get(); + if (backSide) { + side = side.getOpposite(); + } + if (state != State.WHILE_TRAVELING && side != TrainExitSide.UNKNOWN) { + context.renderUtils().renderTexture( + ModGuiIcons.ICON_LOCATION, + pBufferSource, + pBlockEntity, + pPoseStack, + pBlockEntity.getXSizeScaled() * 16 - 3f - 2, + 2.25f, + 0, + 2.5f, + 2.5f, + uv * (side == TrainExitSide.RIGHT ? ModGuiIcons.ARROW_RIGHT : ModGuiIcons.ARROW_LEFT).getU(), + uv * (side == TrainExitSide.RIGHT ? ModGuiIcons.ARROW_RIGHT : ModGuiIcons.ARROW_LEFT).getV(), + uv * ((side == TrainExitSide.RIGHT ? ModGuiIcons.ARROW_RIGHT : ModGuiIcons.ARROW_LEFT).getU() + ModGuiIcons.ICON_SIZE), + uv * ((side == TrainExitSide.RIGHT ? ModGuiIcons.ARROW_RIGHT : ModGuiIcons.ARROW_LEFT).getV() + ModGuiIcons.ICON_SIZE), + pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), + (0xFF << 24) | (pBlockEntity.getColor()), + pPackedLight + ); + } + } + + private boolean notInService(AdvancedDisplayBlockEntity blockEntity) { + Optional optPred = blockEntity.getTrainData().getNextStop(); + return !optPred.isPresent() || optPred.get().stationTagName() == null || optPred.get().stationTagName().isBlank(); + } + + private float generateTimeLabel(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + float arrowOffset = (this.state != State.WHILE_TRAVELING && blockEntity.relativeExitDirection.get() != TrainExitSide.UNKNOWN ? 4 : 0); + float maxWidth = blockEntity.getXSizeScaled() * 16 - arrowOffset; + MutableComponent line = Utils.text(TimeUtils.parseTime((int)(blockEntity.getLevel().getDayTime() % DragonLibConstants.TICKS_PER_DAY + Constants.TIME_SHIFT), ModClientConfig.TIME_FORMAT.get())).withStyle(ChatFormatting.BOLD); + float rawTextWidth = Math.min(parent.getFontUtils().font.width(line) * 0.5f, maxWidth); + float textWidth = rawTextWidth * 0.5f; + timeLabel = parent.carriageIndexLabel = new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.5f, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor() & 0x00FFFFFF)) + .withPredefinedTextTransformation(new TextTransformation(blockEntity.getXSizeScaled() * 16 - 2.5f - textWidth - (this.state != State.WHILE_TRAVELING && blockEntity.relativeExitDirection.get() != TrainExitSide.UNKNOWN ? 4 : 0), 2.5f, 0.0f, 0.5f, 0.25f)) + .build(); + + return rawTextWidth + arrowOffset; + } + + private void generateTitleBar(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + int displayWidth = blockEntity.getXSizeScaled(); + + float maxWidth = displayWidth * 16 - 6 - (this.state != State.WHILE_TRAVELING && blockEntity.relativeExitDirection.get() != TrainExitSide.UNKNOWN ? 4 : 0); + maxWidth *= 2; + float timeWidth = generateTimeLabel(level, pos, state, blockEntity, parent); + MutableComponent line = Utils.text(blockEntity.getTrainData().trainName()).withStyle(ChatFormatting.BOLD); + if (blockEntity.getTrainData().getNextStop().isPresent()) { + switch (this.state) { + case BEFORE_NEXT_STOP: + line = Utils.translate(keyNextStop, blockEntity.getTrainData().getNextStop().get().stationTagName()); + break; + case WHILE_NEXT_STOP: + line = Utils.translate(blockEntity.getTrainData().trainName() + " " + blockEntity.getTrainData().getNextStop().get().stationTagName()).withStyle(ChatFormatting.BOLD); + break; + default: + break; + } + } + + if (titleLabel != null && line.getString().equals(titleLabel.getCurrentText().getString())) { + return; + } + + titleLabel = new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth - timeWidth, true) + .withStretchScale(0.3f, 0.5f) + .withStencil(0, maxWidth - timeWidth) + .withCanScroll(true, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor() & 0x00FFFFFF)) + .withPredefinedTextTransformation(new TextTransformation(3.0f, 2.5f, 0.0f, 0.5f, 0.25f)) + .build(); + } + + private void updateOverview(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + int displayWidth = blockEntity.getXSizeScaled(); + + // ### CONTENT PANEL + if (notInService(blockEntity)) { + return; + } + + float y = PANEL_Y_START; + // DESTINATION + SimpleDeparturePrediction pred = blockEntity.getTrainData().getNextStop().get(); + float maxWidth = displayWidth * 16 - 12.5f; + int rawTime = (int)(blockEntity.getLastRefreshedTime() % 24000 + pred.departureTicks() + Constants.TIME_SHIFT); + MutableComponent line = Utils.text(TimeUtils.parseTime(rawTime - rawTime % ModClientConfig.REALTIME_PRECISION_THRESHOLD.get(), ModClientConfig.TIME_FORMAT.get())); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(4, true) + .withStretchScale(0.08f, 0.14f) + .withStencil(0, 7) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3.0f, y + 0.3f, 0.0f, 1, 0.14f)) + .build() + ); + + + line = Utils.text(pred.stationTagName()).withStyle(ChatFormatting.BOLD); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.15f, 0.2f) + .withStencil(0, maxWidth) + .withCanScroll(true, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(10.0f, y, 0.0f, 1, 0.2f)) + .build() + ); + y += PANEL_LINE_HEIGHT; + + for (int i = 0; i < 2 && i < blockEntity.getTrainData().stopovers().size(); i++) { + pred = blockEntity.getTrainData().stopovers().get(i); + rawTime = (int)(blockEntity.getLastRefreshedTime() % 24000 + pred.departureTicks() + Constants.TIME_SHIFT); + line = Utils.text(TimeUtils.parseTime(rawTime - rawTime % ModClientConfig.REALTIME_PRECISION_THRESHOLD.get(), ModClientConfig.TIME_FORMAT.get())); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(4, true) + .withStretchScale(0.08f, 0.14f) + .withStencil(0, 7) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3.0f, y + 0.1f, 0.0f, 1, 0.14f)) + .build() + ); + line = Utils.text(pred.stationTagName()); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.15f, 0.16f) + .withStencil(0, maxWidth) + .withCanScroll(true, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(10.0f, y + 0.2f, 0.0f, 1, 0.16f)) + .build() + ); + y += PANEL_LINE_HEIGHT; + } + + if (blockEntity.getTrainData().predictions().size() <= 1) { + return; + } + + // DESTINATION + pred = blockEntity.getTrainData().getLastStop().get(); + rawTime = (int)(blockEntity.getLastRefreshedTime() % 24000 + pred.departureTicks() + Constants.TIME_SHIFT); + line = Utils.text(TimeUtils.parseTime(rawTime - rawTime % ModClientConfig.REALTIME_PRECISION_THRESHOLD.get(), ModClientConfig.TIME_FORMAT.get())); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(4, true) + .withStretchScale(0.08f, 0.14f) + .withStencil(0, 7) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3.0f, y + 0.3f, 0.0f, 1, 0.14f)) + .build() + ); + line = Utils.text(pred.stationTagName()).withStyle(ChatFormatting.BOLD); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.2f, 0.2f) + .withStencil(0, maxWidth) + .withCanScroll(true, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(10.0f, y, 0.0f, 1, 0.2f)) + .build() + ); + } + + private void updateNextConnections(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + int displayWidth = blockEntity.getXSizeScaled(); + + // ### CONTENT PANEL + if (notInService(blockEntity)) { + return; + } + + float y = PANEL_Y_START; + float maxWidth = displayWidth * 16 - 3; + + MutableComponent ln = Utils.text(generatePageIndexString()); + float rawTextWidth = Math.min(parent.getFontUtils().font.width(ln) * 0.2f, maxWidth - 16.0f); + parent.labels.add(new BERText(parent.getFontUtils(), ln, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth - 16.0f, true) + .withStretchScale(0.2f, 0.2f) + .withStencil(0, maxWidth - 16.0f) + .withCanScroll(false, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(maxWidth - rawTextWidth - 0.25f, y - 0.2f, 0.0f, 1, 0.2f)) + .build() + ); + + parent.labels.add(new BERText(parent.getFontUtils(), textNextConnections, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth - 6.0f - rawTextWidth, true) + .withStretchScale(0.1f, 0.15f) + .withStencil(0, maxWidth - 6.0f - rawTextWidth) + .withCanScroll(true, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3.0f, y, 0.0f, 1, 0.15f)) + .build() + ); + y += PANEL_LINE_HEIGHT; + + if (this.nextConnections == null) { + return; + } + + for (int i = nextConnectionsPage * NEXT_CONNECTIONS_MAX_ENTRIES_PER_PAGE; i < (nextConnectionsPage + 1) * NEXT_CONNECTIONS_MAX_ENTRIES_PER_PAGE && i < nextConnections.size(); i++) { + + SimpleTrainConnection connection = nextConnections.get(i); + int rawTime = (int)(nextConnectionsRefreshTime % 24000 + connection.ticks() + Constants.TIME_SHIFT); + MutableComponent line = Utils.text(TimeUtils.parseTime(rawTime - rawTime % ModClientConfig.REALTIME_PRECISION_THRESHOLD.get(), ModClientConfig.TIME_FORMAT.get())); + + // Time + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(4, true) + .withStretchScale(0.08f, 0.14f) + .withStencil(0, 4) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(4.0f, y + 0.1f, 0.0f, 1, 0.14f)) + .build() + ); + + // Train Name + line = Utils.text(connection.trainName()); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(5, true) + .withStretchScale(0.1f, 0.16f) + .withStencil(0, 5) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(8.5f, y, 0.0f, 1, 0.16f)) + .build() + ); + + // Platform + line = Utils.text(connection.stationDetails().platform()); + rawTextWidth = Math.min(parent.getFontUtils().font.width(line) * 0.14f, maxWidth - 16.0f); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth - 16.0f, true) + .withStretchScale(0.14f, 0.16f) + .withStencil(0, maxWidth - 16.0f) + .withCanScroll(false, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(maxWidth - rawTextWidth, y, 0.0f, 1, 0.16f)) + .build() + ); + + // Destination + line = Utils.text(connection.scheduleTitle()); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth - 17.0f - rawTextWidth, true) + .withStretchScale(0.1f, 0.16f) + .withStencil(0, maxWidth - 17.0f - rawTextWidth) + .withCanScroll(true, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(14.0f, y, 0.0f, 1, 0.16f)) + .build() + ); + y += PANEL_LINE_HEIGHT; + } + } + + private String generatePageIndexString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < nextConnectionsPage; i++) { + sb.append(" □"); + } + sb.append(" ■"); + + for (int i = nextConnectionsPage + 1; i < nextConnectionsMaxPage; i++) { + sb.append(" □"); + } + + return sb.toString(); + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPassengerInfoSimple.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPassengerInfoSimple.java new file mode 100644 index 00000000..a666678d --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPassengerInfoSimple.java @@ -0,0 +1,191 @@ +package de.mrjulsen.crn.client.ber.variants; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.base.BERText.TextTransformation; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.BlockEntityRendererContext; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.crn.client.gui.ModGuiIcons; +import de.mrjulsen.crn.config.ModClientConfig; +import de.mrjulsen.crn.data.GlobalSettingsManager; +import de.mrjulsen.crn.data.DeparturePrediction.TrainExitSide; +import de.mrjulsen.crn.event.listeners.JourneyListener.State; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; + +public class BERPassengerInfoSimple implements IBERRenderSubtype { + + private State state = State.WHILE_TRAVELING; + + private static final String keyNextStop = "gui.createrailwaysnavigator.route_overview.next_stop"; + + @Override + public boolean isSingleLined() { + return true; + } + + @Override + public void tick(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent) { + if (pBlockEntity.getTrainData() == null) { + return; + } + + boolean dirty = false; + if (pBlockEntity.getTrainData().getNextStop().isPresent()) { + if (this.state != State.WHILE_NEXT_STOP && pBlockEntity.getTrainData().getNextStop().get().departureTicks() <= 0) { + this.state = State.WHILE_NEXT_STOP; + dirty = true; + } else if (this.state != State.BEFORE_NEXT_STOP && pBlockEntity.getTrainData().getNextStop().get().departureTicks() <= ModClientConfig.NEXT_STOP_ANNOUNCEMENT.get() && pBlockEntity.getTrainData().getNextStop().get().departureTicks() > 0) { + this.state = State.BEFORE_NEXT_STOP; + dirty = true; + } else if (this.state != State.WHILE_TRAVELING && pBlockEntity.getTrainData().getNextStop().get().departureTicks() > ModClientConfig.NEXT_STOP_ANNOUNCEMENT.get()) { + this.state = State.WHILE_TRAVELING; + dirty = true; + } + } + + if (dirty) { + update(level, pos, state, pBlockEntity, parent, EUpdateReason.DATA_CHANGED); + } + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + if (blockEntity.getTrainData() == null) { + return; + } + + parent.labels.clear(); + switch (this.state) { + case BEFORE_NEXT_STOP: + updateAnnounceNextStop(level, pos, state, blockEntity, parent); + break; + case WHILE_NEXT_STOP: + updateWhileNextStop(level, pos, state, blockEntity, parent); + break; + default: + updateDefault(level, pos, state, blockEntity, parent); + break; + } + } + + @Override + public void renderAdditional(BlockEntityRendererContext context, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay, Boolean backSide) { + if (state == State.WHILE_NEXT_STOP || state == State.BEFORE_NEXT_STOP) { + context.renderUtils().initRenderEngine(); + TrainExitSide side = pBlockEntity.relativeExitDirection.get(); + float uv = 1.0f / 256.0f; + + if (backSide) { + side = side.getOpposite(); + } + + switch (side) { + case RIGHT: + context.renderUtils().renderTexture( + ModGuiIcons.ICON_LOCATION, + pBufferSource, + pBlockEntity, + pPoseStack, + pBlockEntity.getXSizeScaled() * 16 - 3 - 8, + 4, + 0, + 8, + 8, + uv * ModGuiIcons.ARROW_RIGHT.getU(), + uv * ModGuiIcons.ARROW_RIGHT.getV(), + uv * (ModGuiIcons.ARROW_RIGHT.getU() + ModGuiIcons.ICON_SIZE), + uv * (ModGuiIcons.ARROW_RIGHT.getV() + ModGuiIcons.ICON_SIZE), + pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), + (0xFF << 24) | (pBlockEntity.getColor()), + pPackedLight + ); + break; + case LEFT: + context.renderUtils().renderTexture( + ModGuiIcons.ICON_LOCATION, + pBufferSource, + pBlockEntity, + pPoseStack, + 3f, + 4, + 0, + 8, + 8, + uv * ModGuiIcons.ARROW_LEFT.getU(), + uv * ModGuiIcons.ARROW_LEFT.getV(), + uv * (ModGuiIcons.ARROW_LEFT.getU() + ModGuiIcons.ICON_SIZE), + uv * (ModGuiIcons.ARROW_LEFT.getV() + ModGuiIcons.ICON_SIZE), + pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), + (0xFF << 24) | (pBlockEntity.getColor()), + pPackedLight + ); + break; + default: + break; + } + } + } + + private void updateDefault(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + int displayWidth = blockEntity.getXSizeScaled(); + + MutableComponent line = Utils.text(blockEntity.getTrainData().trainName()).append(" ").append(Utils.text(blockEntity.getTrainData().getNextStop().get().scheduleTitle())); + float maxWidth = displayWidth * 16 - 6; + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(true) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.75f, 0.75f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3, 5.5f, 0.0f, 1, 0.75f)) + .build() + ); + } + + private void updateAnnounceNextStop(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + int displayWidth = blockEntity.getXSizeScaled(); + TrainExitSide side = blockEntity.relativeExitDirection.get(); + + MutableComponent line = Utils.translate(keyNextStop, GlobalSettingsManager.getInstance().getSettingsData().getAliasFor(blockEntity.getTrainData().getNextStop().get().stationTagName()).getAliasName().get()); + float maxWidth = displayWidth * 16 - 6 - (side != TrainExitSide.UNKNOWN ? 10 : 0); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(true) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.75f, 0.75f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3 + (side == TrainExitSide.LEFT ? 10 : 0), 5.5f, 0.0f, 1, 0.75f)) + .build() + ); + } + + private void updateWhileNextStop(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent) { + int displayWidth = blockEntity.getXSizeScaled(); + + TrainExitSide side = blockEntity.relativeExitDirection.get(); + MutableComponent line = Utils.text(GlobalSettingsManager.getInstance().getSettingsData().getAliasFor(blockEntity.getTrainData().getNextStop().get().stationTagName()).getAliasName().get()); + + float maxWidth = displayWidth * 16 - 6 - (side != TrainExitSide.UNKNOWN ? 10 : 0); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(true) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.75f, 0.75f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3 + (side == TrainExitSide.LEFT ? 10 : 0), 5.5f, 0.0f, 1, 0.75f)) + .build() + ); + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPlatformDetailed.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPlatformDetailed.java new file mode 100644 index 00000000..b309ac07 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPlatformDetailed.java @@ -0,0 +1,222 @@ +package de.mrjulsen.crn.client.ber.variants; + +import java.util.ArrayList; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.Constants; +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.base.BERText.TextTransformation; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.BlockEntityRendererContext; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.crn.config.ModClientConfig; +import de.mrjulsen.crn.data.DeparturePrediction.SimpleDeparturePrediction; +import de.mrjulsen.crn.util.ModUtils; +import de.mrjulsen.mcdragonlib.DragonLibConstants; +import de.mrjulsen.mcdragonlib.utils.TimeUtils; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public class BERPlatformDetailed implements IBERRenderSubtype { + + private static final String keyTime = "gui.createrailwaysnavigator.time"; + + private static final int TIME_LABEL_WIDTH = 16; + + private List lastPredictions = new ArrayList<>(); + + private BERText timeLabel; + private BERText[][] additionalLabels; + + private int timer; + private static final int MAX_TIMER = 100; + private boolean showTime = false; + + @Override + public boolean isSingleLined() { + return false; + } + + @Override + public void tick(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent) { + if (timeLabel != null) timeLabel.tick(); + + if (additionalLabels != null) { + for (int i = 0; i < additionalLabels.length; i++) { + if (additionalLabels[i] == null) { + continue; + } + + for (int k = 0; k < additionalLabels[i].length; k++) { + if (additionalLabels[i][k] == null) { + continue; + } + + additionalLabels[i][k].tick(); + } + } + } + + timer++; + if ((timer %= MAX_TIMER) == 0) { + showTime = !showTime; + } + } + + @Override + public void renderAdditional(BlockEntityRendererContext context, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay, Boolean backSide) { + if (additionalLabels != null) { + for (int i = 0; i < additionalLabels.length; i++) { + if (additionalLabels[i] == null) { + continue; + } + + if (i >= pBlockEntity.getPlatformInfoLinesCount() - 1 && showTime) { + break; + } else { + for (int k = 0; k < additionalLabels[i].length; k++) { + if (additionalLabels[i][k] == null) { + continue; + } + + additionalLabels[i][k].render(pPoseStack, pBufferSource, pPackedLight); + } + + if (i >= pBlockEntity.getPlatformInfoLinesCount() - 1) { + return; + } + } + } + } + timeLabel.render(pPoseStack, pBufferSource, pPackedLight); + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + + parent.labels.clear(); + + List preds = blockEntity.getPredictions().stream().filter(x -> x.departureTicks() < ModClientConfig.DISPLAY_LEAD_TIME.get()).toList(); + + if (preds.size() <= 0) { + additionalLabels = null; + setTimer(level, pos, state, blockEntity, parent, reason, 4f); + return; + } + + int maxLines = blockEntity.getPlatformInfoLinesCount(); + boolean refreshAll = reason != EUpdateReason.DATA_CHANGED || !ModUtils.compareCollections(lastPredictions, preds, (a, b) -> a.stationInfo().platform().equals(b.stationInfo().platform()) && a.trainId().equals(b.trainId())); + + lastPredictions = preds; + + if (refreshAll) { + additionalLabels = null; + timeLabel = null; + additionalLabels = new BERText[Math.min(preds.size(), maxLines)][]; + + for (int i = 0; i < additionalLabels.length; i++) { + additionalLabels[i] = addLine(level, pos, state, blockEntity, parent, reason, i, 4 + (i * 5.4f)); + } + setTimer(level, pos, state, blockEntity, parent, reason, 4 + ((additionalLabels.length < maxLines ? additionalLabels.length : maxLines - 1) * 5.34f)); + } + + } + + + private BERText[] addLine(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason, int predictionIdx, float y) { + float displayWidth = blockEntity.getXSizeScaled() * 16 - 4; + + BERText[] labels = new BERText[4]; + + // PLATFORM + Component label = Utils.text(lastPredictions.get(predictionIdx).stationInfo().platform()); + float labelWidth = blockEntity.getPlatformWidth() < 0 ? parent.getFontUtils().font.width(label) * 0.4f : Math.min(parent.getFontUtils().font.width(label) * 0.4f, blockEntity.getPlatformWidth() - 2); + int platformMaxWidth = blockEntity.getPlatformWidth() < 0 ? (int)(displayWidth - 6) : blockEntity.getPlatformWidth() - 2; + + BERText lastLabel = new BERText(parent.getFontUtils(), label, 0) + .withIsCentered(false) + .withMaxWidth(platformMaxWidth, true) + .withStretchScale(0.2f, 0.4f) + .withStencil(0, platformMaxWidth) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(blockEntity.getXSizeScaled() * 16 - 3 - labelWidth, y, 0.01f, 1, 0.4f)) + .build(); + labels[0] = lastLabel; + + // TIME + labels[1] = new BERText(parent.getFontUtils(), () -> { + List texts = new ArrayList<>(); + int rawTime = (int)(blockEntity.getLastRefreshedTime() % DragonLibConstants.TICKS_PER_DAY + Constants.TIME_SHIFT + lastPredictions.get(predictionIdx).departureTicks()); + texts.add(Utils.text(TimeUtils.parseTime(rawTime - rawTime % ModClientConfig.REALTIME_PRECISION_THRESHOLD.get(), ModClientConfig.TIME_FORMAT.get()))); + return texts; + }, 0) + .withIsCentered(false) + .withMaxWidth(TIME_LABEL_WIDTH - 4, true) + .withStretchScale(0.2f, 0.4f) + .withStencil(0, TIME_LABEL_WIDTH - 4) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withRefreshRate(100) + .withPredefinedTextTransformation(new TextTransformation(3, y, 0.01f, 1, 0.4f)) + .build() + ; + + float platformWidth = blockEntity.getPlatformWidth() < 0 ? lastLabel.getScaledTextWidth() + 2 : blockEntity.getPlatformWidth(); + int trainNameWidth = blockEntity.getTrainNameWidth(); + + lastLabel = new BERText(parent.getFontUtils(), () -> { + List texts = new ArrayList<>(); + texts.add(Utils.text(lastPredictions.get(predictionIdx).trainName())); + return texts; + }, 0) + .withIsCentered(false) + .withMaxWidth(Math.min(trainNameWidth - 1, displayWidth - TIME_LABEL_WIDTH - platformWidth - 1), false) + .withStretchScale(0.2f, 0.4f) + .withStencil(0, Math.min(trainNameWidth - 1, displayWidth - TIME_LABEL_WIDTH - platformWidth - 1)) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(TIME_LABEL_WIDTH, y, 0.01f, 1, 0.4f)) + .build() + ; + labels[2] = lastLabel; + + lastLabel = new BERText(parent.getFontUtils(), () -> { + List texts = new ArrayList<>(); + texts.add(Utils.text(lastPredictions.get(predictionIdx).scheduleTitle())); + return texts; + }, 0) + .withIsCentered(false) + .withMaxWidth(displayWidth - TIME_LABEL_WIDTH - trainNameWidth - platformWidth + 1, true) + .withStretchScale(0.25f, 0.4f) + .withStencil(0, displayWidth - TIME_LABEL_WIDTH - trainNameWidth - platformWidth + 1) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(TIME_LABEL_WIDTH + trainNameWidth, y, 0.01f, 1, 0.4f)) + .build() + ; + + labels[3] = lastLabel; + return labels; + } + + public void setTimer(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason, float y) { + float displayWidth = blockEntity.getXSizeScaled() * 16 - 6; + timeLabel = new BERText(parent.getFontUtils(), () -> List.of(Utils.translate(keyTime, TimeUtils.parseTime((int)(blockEntity.getLevel().getDayTime() % 24000 + 6000), ModClientConfig.TIME_FORMAT.get()))), 0) + .withIsCentered(true) + .withMaxWidth(displayWidth, true) + .withStretchScale(0.4f, 0.4f) + .withStencil(0, displayWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withTicksPerPage(100) + .withRefreshRate(16) + .withPredefinedTextTransformation(new TextTransformation(3, y, 0.0f, 1, 0.4f)) + .build() + ; + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPlatformInformative.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPlatformInformative.java new file mode 100644 index 00000000..e68f40f9 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPlatformInformative.java @@ -0,0 +1,329 @@ +package de.mrjulsen.crn.client.ber.variants; + +import java.util.ArrayList; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.Constants; +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.base.BERText.TextTransformation; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.BlockEntityRendererContext; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.crn.config.ModClientConfig; +import de.mrjulsen.crn.data.DeparturePrediction.SimpleDeparturePrediction; +import de.mrjulsen.crn.util.ModUtils; +import de.mrjulsen.mcdragonlib.DragonLibConstants; +import de.mrjulsen.mcdragonlib.utils.TimeUtils; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.ChatFormatting; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; + +public class BERPlatformInformative implements IBERRenderSubtype { + + private List lastPredictions = new ArrayList<>(); + + private static final int TIME_LABEL_WIDTH = 16; + + private static final String keyPlatform = "gui.createrailwaysnavigator.platform"; + private static final String keyLine = "gui.createrailwaysnavigator.line"; + private static final String keyDestination = "gui.createrailwaysnavigator.destination"; + private static final String keyDeparture = "gui.createrailwaysnavigator.departure"; + private static final String keyFollowingTrains = "gui.createrailwaysnavigator.following_trains"; + + + // cache + private boolean wasPlatformFixed; + + @Override + public boolean isSingleLined() { + return false; + } + + @Override + public void tick(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent) { + + } + + private boolean extendedDisplay(AdvancedDisplayBlockEntity blockEntity) { + return blockEntity.getYSize() > 1; + } + + @Override + public void renderAdditional(BlockEntityRendererContext context, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay, Boolean backSide) { + boolean isPlatformFixed = pBlockEntity.isPlatformFixed(); + context.renderUtils().initRenderEngine(); + if (!isPlatformFixed) { + context.renderUtils().fillColor(pBufferSource, pBlockEntity, (0xFF << 24) | (pBlockEntity.getColor() & 0x00FFFFFF), pPoseStack, 2.5f, 6.0f, 0.0f, pBlockEntity.getXSizeScaled() * 16 - 5, 0.25f, pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), pPackedLight); + + int count = pBlockEntity.getPlatformInfoLinesCount(); + for (int i = 0; i < count; i += 2) { + context.renderUtils().fillColor(pBufferSource, pBlockEntity, 0x22FFFFFF, pPoseStack, 2, 4 + ((i + 1) * 5.34f) - 1f, 0.0f, pBlockEntity.getXSizeScaled() * 16 - 4, 5.34f, pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), pPackedLight); + } + } else { + if (extendedDisplay(pBlockEntity)) { + context.renderUtils().fillColor(pBufferSource, pBlockEntity, (0xFF << 24) | (pBlockEntity.getColor() & 0x00FFFFFF), pPoseStack, 2.5f, 15.5f, 0.0f, pBlockEntity.getXSizeScaled() * 16 - 5, 0.25f, pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), pPackedLight); + } + } + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + List preds = blockEntity.getPredictions(); + boolean isPlatformFixed = blockEntity.isPlatformFixed(); + /* + if (preds.size() <= 0) { + parent.labels.clear(); + return; + } + */ + + int maxLines = blockEntity.getPlatformInfoLinesCount() - (isPlatformFixed ? 1 : 0) ; + boolean refreshAll = reason != EUpdateReason.DATA_CHANGED || + !ModUtils.compareCollections(lastPredictions, preds, (a, b) -> a.stationInfo().platform().equals(b.stationInfo().platform()) && a.trainId().equals(b.trainId())) || + wasPlatformFixed != isPlatformFixed + ; + + lastPredictions = preds; + wasPlatformFixed = blockEntity.isPlatformFixed(); + + if (refreshAll) { + parent.labels.clear(); + if (isPlatformFixed) { + addNextDeparture(level, pos, state, blockEntity, parent, reason, 0); + } else { + addHeader(level, pos, state, blockEntity, parent, reason); + } + + if (isPlatformFixed && preds.size() > 0) { + for (int i = 1; i < maxLines && i < preds.size(); i++) { + addLine(level, pos, state, blockEntity, parent, reason, i, 4 + ((i + 2) * 5.4f)); + } + } else { + for (int i = 0; i < maxLines && i < preds.size(); i++) { + addLine(level, pos, state, blockEntity, parent, reason, i, 4 + ((i + 1) * 5.34f)); + } + } + } + } + + private void addLine(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason, int predictionIdx, float y) { + float displayWidth = blockEntity.getXSizeScaled() * 16 - 4; + + // PLATFORM + Component label = blockEntity.isPlatformFixed() ? Utils.emptyText() : Utils.text(lastPredictions.get(predictionIdx).stationInfo().platform()); + float labelWidth = blockEntity.getPlatformWidth() < 0 ? parent.getFontUtils().font.width(label) * 0.4f : Math.min(parent.getFontUtils().font.width(label) * 0.4f, blockEntity.getPlatformWidth() - 2); + int platformMaxWidth = blockEntity.getPlatformWidth() < 0 ? (int)(displayWidth - 6) : blockEntity.getPlatformWidth() - 2; + + BERText lastLabel = new BERText(parent.getFontUtils(), label, 0) + .withIsCentered(false) + .withMaxWidth(platformMaxWidth, true) + .withStretchScale(0.2f, 0.4f) + .withStencil(0, platformMaxWidth) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(blockEntity.getXSizeScaled() * 16 - 3 - labelWidth, y, 0.01f, 1, 0.4f)) + .build(); + parent.labels.add(lastLabel); + + // TIME + parent.labels.add(new BERText(parent.getFontUtils(), () -> { + List texts = new ArrayList<>(); + int rawTime = (int)(blockEntity.getLastRefreshedTime() % DragonLibConstants.TICKS_PER_DAY + Constants.TIME_SHIFT + lastPredictions.get(predictionIdx).departureTicks()); + texts.add(Utils.text(TimeUtils.parseTime(rawTime - rawTime % ModClientConfig.REALTIME_PRECISION_THRESHOLD.get(), ModClientConfig.TIME_FORMAT.get()))); + return texts; + }, 0) + .withIsCentered(false) + .withMaxWidth(TIME_LABEL_WIDTH - 4, true) + .withStretchScale(0.2f, 0.4f) + .withStencil(0, TIME_LABEL_WIDTH - 4) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withRefreshRate(100) + .withPredefinedTextTransformation(new TextTransformation(3, y, 0.01f, 1, 0.4f)) + .build() + ); + + float platformWidth = blockEntity.getPlatformWidth() < 0 ? lastLabel.getScaledTextWidth() + 2 : blockEntity.getPlatformWidth(); + int trainNameWidth = blockEntity.getTrainNameWidth(); + + lastLabel = new BERText(parent.getFontUtils(), () -> { + List texts = new ArrayList<>(); + texts.add(Utils.text(lastPredictions.get(predictionIdx).trainName())); + return texts; + }, 0) + .withIsCentered(false) + .withMaxWidth(Math.min(trainNameWidth - 1, displayWidth - TIME_LABEL_WIDTH - platformWidth - 1), false) + .withStretchScale(0.2f, 0.4f) + .withStencil(0, Math.min(trainNameWidth - 1, displayWidth - TIME_LABEL_WIDTH - platformWidth - 1)) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(TIME_LABEL_WIDTH, y, 0.01f, 1, 0.4f)) + .build() + ; + parent.labels.add(lastLabel); + + lastLabel = new BERText(parent.getFontUtils(), () -> { + List texts = new ArrayList<>(); + texts.add(Utils.text(lastPredictions.get(predictionIdx).scheduleTitle())); + return texts; + }, 0) + .withIsCentered(false) + .withMaxWidth(displayWidth - TIME_LABEL_WIDTH - trainNameWidth - platformWidth + 1, true) + .withStretchScale(0.25f, 0.4f) + .withStencil(0, displayWidth - TIME_LABEL_WIDTH - trainNameWidth - platformWidth + 1) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(TIME_LABEL_WIDTH + trainNameWidth, y, 0.01f, 1, 0.4f)) + .build() + ; + + parent.labels.add(lastLabel); + } + + private void addNextDeparture(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason, int predictionIdx) { + float displayWidth = blockEntity.getXSizeScaled() * 16 - 6; + int timeLabelWidth = TIME_LABEL_WIDTH - 3; + + // PLATFORM + Component label = Utils.text(blockEntity.getStationInfo().platform()).withStyle(ChatFormatting.BOLD); + float labelWidth = parent.getFontUtils().font.width(label) * 0.8f; + BERText lastLabel = new BERText(parent.getFontUtils(), label, 0) + .withIsCentered(false) + .withMaxWidth(displayWidth, true) + .withStretchScale(0.8f, 0.8f) + .withStencil(0, displayWidth) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(displayWidth - labelWidth + 3, 3, 0.0f, 1, 1f)) + .build(); + parent.labels.add(lastLabel); + + if (lastPredictions.size() <= 0) { + return; + } + + float platformWidth = lastLabel.getScaledTextWidth(); + + // TIME + parent.labels.add(new BERText(parent.getFontUtils(), () -> { + List texts = new ArrayList<>(); + int rawTime = (int)(blockEntity.getLevel().getDayTime() % DragonLibConstants.TICKS_PER_DAY + Constants.TIME_SHIFT + lastPredictions.get(predictionIdx).departureTicks()); + texts.add(Utils.text(TimeUtils.parseTime(rawTime - rawTime % ModClientConfig.REALTIME_PRECISION_THRESHOLD.get(), ModClientConfig.TIME_FORMAT.get()))); + return texts; + }, 0) + .withIsCentered(false) + .withMaxWidth(timeLabelWidth, true) + .withStretchScale(0.2f, 0.4f) + .withStencil(0, timeLabelWidth) + .withRefreshRate(100) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3, 3, 0.0f, 1, 0.4f)) + .build() + ); + + parent.labels.add(new BERText(parent.getFontUtils(), Utils.text(lastPredictions.get(predictionIdx).trainName()), 0) + .withIsCentered(false) + .withMaxWidth(timeLabelWidth, true) + .withStretchScale(0.15f, 0.3f) + .withStencil(0, timeLabelWidth) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3, 7, 0.0f, 1, 0.3f)) + .build() + ); + + parent.labels.add(new BERText(parent.getFontUtils(), Utils.text(lastPredictions.get(predictionIdx).scheduleTitle()).withStyle(ChatFormatting.BOLD), 0) + .withIsCentered(false) + .withMaxWidth(displayWidth - timeLabelWidth - platformWidth - 5, true) + .withStretchScale(0.3f, 0.6f) + .withStencil(0, displayWidth - timeLabelWidth - platformWidth - 5) + .withCanScroll(true, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3 + timeLabelWidth + 1, 8, 0.0f, 1, 0.6f)) + .build() + ); + + parent.labels.add(new BERText(parent.getFontUtils(), parent.getStopoversString(blockEntity), 0) + .withIsCentered(false) + .withMaxWidth(displayWidth - TIME_LABEL_WIDTH - platformWidth - 2, true) + .withStretchScale(0.2f, 0.25f) + .withStencil(0, displayWidth - TIME_LABEL_WIDTH - platformWidth - 2) + .withCanScroll(true, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(TIME_LABEL_WIDTH + 1, 5, 0.0f, 1, 0.25f)) + .build() + ); + + if (extendedDisplay(blockEntity)) { + parent.labels.add(new BERText(parent.getFontUtils(), Utils.translate(keyFollowingTrains), 0) + .withIsCentered(false) + .withMaxWidth(displayWidth, true) + .withStretchScale(0.15f, 0.2f) + .withStencil(0, displayWidth) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3, 17, 0.0f, 1, 0.2f)) + .build() + ); + } + } + + private void addHeader(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + float displayWidth = blockEntity.getXSizeScaled() * 16 - 4; + float TIME_LABEL_WIDTH = 16; + + // TIME + parent.labels.add(new BERText(parent.getFontUtils(), Utils.translate(keyDeparture).withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.ITALIC), 0) + .withIsCentered(false) + .withMaxWidth(TIME_LABEL_WIDTH - 4, true) + .withStretchScale(0.15f, 0.3f) + .withStencil(0, Math.min(TIME_LABEL_WIDTH - 4, displayWidth - 2)) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3, 3, 0.0f, 1, 0.3f)) + .build() + ); + + // PLATFORM + Component label = Utils.translate(keyPlatform).withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.ITALIC); + float labelWidth = blockEntity.getPlatformWidth() < 0 ? parent.getFontUtils().font.width(label) * 0.3f : Math.min(parent.getFontUtils().font.width(label) * 0.4f, blockEntity.getPlatformWidth() - 2); + int platformMaxWidth = blockEntity.getPlatformWidth() < 0 ? (int)(displayWidth - 6) : blockEntity.getPlatformWidth() - 2; + + BERText lastLabel = new BERText(parent.getFontUtils(), label, 0) + .withIsCentered(false) + .withMaxWidth(platformMaxWidth, true) + .withStretchScale(0.15f, 0.3f) + .withStencil(0, labelWidth) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(blockEntity.getXSizeScaled() * 16 - 3 - labelWidth, 3, 0.0f, 1, 0.3f)) + .build(); + parent.labels.add(lastLabel); + + float platformWidth = blockEntity.getPlatformWidth() < 0 ? lastLabel.getScaledTextWidth() + 2 : blockEntity.getPlatformWidth(); + int trainNameWidth = blockEntity.getTrainNameWidth(); + + lastLabel = new BERText(parent.getFontUtils(), Utils.translate(keyLine).withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.ITALIC), 0) + .withIsCentered(false) + .withMaxWidth(Math.min(trainNameWidth - 1, displayWidth - TIME_LABEL_WIDTH - platformWidth - 1), true) + .withStretchScale(0.15f, 0.3f) + .withStencil(0, Math.min(trainNameWidth - 1, displayWidth - TIME_LABEL_WIDTH - platformWidth - 1)) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(TIME_LABEL_WIDTH, 3, 0.0f, 1, 0.3f)) + .build() + ; + parent.labels.add(lastLabel); + + lastLabel = new BERText(parent.getFontUtils(), Utils.translate(keyDestination).withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.ITALIC), 0) + .withIsCentered(false) + .withMaxWidth(displayWidth - TIME_LABEL_WIDTH - trainNameWidth - platformWidth + 1, true) + .withStretchScale(0.15f, 0.3f) + .withStencil(0, displayWidth - TIME_LABEL_WIDTH - trainNameWidth - platformWidth + 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(TIME_LABEL_WIDTH + trainNameWidth, 3, 0.0f, 1, 0.3f)) + .build() + ; + + parent.labels.add(lastLabel); + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPlatformSimple.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPlatformSimple.java new file mode 100644 index 00000000..0ab17ff9 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERPlatformSimple.java @@ -0,0 +1,82 @@ +package de.mrjulsen.crn.client.ber.variants; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.base.BERText.TextTransformation; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.BlockEntityRendererContext; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.crn.config.ModClientConfig; +import de.mrjulsen.crn.data.DeparturePrediction.SimpleDeparturePrediction; +import de.mrjulsen.crn.util.ModUtils; +import de.mrjulsen.mcdragonlib.utils.TimeUtils; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public class BERPlatformSimple implements IBERRenderSubtype { + + private static final String keyTrainDeparture = "gui.createrailwaysnavigator.route_overview.notification.journey_begins"; + private static final String keyTime = "gui.createrailwaysnavigator.time"; + + private Collection lastTrainOrder = new ArrayList<>(); + + @Override + public boolean isSingleLined() { + return true; + } + + @Override + public void tick(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent) { + + } + + @Override + public void renderAdditional(BlockEntityRendererContext context, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay, Boolean backSide) { + + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + Collection preds = blockEntity.getPredictions().stream().filter(x -> x.departureTicks() < ModClientConfig.DISPLAY_LEAD_TIME.get()).toList(); + Collection uuidOrder = preds.stream().map(x -> x.trainId()).toList(); + + if (reason == EUpdateReason.DATA_CHANGED && lastTrainOrder.equals(uuidOrder)) { + return; + } + + lastTrainOrder = uuidOrder; + parent.labels.clear(); + + int displayWidth = blockEntity.getXSizeScaled(); + float maxWidth = displayWidth * 16 - 6; + parent.labels.add(new BERText(parent.getFontUtils(), () -> { + List texts = new ArrayList<>(); + texts.add(Utils.translate(keyTime, TimeUtils.parseTime((int)(blockEntity.getLevel().getDayTime() % 24000 + 6000), ModClientConfig.TIME_FORMAT.get()))); + texts.addAll(preds.stream().map(x -> Utils.translate(keyTrainDeparture, x.trainName(), x.scheduleTitle(), TimeUtils.parseTime((int)(blockEntity.getLastRefreshedTime() % 24000 + 6000 + x.departureTicks()), ModClientConfig.TIME_FORMAT.get()), x.stationInfo().platform())).toList()); + + return List.of(ModUtils.concat(texts.toArray(Component[]::new))); + }, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.75f, 0.75f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withTicksPerPage(100) + .withRefreshRate(16) + .withPredefinedTextTransformation(new TextTransformation(3, 5.5f, 0.0f, 1, 0.75f)) + .build() + ); + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERRenderSubtypeBase.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERRenderSubtypeBase.java new file mode 100644 index 00000000..e1fe62d7 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERRenderSubtypeBase.java @@ -0,0 +1,19 @@ +package de.mrjulsen.crn.client.ber.variants; + +import de.mrjulsen.crn.client.ber.base.AbstractBlockEntityRenderInstance; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public final class BERRenderSubtypeBase, U> implements IBERRenderSubtype{ + + @Override + public boolean isSingleLined() { + return false; + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, T blockEntity, S parent, EUpdateReason reason) {} +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERTrainDestinationDetailed.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERTrainDestinationDetailed.java new file mode 100644 index 00000000..48dc5be3 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERTrainDestinationDetailed.java @@ -0,0 +1,94 @@ +package de.mrjulsen.crn.client.ber.variants; + +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.base.BERText.TextTransformation; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.crn.util.ModGuiUtils; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public class BERTrainDestinationDetailed implements IBERRenderSubtype { + + @Override + public boolean isSingleLined() { + return true; + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + if (blockEntity.getTrainData() == null) { + return; + } + parent.labels.clear(); + + int displayWidth = blockEntity.getXSizeScaled(); + boolean isSingleBlock = blockEntity.getXSizeScaled() <= 1; + + // TRAIN NAME + float maxWidth = isSingleBlock ? 11.0f : 12.0f; + MutableComponent line = Utils.text(blockEntity.getTrainData().trainName()).withStyle(ChatFormatting.BOLD); + BERText lastLabel = new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(isSingleBlock) + .withMaxWidth(maxWidth, isSingleBlock) + .withStretchScale(0.3f, 0.5f) + .withStencil(0, displayWidth * 16 - 5) + .withCanScroll(isSingleBlock, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor() & 0x00FFFFFF)) + .withPredefinedTextTransformation(new TextTransformation(isSingleBlock ? 2.5f : 3.0f, 4, 0.0f, 1, 0.5f)) + .build(); + parent.labels.add(lastLabel); + + // DESTINATION + float startX = lastLabel.getScaledTextWidth(); + line = Utils.text(blockEntity.getTrainData().getNextStop().get().scheduleTitle()); + maxWidth = displayWidth * 16 - 7 - startX; + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(true) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.25f, 0.5f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(2 + startX + 2, 4, 0.0f, 1, 0.5f)) + .build() + ); + + + maxWidth = isSingleBlock ? 11.0f : 12.0f; + line = Utils.text("via").withStyle(ChatFormatting.ITALIC); + maxWidth = displayWidth * 16 - 8; + maxWidth /= 0.75f; + lastLabel = new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.35f, 0.35f) + .withColor(ModGuiUtils.darkenColor(blockEntity.getColor(), -0.75f)) + .withPredefinedTextTransformation(new TextTransformation(isSingleBlock ? 2.5f : 3.0f, 10, 0.0f, 0.75f, 0.3f)) + .build(); + + parent.labels.add(lastLabel); + + startX = lastLabel.getScaledTextWidth(); + startX *= 0.75f; + line = parent.getStopoversString(blockEntity); + maxWidth = displayWidth * 16 - 7 - startX; + maxWidth /= 0.75f; + + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.35f, 0.35f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor(ModGuiUtils.darkenColor(blockEntity.getColor(), -0.75f)) + .withPredefinedTextTransformation(new TextTransformation(2 + startX + 2, 10, 0.0f, 0.75f, 0.3f)) + .build() + ); + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERTrainDestinationInformative.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERTrainDestinationInformative.java new file mode 100644 index 00000000..1783cb64 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERTrainDestinationInformative.java @@ -0,0 +1,133 @@ +package de.mrjulsen.crn.client.ber.variants; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.base.BERText.TextTransformation; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.BlockEntityRendererContext; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.ChatFormatting; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; + +public class BERTrainDestinationInformative implements IBERRenderSubtype { + + @Override + public boolean isSingleLined() { + return true; + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + if (blockEntity.getTrainData() == null) { + return; + } + parent.labels.clear(); + + int displayWidth = blockEntity.getXSizeScaled(); + boolean isSingleBlock = blockEntity.getXSizeScaled() <= 1; + + float maxWidth = displayWidth * 16 - 6; + maxWidth /= 0.5f; + + // TRAIN NAME + MutableComponent line = Utils.text(String.format("%02d", blockEntity.getCarriageData().index() + 1)).withStyle(ChatFormatting.BOLD); + float textWidth = parent.getFontUtils().font.width(line) * 0.25f; + BERText lastLabel = parent.carriageIndexLabel = new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, false) + .withStretchScale(0.5f, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor() & 0x00FFFFFF)) + .withPredefinedTextTransformation(new TextTransformation(displayWidth * 16 - 2.5f - textWidth, 2.5f, 0.0f, 0.5f, 0.3f)) + .build(); + parent.labels.add(lastLabel); + + line = Utils.text(blockEntity.getTrainData().trainName()).withStyle(ChatFormatting.BOLD); + lastLabel = new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(isSingleBlock) + .withMaxWidth(maxWidth - 10f - textWidth, true) + .withStretchScale(0.3f, 0.6f) + .withStencil(0, maxWidth - 10f - textWidth) + .withCanScroll(true, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor() & 0x00FFFFFF)) + .withPredefinedTextTransformation(new TextTransformation(3.0f, 2.5f, 0.0f, 0.5f, 0.3f)) + .build(); + parent.labels.add(lastLabel); + + // DESTINATION + line = Utils.text(blockEntity.getTrainData().getNextStop().get().stationTagName()).withStyle(ChatFormatting.BOLD); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.25f, 0.5f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3.0f, 6.0f, 0.0f, 0.5f, 0.25f)) + .build() + ); + + // STOPOVERS + line = parent.getStopoversString(blockEntity); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.25f, 0.4f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3.0f, 8.75f, 0.0f, 0.5f, 0.2f)) + .build() + ); + + // DESTINATION + line = Utils.text(blockEntity.getTrainData().getNextStop().get().scheduleTitle()).withStyle(ChatFormatting.BOLD); + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(false) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.25f, 0.5f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(3.0f, 11.0f, 0.0f, 0.5f, 0.25f)) + .build() + ); + } + + @Override + public void renderAdditional(BlockEntityRendererContext context, AdvancedDisplayBlockEntity pBlockEntity, AdvancedDisplayRenderInstance parent, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay, Boolean backSide) { + context.renderUtils().initRenderEngine(); + float uv = 1.0f / 256.0f; + context.renderUtils().renderTexture( + new ResourceLocation("create:textures/gui/assemble.png"), + pBufferSource, + pBlockEntity, + pPoseStack, + pBlockEntity.getXSizeScaled() * 16 - 6f - (parent.carriageIndexLabel == null ? 0 : parent.carriageIndexLabel.getScaledTextWidth() * 0.5f), + 2.5f, + 0.0f, + 3.0f, + 2.0f, + uv * 22, + uv * 231, + uv * 22 + uv * 13, + uv * 231 + uv * 5, + pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), + (0xFF << 24) | (pBlockEntity.getColor() & 0x00FFFFFF), + pPackedLight + ); + + + context.renderUtils().fillColor(pBufferSource, pBlockEntity, (0xFF << 24) | (pBlockEntity.getColor() & 0x00FFFFFF), pPoseStack, 2.5f, 5.0f, 0.0f, pBlockEntity.getXSizeScaled() * 16 - 5, 0.25f, pBlockEntity.getBlockState().getValue(HorizontalDirectionalBlock.FACING), pPackedLight); + } + + +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/BERTrainDestinationSimple.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERTrainDestinationSimple.java new file mode 100644 index 00000000..1a848c91 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/BERTrainDestinationSimple.java @@ -0,0 +1,64 @@ +package de.mrjulsen.crn.client.ber.variants; + +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.ber.AdvancedDisplayRenderInstance; +import de.mrjulsen.crn.client.ber.base.BERText; +import de.mrjulsen.crn.client.ber.base.BERText.TextTransformation; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public class BERTrainDestinationSimple implements IBERRenderSubtype { + + @Override + public boolean isSingleLined() { + return true; + } + + @Override + public void update(Level level, BlockPos pos, BlockState state, AdvancedDisplayBlockEntity blockEntity, AdvancedDisplayRenderInstance parent, EUpdateReason reason) { + if (blockEntity.getTrainData() == null) { + return; + } + + parent.labels.clear(); + + int displayWidth = blockEntity.getXSizeScaled(); + boolean isSingleBlock = blockEntity.getXSizeScaled() <= 1; + + // TRAIN NAME + float maxWidth = isSingleBlock ? 11.0f : 12.0f; + MutableComponent line = Utils.text(blockEntity.getTrainData().trainName()).withStyle(ChatFormatting.BOLD); + BERText lastLabel = new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(isSingleBlock) + .withMaxWidth(maxWidth, isSingleBlock) + .withStretchScale(0.3f, 0.6f) + .withStencil(0, displayWidth * 16 - 5) + .withCanScroll(isSingleBlock, 0.5f) + .withColor((0xFF << 24) | (blockEntity.getColor() & 0x00FFFFFF)) + .withPredefinedTextTransformation(new TextTransformation(isSingleBlock ? 2.5f : 3.0f, 5f, 0.0f, 1, 0.8f)) + .build(); + parent.labels.add(lastLabel); + + if (!isSingleBlock) { + // DESTINATION + float startX = lastLabel.getScaledTextWidth(); + line = Utils.text(blockEntity.getTrainData().getNextStop().get().scheduleTitle()); + maxWidth = displayWidth * 16 - 7 - startX; + parent.labels.add(new BERText(parent.getFontUtils(), line, 0) + .withIsCentered(true) + .withMaxWidth(maxWidth, true) + .withStretchScale(0.25f, 0.5f) + .withStencil(0, maxWidth) + .withCanScroll(true, 1) + .withColor((0xFF << 24) | (blockEntity.getColor())) + .withPredefinedTextTransformation(new TextTransformation(2 + startX + 2, 6, 0.0f, 1, 0.5f)) + .build() + ); + } + } +} diff --git a/src/main/java/de/mrjulsen/crn/client/ber/variants/IBERRenderSubtype.java b/src/main/java/de/mrjulsen/crn/client/ber/variants/IBERRenderSubtype.java new file mode 100644 index 00000000..45a37679 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/ber/variants/IBERRenderSubtype.java @@ -0,0 +1,19 @@ +package de.mrjulsen.crn.client.ber.variants; + +import com.mojang.blaze3d.vertex.PoseStack; + +import de.mrjulsen.crn.client.ber.base.AbstractBlockEntityRenderInstance; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.BlockEntityRendererContext; +import de.mrjulsen.crn.client.ber.base.IBlockEntityRendererInstance.EUpdateReason; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public interface IBERRenderSubtype, U> { + void update(Level level, BlockPos pos, BlockState state, T blockEntity, S parent, EUpdateReason reason); + boolean isSingleLined(); + default void renderAdditional(BlockEntityRendererContext context, T pBlockEntity, S parent, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBufferSource, int pPackedLight, int pOverlay, U renderData) {} + default void tick(Level level, BlockPos pos, BlockState state, T pBlockEntity, S parent) {} +} diff --git a/src/main/java/de/mrjulsen/crn/client/gui/ModGuiIcons.java b/src/main/java/de/mrjulsen/crn/client/gui/ModGuiIcons.java index 4e4f6df1..1ae26e2a 100644 --- a/src/main/java/de/mrjulsen/crn/client/gui/ModGuiIcons.java +++ b/src/main/java/de/mrjulsen/crn/client/gui/ModGuiIcons.java @@ -15,6 +15,7 @@ public enum ModGuiIcons { CHECK("check", 1, 0), CROSS("cross", 2, 0), WARN("warn", 3, 0), + SETTINGS("settings", 0, 1), FILTER("filter", 1, 1), BOOKMARK("bookmark", 2, 1), @@ -31,11 +32,21 @@ public enum ModGuiIcons { TARGET("target", 13, 1), TIME("target", 14, 1), WALK("walk", 15, 1), + INFO("info", 0, 2), EXPAND("expand", 1, 2), COLLAPSE("collapse", 2, 2), DELETE("delete", 3, 2), - ADD("add", 4, 2); + ADD("add", 4, 2), + DOUBLE_SIDED("double_sided", 5, 2), + TRAIN_DESTINATION("train_destination", 6, 2), + PASSENGER_INFORMATION("passenger_information", 7, 2), + PLATFORM_INFORMATION("platform_information", 8, 2), + LESS_DETAILS("less_details", 9, 2), + DETAILED("detailed", 10, 2), + VERY_DETAILED("very_detailed", 11, 2), + ARROW_RIGHT("arrow_right", 12, 2), + ARROW_LEFT("arrow_left", 13, 2); private String id; private int u; diff --git a/src/main/java/de/mrjulsen/crn/data/OverlayPosition.java b/src/main/java/de/mrjulsen/crn/client/gui/overlay/OverlayPosition.java similarity index 96% rename from src/main/java/de/mrjulsen/crn/data/OverlayPosition.java rename to src/main/java/de/mrjulsen/crn/client/gui/overlay/OverlayPosition.java index 6c392b34..458a4005 100644 --- a/src/main/java/de/mrjulsen/crn/data/OverlayPosition.java +++ b/src/main/java/de/mrjulsen/crn/client/gui/overlay/OverlayPosition.java @@ -1,4 +1,4 @@ -package de.mrjulsen.crn.data; +package de.mrjulsen.crn.client.gui.overlay; import java.util.Arrays; diff --git a/src/main/java/de/mrjulsen/crn/client/gui/overlay/RouteDetailsOverlayScreen.java b/src/main/java/de/mrjulsen/crn/client/gui/overlay/RouteDetailsOverlayScreen.java index 8b8f1f3a..f1a1fce7 100644 --- a/src/main/java/de/mrjulsen/crn/client/gui/overlay/RouteDetailsOverlayScreen.java +++ b/src/main/java/de/mrjulsen/crn/client/gui/overlay/RouteDetailsOverlayScreen.java @@ -17,12 +17,10 @@ import de.mrjulsen.crn.client.ClientWrapper; import de.mrjulsen.crn.client.gui.ModGuiIcons; import de.mrjulsen.crn.client.gui.NavigatorToast; -import de.mrjulsen.crn.client.input.KeyBinding; +import de.mrjulsen.crn.client.input.ModKeys; import de.mrjulsen.crn.config.ModClientConfig; -import de.mrjulsen.crn.data.OverlayPosition; import de.mrjulsen.crn.data.SimpleRoute; import de.mrjulsen.crn.data.SimpleTrainConnection; -import de.mrjulsen.crn.item.ModItems; import de.mrjulsen.crn.data.SimpleRoute.StationEntry; import de.mrjulsen.crn.data.SimpleRoute.StationTag; import de.mrjulsen.crn.event.listeners.IJourneyListenerClient; @@ -40,6 +38,7 @@ import de.mrjulsen.crn.network.NetworkManager; import de.mrjulsen.crn.network.packets.cts.NextConnectionsRequestPacket; import de.mrjulsen.crn.network.packets.cts.TrainDataRequestPacket; +import de.mrjulsen.crn.registry.ModItems; import de.mrjulsen.crn.util.ModGuiUtils; import de.mrjulsen.mcdragonlib.DragonLibConstants; import de.mrjulsen.mcdragonlib.client.gui.GuiUtils; @@ -196,7 +195,7 @@ public void onClose() { @Override public void tick() { - if (KeyBinding.OPEN_SETTINGS_KEY.isDown() && Minecraft.getInstance().player.getInventory().hasAnyOf(Set.of(ModItems.NAVIGATOR.get()))) { + if (ModKeys.keyRouteOverlayOptions.isDown() && Minecraft.getInstance().player.getInventory().hasAnyOf(Set.of(ModItems.NAVIGATOR.get()))) { ClientWrapper.showRouteOverlaySettingsGui(this); } @@ -453,7 +452,7 @@ private void setTrainDataSubPage(boolean reset) { )); trainDataSubPageTime = 0; }); - NetworkManager.getInstance().sendToServer(Minecraft.getInstance().getConnection().getConnection(), new TrainDataRequestPacket(id, getListener().currentStation().getTrain().trainId())); + NetworkManager.getInstance().sendToServer(Minecraft.getInstance().getConnection().getConnection(), new TrainDataRequestPacket(id, getListener().currentStation().getTrain().trainId(), false)); break; } } diff --git a/src/main/java/de/mrjulsen/crn/client/gui/screen/AbstractBlacklistScreen.java b/src/main/java/de/mrjulsen/crn/client/gui/screen/AbstractBlacklistScreen.java index 04fb857d..4e9635a0 100644 --- a/src/main/java/de/mrjulsen/crn/client/gui/screen/AbstractBlacklistScreen.java +++ b/src/main/java/de/mrjulsen/crn/client/gui/screen/AbstractBlacklistScreen.java @@ -126,7 +126,7 @@ public void onClick(double mouseX, double mouseY) { addTooltip(DragonLibTooltip.of(tooltipAdd).assignedTo(addButton)); searchBox = addRenderableWidget(new HintTextBox(font, guiLeft + AREA_X + 1, guiTop + 16 + 1, AREA_W - 2, 16)); - searchBox.setHint(Constants.TEXT_SEARCH); + searchBox.setHint(Constants.TEXT_SEARCH.getString()); searchBox.setResponder(text -> { initStationDeleteButtons(); }); diff --git a/src/main/java/de/mrjulsen/crn/client/gui/screen/AbstractEntryListSettingsScreen.java b/src/main/java/de/mrjulsen/crn/client/gui/screen/AbstractEntryListSettingsScreen.java index e6ab6434..e3e28094 100644 --- a/src/main/java/de/mrjulsen/crn/client/gui/screen/AbstractEntryListSettingsScreen.java +++ b/src/main/java/de/mrjulsen/crn/client/gui/screen/AbstractEntryListSettingsScreen.java @@ -108,7 +108,7 @@ protected void init() { addTooltip(DragonLibTooltip.of(tooltipAdd).assignedTo(addButton)); searchBox = addRenderableWidget(new HintTextBox(font, guiLeft + AREA_X + 1, guiTop + 16 + 1, AREA_W - 2, 16)); - searchBox.setHint(Constants.TEXT_SEARCH); + searchBox.setHint(Constants.TEXT_SEARCH.getString()); searchBox.setResponder(text -> { refreshEntries(); }); diff --git a/src/main/java/de/mrjulsen/crn/client/gui/screen/AdvancedDisplaySettingsScreen.java b/src/main/java/de/mrjulsen/crn/client/gui/screen/AdvancedDisplaySettingsScreen.java new file mode 100644 index 00000000..2bb153b3 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/gui/screen/AdvancedDisplaySettingsScreen.java @@ -0,0 +1,214 @@ +package de.mrjulsen.crn.client.gui.screen; + +import java.util.Arrays; +import java.util.List; + +import com.simibubi.create.content.trains.station.NoShadowFontWrapper; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.element.GuiGameElement; +import com.simibubi.create.foundation.gui.widget.AbstractSimiWidget; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.gui.widget.Label; +import com.simibubi.create.foundation.gui.widget.ScrollInput; +import com.simibubi.create.foundation.gui.widget.SelectionScrollInput; +import com.simibubi.create.foundation.utility.Components; + +import de.mrjulsen.crn.ModMain; +import de.mrjulsen.crn.block.AbstractAdvancedDisplayBlock; +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.client.gui.ModGuiIcons; +import de.mrjulsen.crn.config.ModCommonConfig; +import de.mrjulsen.crn.data.ClientTrainStationSnapshot; +import de.mrjulsen.crn.data.EDisplayInfo; +import de.mrjulsen.crn.data.EDisplayType; +import de.mrjulsen.crn.data.ESide; +import de.mrjulsen.crn.data.GlobalSettingsManager; +import de.mrjulsen.crn.network.NetworkManager; +import de.mrjulsen.crn.network.packets.cts.AdvancedDisplayUpdatePacket; +import de.mrjulsen.mcdragonlib.DragonLibConstants; +import de.mrjulsen.mcdragonlib.client.gui.DragonLibTooltip; +import de.mrjulsen.mcdragonlib.client.gui.GuiUtils; +import de.mrjulsen.mcdragonlib.client.gui.wrapper.CommonScreen; +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Renderable; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +public class AdvancedDisplaySettingsScreen extends CommonScreen { + + private static final Component title = Utils.translate("gui.createrailwaysnavigator.advanced_display_settings.title"); + private static final ResourceLocation GUI = new ResourceLocation(ModMain.MOD_ID, "textures/gui/advanced_display_settings.png"); + private static final int GUI_WIDTH = 212; + private static final int GUI_HEIGHT = 123; + private static final int DEFAULT_ICON_BUTTON_WIDTH = 18; + private static final int DEFAULT_ICON_BUTTON_HEIGHT = 18; + + private final Font shadowlessFont; + private final ItemStack renderedItem; + + // Settings + private final Level level; + private final BlockPos pos; + private EDisplayInfo info; + private EDisplayType type; + private ESide side; + + private ScrollInput infoTypeInput; + private Label infoTypeLabel; + private ScrollInput displayTypeInput; + private Label displayTypeLabel; + private ScrollInput sidesInput; + private Label sidesLabel; + + private IconButton globalSettingsButton; + private final MutableComponent tooltipGlobalSettings = Utils.translate("gui." + ModMain.MOD_ID + ".navigator.global_settings.tooltip"); + private final MutableComponent tooltipDisplayType = Utils.translate("gui.createrailwaysnavigator.advanced_display_settings.display_type"); + private final MutableComponent tooltipDisplayTypeDescription = Utils.translate("gui.createrailwaysnavigator.advanced_display_settings.display_type.description"); + private final MutableComponent tooltipInfoType = Utils.translate("gui.createrailwaysnavigator.advanced_display_settings.info_type"); + private final MutableComponent tooltipInfoTypeDescription = Utils.translate("gui.createrailwaysnavigator.advanced_display_settings.info_type.description"); + private final MutableComponent tooltipSides = Utils.translate("gui.createrailwaysnavigator.advanced_display_settings.sides"); + private final MutableComponent tooltipSidesDescription = Utils.translate("gui.createrailwaysnavigator.advanced_display_settings.sides.description"); + + private int guiLeft, guiTop; + + private IconButton backButton; + + @SuppressWarnings("resource") + public AdvancedDisplaySettingsScreen(AdvancedDisplayBlockEntity blockEntity) { + super(title); + this.shadowlessFont = new NoShadowFontWrapper(Minecraft.getInstance().font); + this.pos = blockEntity.getBlockPos(); + this.level = blockEntity.getLevel(); + this.info = blockEntity.getInfoType(); + this.type = blockEntity.getDisplayType(); + this.side = blockEntity.getBlockState().getValue(AbstractAdvancedDisplayBlock.SIDE); + this.renderedItem = new ItemStack(blockEntity.getBlockState().getBlock()); + } + + @Override + public void onClose() { + NetworkManager.getInstance().sendToServer(Minecraft.getInstance().getConnection().getConnection(), new AdvancedDisplayUpdatePacket(level, pos, type, info, side)); + super.onClose(); + } + + @Override + protected void init() { + super.init(); + guiLeft = this.width / 2 - GUI_WIDTH / 2; + guiTop = this.height / 2 - GUI_HEIGHT / 2; + + backButton = this.addRenderableWidget(new IconButton(guiLeft + 179, guiTop + 99, DEFAULT_ICON_BUTTON_WIDTH, DEFAULT_ICON_BUTTON_HEIGHT, AllIcons.I_CONFIRM)); + backButton.withCallback(() -> { + onClose(); + }); + + displayTypeLabel = addRenderableWidget(new Label(guiLeft + 45 + 5, guiTop + 23 + 5, Components.immutableEmpty()).withShadow()); + displayTypeInput = addRenderableWidget(new SelectionScrollInput(guiLeft + 45, guiTop + 23, 138, 18) + .forOptions(Arrays.stream(EDisplayType.values()).map(x -> Utils.translate(x.getValueTranslationKey(ModMain.MOD_ID))).toList()) + .titled(tooltipDisplayType) + .writingTo(displayTypeLabel) + .calling((i) -> { + type = EDisplayType.getTypeById(i); + }) + .addHint(tooltipDisplayTypeDescription) + .setState(type.getId())); + displayTypeInput.onChanged(); + + infoTypeLabel = addRenderableWidget(new Label(guiLeft + 45 + 5, guiTop + 45 + 5, Components.immutableEmpty()).withShadow()); + infoTypeInput = addRenderableWidget(new SelectionScrollInput(guiLeft + 45, guiTop + 45, 138, 18) + .forOptions(Arrays.stream(EDisplayInfo.values()).map(x -> Utils.translate(x.getValueTranslationKey(ModMain.MOD_ID))).toList()) + .titled(tooltipInfoType) + .writingTo(infoTypeLabel) + .calling((i) -> { + info = EDisplayInfo.getTypeById(i); + }) + .addHint(tooltipInfoTypeDescription) + .setState(info.getId())); + infoTypeInput.onChanged(); + + sidesLabel = addRenderableWidget(new Label(guiLeft + 45 + 5, guiTop + 67 + 5, Components.immutableEmpty()).withShadow()); + sidesInput = addRenderableWidget(new SelectionScrollInput(guiLeft + 45, guiTop + 67, 138, 18) + .forOptions(Arrays.stream(ESide.values()).map(x -> Utils.translate(x.getValueTranslationKey(ModMain.MOD_ID))).toList()) + .titled(tooltipSides) + .writingTo(sidesLabel) + .calling((i) -> { + side = ESide.getSideById(i); + }) + .addHint(tooltipSidesDescription) + .setState(side.getId())); + sidesInput.onChanged(); + + // Global Options Button + if (minecraft.player.hasPermissions(ModCommonConfig.GLOBAL_SETTINGS_PERMISSION_LEVEL.get())) { + final Screen instance = this; + globalSettingsButton = this.addRenderableWidget(new IconButton(guiLeft + 7, guiTop + 99, DEFAULT_ICON_BUTTON_WIDTH, DEFAULT_ICON_BUTTON_HEIGHT, ModGuiIcons.SETTINGS.getAsCreateIcon()) { + @Override + public void onClick(double mouseX, double mouseY) { + super.onClick(mouseX, mouseY); + minecraft.setScreen(new LoadingScreen()); + GlobalSettingsManager.syncToClient(() -> { + ClientTrainStationSnapshot.syncToClient(() -> { + minecraft.setScreen(new GlobalSettingsScreen(level, instance)); + }); + }); + } + }); + addTooltip(DragonLibTooltip.of(tooltipGlobalSettings).assignedTo(globalSettingsButton)); + } + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public void tick() { + super.tick(); + infoTypeInput.tick(); + displayTypeInput.tick(); + sidesInput.tick(); + } + + @Override + public void renderBg(GuiGraphics graphics, int pMouseX, int pMouseY, float pPartialTick) { + renderBackground(graphics); + GuiUtils.blit(GUI, graphics, guiLeft, guiTop, 0, 0, GUI_WIDTH, GUI_HEIGHT); + graphics.drawString(shadowlessFont, title, guiLeft + 6, guiTop + 4, DragonLibConstants.DEFAULT_UI_FONT_COLOR); + + GuiGameElement.of(renderedItem).at(guiLeft + GUI_WIDTH, guiTop + GUI_HEIGHT - 48, -200) + .scale(4f) + .render(graphics); + + type.getIcon().render(graphics, guiLeft + 22, guiTop + 24); + info.getIcon().render(graphics, guiLeft + 22, guiTop + 46); + ModGuiIcons.DOUBLE_SIDED.render(graphics, guiLeft + 22, guiTop + 68); + + super.renderBg(graphics, pMouseX, pMouseY, pPartialTick); + } + + @Override + public void renderFg(GuiGraphics graphics, int pMouseX, int pMouseY, float pPartialTick) { + super.renderFg(graphics, pMouseX, pMouseY, pPartialTick); + for (Renderable widget : renderables) { + if (widget instanceof AbstractSimiWidget simiWidget && simiWidget.isHoveredOrFocused() + && simiWidget.visible) { + List tooltip = simiWidget.getToolTip(); + if (tooltip.isEmpty()) + continue; + int ttx = simiWidget.lockedTooltipX == -1 ? pMouseX : simiWidget.lockedTooltipX + simiWidget.getX(); + int tty = simiWidget.lockedTooltipY == -1 ? pMouseY : simiWidget.lockedTooltipY + simiWidget.getY(); + graphics.renderComponentTooltip(font, tooltip, ttx, tty); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/de/mrjulsen/crn/client/gui/screen/RouteOverlaySettingsScreen.java b/src/main/java/de/mrjulsen/crn/client/gui/screen/RouteOverlaySettingsScreen.java index 03f4991d..49714c2c 100644 --- a/src/main/java/de/mrjulsen/crn/client/gui/screen/RouteOverlaySettingsScreen.java +++ b/src/main/java/de/mrjulsen/crn/client/gui/screen/RouteOverlaySettingsScreen.java @@ -22,10 +22,10 @@ import de.mrjulsen.crn.client.gui.ModGuiIcons; import de.mrjulsen.crn.client.gui.NavigatorToast; import de.mrjulsen.crn.client.gui.overlay.HudOverlays; +import de.mrjulsen.crn.client.gui.overlay.OverlayPosition; import de.mrjulsen.crn.client.gui.overlay.RouteDetailsOverlayScreen; import de.mrjulsen.crn.config.ModClientConfig; -import de.mrjulsen.crn.data.OverlayPosition; -import de.mrjulsen.crn.item.ModItems; +import de.mrjulsen.crn.registry.ModItems; import de.mrjulsen.crn.util.Pair; import de.mrjulsen.mcdragonlib.DragonLibConstants; import de.mrjulsen.mcdragonlib.client.gui.GuiUtils; diff --git a/src/main/java/de/mrjulsen/crn/client/gui/screen/SearchSettingsScreen.java b/src/main/java/de/mrjulsen/crn/client/gui/screen/SearchSettingsScreen.java index 517679fb..9943d18b 100644 --- a/src/main/java/de/mrjulsen/crn/client/gui/screen/SearchSettingsScreen.java +++ b/src/main/java/de/mrjulsen/crn/client/gui/screen/SearchSettingsScreen.java @@ -181,6 +181,7 @@ public void onClose() { public void tick() { super.tick(); scroll.tickChaser(); + transferTimeInput.tick(); } private void renderDefaultOptionWidget(GuiGraphics graphics, int x, int y, String text, MultiLineLabel label) { diff --git a/src/main/java/de/mrjulsen/crn/client/input/KeyBinding.java b/src/main/java/de/mrjulsen/crn/client/input/KeyBinding.java deleted file mode 100644 index 00e1a1c1..00000000 --- a/src/main/java/de/mrjulsen/crn/client/input/KeyBinding.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.mrjulsen.crn.client.input; - -import org.lwjgl.glfw.GLFW; - -import com.mojang.blaze3d.platform.InputConstants; - -import de.mrjulsen.crn.ModMain; -import net.minecraft.client.KeyMapping; -import net.minecraftforge.client.settings.KeyConflictContext; -import net.minecraftforge.client.settings.KeyModifier; - -public class KeyBinding { - public static final String KEY_CAT_MOD = "key." + ModMain.MOD_ID + ".category.crn"; - public static final String KEY_OPEN_OVERLAY_SETTINGS = "key." + ModMain.MOD_ID + ".route_overlay_options"; - - public static final KeyMapping OPEN_SETTINGS_KEY = new KeyMapping(KEY_OPEN_OVERLAY_SETTINGS, KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_R, KEY_CAT_MOD); -} diff --git a/src/main/java/de/mrjulsen/crn/client/input/ModKeys.java b/src/main/java/de/mrjulsen/crn/client/input/ModKeys.java new file mode 100644 index 00000000..a5d24c58 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/client/input/ModKeys.java @@ -0,0 +1,20 @@ +package de.mrjulsen.crn.client.input; + +import com.mojang.blaze3d.platform.InputConstants; + +import de.mrjulsen.crn.ModMain; +import net.minecraft.client.KeyMapping; +import net.minecraftforge.client.settings.IKeyConflictContext; +import net.minecraftforge.client.settings.KeyModifier; + +public class ModKeys { + + private ModKeys() {} + + public static KeyMapping keyRouteOverlayOptions; + + public static KeyMapping registerKey(String name, String category, IKeyConflictContext context, KeyModifier modifier, int keycode) { + KeyMapping k = new KeyMapping("key." + ModMain.MOD_ID + "." + name, context, modifier, InputConstants.Type.KEYSYM, keycode, "key." + ModMain.MOD_ID + ".category." + category); + return k; + } +} diff --git a/src/main/java/de/mrjulsen/crn/config/ModClientConfig.java b/src/main/java/de/mrjulsen/crn/config/ModClientConfig.java index b00811b5..2273ef04 100644 --- a/src/main/java/de/mrjulsen/crn/config/ModClientConfig.java +++ b/src/main/java/de/mrjulsen/crn/config/ModClientConfig.java @@ -3,7 +3,7 @@ import java.util.ArrayList; import java.util.List; -import de.mrjulsen.crn.data.OverlayPosition; +import de.mrjulsen.crn.client.gui.overlay.OverlayPosition; import de.mrjulsen.mcdragonlib.utils.TimeUtils.TimeFormat; import net.minecraftforge.common.ForgeConfigSpec; @@ -15,6 +15,7 @@ public class ModClientConfig { public static final ForgeConfigSpec.ConfigValue REALTIME_PRECISION_THRESHOLD; public static final ForgeConfigSpec.ConfigValue DEVIATION_THRESHOLD; public static final ForgeConfigSpec.ConfigValue NEXT_STOP_ANNOUNCEMENT; + public static final ForgeConfigSpec.ConfigValue DISPLAY_LEAD_TIME; public static final ForgeConfigSpec.ConfigValue REALTIME_EARLY_ARRIVAL_THRESHOLD; public static final ForgeConfigSpec.ConfigValue OVERLAY_SCALE; public static final ForgeConfigSpec.ConfigValue TRANSFER_TIME; @@ -40,6 +41,8 @@ public class ModClientConfig { .defineInRange("general.next_stop_announcement", 500, 100, 1000); REALTIME_PRECISION_THRESHOLD = BUILDER.comment("This value (in ticks) indicates how accurately the real-time data should be displayed. By default, only deviations over 10 in-game minutes (167 ticks, approx. 8 real life seconds) are displayed. The lower the value, the more accurate the real-time data but also the more often deviations from the schedule occur. (Default: 167, 10 in-game minutes)") .defineInRange("general.realtime_precision_threshold", 167, 1, 1000); + DISPLAY_LEAD_TIME = BUILDER.comment("This value indicates when departing trains should be displayed on advanced displays. By default 1000 ticks (1 in-game hour, 50 real life seconds) before departure is imminent.") + .defineInRange("general.display_lead_time", 1000, 200, MAX_TRANSFER_TIME); OVERLAY_SCALE = BUILDER.comment("Scale of the route overlay UI. (Default: 0.75)") .defineInRange("route_overlay.scale", 0.75f, MIN_SCALE, MAX_SCALE); ROUTE_NARRATOR = BUILDER.comment("If active, events during the journey (e.g. the next stop) are announced. (Default: OFF)") diff --git a/src/main/java/de/mrjulsen/crn/data/CarriageData.java b/src/main/java/de/mrjulsen/crn/data/CarriageData.java new file mode 100644 index 00000000..5ad718f0 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/data/CarriageData.java @@ -0,0 +1,5 @@ +package de.mrjulsen.crn.data; + +import net.minecraft.core.Direction; + +public record CarriageData(int index, Direction assemblyDirection, boolean isOppositeDirection) {} diff --git a/src/main/java/de/mrjulsen/crn/data/DeparturePrediction.java b/src/main/java/de/mrjulsen/crn/data/DeparturePrediction.java index 16d20a55..68aac1ea 100644 --- a/src/main/java/de/mrjulsen/crn/data/DeparturePrediction.java +++ b/src/main/java/de/mrjulsen/crn/data/DeparturePrediction.java @@ -1,5 +1,6 @@ package de.mrjulsen.crn.data; +import java.util.Arrays; import java.util.Objects; import java.util.UUID; @@ -18,6 +19,9 @@ public class DeparturePrediction { private String nextStop; private StationInfo info; + // Special data + private TrainExitSide exit = TrainExitSide.UNKNOWN; + private int cycle; public DeparturePrediction(Train train, int ticks, String scheduleTitle, String nextStop, int cycle, StationInfo info) { @@ -34,16 +38,16 @@ public DeparturePrediction(TrainDeparturePrediction prediction) { } public DeparturePrediction copy() { - return new DeparturePrediction(getTrain(), getTicks(), getScheduleTitle(), getNextStopStation(), getCycle(), getInfo()); + return new DeparturePrediction(getTrain(), getTicks(), getScheduleTitle(), getStationName(), getCycle(), getInfo()); } public static DeparturePrediction withNextCycleTicks(DeparturePrediction current) { int cycle = current.getCycle() + 1; - return new DeparturePrediction(current.getTrain(), (getTrainCycleDuration(current.getTrain()) * cycle) + current.getTicks(), current.getScheduleTitle(), current.getNextStopStation(), cycle, current.getInfo()); + return new DeparturePrediction(current.getTrain(), (getTrainCycleDuration(current.getTrain()) * cycle) + current.getTicks(), current.getScheduleTitle(), current.getStationName(), cycle, current.getInfo()); } public static DeparturePrediction withCycleTicks(DeparturePrediction current, int cycles) { - return new DeparturePrediction(current.getTrain(), (getTrainCycleDuration(current.getTrain()) * cycles) + current.getTicks(), current.getScheduleTitle(), current.getNextStopStation(), cycles, current.getInfo()); + return new DeparturePrediction(current.getTrain(), (getTrainCycleDuration(current.getTrain()) * cycles) + current.getTicks(), current.getScheduleTitle(), current.getStationName(), cycles, current.getInfo()); } public Train getTrain() { @@ -58,7 +62,7 @@ public String getScheduleTitle() { return scheduleTitle; } - public String getNextStopStation() { + public String getStationName() { return nextStop; } @@ -82,15 +86,23 @@ public static int getTrainCycleDuration(Train train) { return TrainListener.getInstance().getApproximatedTrainDuration(train); } + public TrainExitSide getExitSide() { + return this.exit; + } + + public void setExit(TrainExitSide exit) { + this.exit = exit; + } + public SimpleDeparturePrediction simplify() { - return new SimpleDeparturePrediction(getNextStop().getAliasName().get(), getTicks(), getScheduleTitle(), getTrain().id, getInfo()); + return new SimpleDeparturePrediction(getNextStop().getAliasName().get(), nextStop, getTicks(), getScheduleTitle(), getTrain().name.getString(), getTrain().id, getInfo(), getExitSide()); } @Override public boolean equals(Object obj) { if (obj instanceof DeparturePrediction other) { - return getTrain().id == other.getTrain().id && getTicks() == other.getTicks() && getScheduleTitle().equals(other.getScheduleTitle()) && getNextStopStation().equals(other.getNextStopStation()); + return getTrain().id == other.getTrain().id && getTicks() == other.getTicks() && getScheduleTitle().equals(other.getScheduleTitle()) && getStationName().equals(other.getStationName()); } return false; @@ -98,11 +110,11 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return 19 * Objects.hash(getTrain().id, getTicks(), getScheduleTitle(), getNextStopStation()); + return 19 * Objects.hash(getTrain().id, getTicks(), getScheduleTitle(), getStationName()); } public boolean similar(DeparturePrediction other) { - return getTicks() == other.getTicks() && getNextStopStation().equals(other.getNextStopStation()); + return getTicks() == other.getTicks() && getStationName().equals(other.getStationName()); } @Override @@ -110,30 +122,63 @@ public String toString() { return String.format("%s, Next stop: %s in %st", getTrain().name.getString(), getNextStop().getAliasName(), getTicks()); } - public static record SimpleDeparturePrediction(String station, int ticks, String scheduleTitle, UUID id, StationInfo info) { + public static enum TrainExitSide { + UNKNOWN((byte)0), + RIGHT((byte)1), + LEFT((byte)-1); + + private byte side; + + TrainExitSide(byte side) { + this.side = side; + } + + public byte getAsByte() { + return side; + } + + public static TrainExitSide getFromByte(byte side) { + return Arrays.stream(values()).filter(x -> x.getAsByte() == side).findFirst().orElse(UNKNOWN); + } + + public TrainExitSide getOpposite() { + return getFromByte((byte)-getAsByte()); + } + } + + public static record SimpleDeparturePrediction(String stationTagName, String stationName, int departureTicks, String scheduleTitle, String trainName, UUID trainId, StationInfo stationInfo, TrainExitSide exitSide) { private static final String NBT_STATION = "station"; + private static final String NBT_STATION_NAME = "stationName"; private static final String NBT_TICKS = "ticks"; private static final String NBT_SCHEDULE_TITLE = "title"; + private static final String NBT_TRAIN_NAME = "tname"; private static final String NBT_ID = "id"; + private static final String NBT_EXIT_SIDE = "exit"; public CompoundTag toNbt() { CompoundTag nbt = new CompoundTag(); - nbt.putString(NBT_STATION, station); - nbt.putInt(NBT_TICKS, ticks); + nbt.putString(NBT_STATION, stationTagName); + nbt.putString(NBT_STATION_NAME, stationName); + nbt.putInt(NBT_TICKS, departureTicks); nbt.putString(NBT_SCHEDULE_TITLE, scheduleTitle); - nbt.putUUID(NBT_ID, id); - info().writeNbt(nbt); + nbt.putString(NBT_TRAIN_NAME, trainName); + nbt.putUUID(NBT_ID, trainId); + stationInfo().writeNbt(nbt); + nbt.putByte(NBT_EXIT_SIDE, exitSide.getAsByte()); return nbt; } public static SimpleDeparturePrediction fromNbt(CompoundTag nbt) { return new SimpleDeparturePrediction( - nbt.getString(NBT_STATION), + nbt.getString(NBT_STATION), + nbt.getString(NBT_STATION_NAME), nbt.getInt(NBT_TICKS), - nbt.getString(NBT_SCHEDULE_TITLE), + nbt.getString(NBT_SCHEDULE_TITLE), + nbt.getString(NBT_TRAIN_NAME), nbt.getUUID(NBT_ID), - StationInfo.fromNbt(nbt) + StationInfo.fromNbt(nbt), + TrainExitSide.getFromByte(nbt.getByte(NBT_EXIT_SIDE)) ); } } diff --git a/src/main/java/de/mrjulsen/crn/data/EDisplayInfo.java b/src/main/java/de/mrjulsen/crn/data/EDisplayInfo.java new file mode 100644 index 00000000..7f7c0b8f --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/data/EDisplayInfo.java @@ -0,0 +1,54 @@ +package de.mrjulsen.crn.data; + +import java.util.Arrays; + +import de.mrjulsen.crn.client.gui.ModGuiIcons; +import de.mrjulsen.mcdragonlib.common.ITranslatableEnum; +import net.minecraft.util.StringRepresentable; + +public enum EDisplayInfo implements StringRepresentable, ITranslatableEnum{ + SIMPLE(0, "simple", ModGuiIcons.LESS_DETAILS), + DETAILED(1, "detailed", ModGuiIcons.DETAILED), + INFORMATIVE(2, "informative", ModGuiIcons.VERY_DETAILED); + + private String name; + private int id; + private ModGuiIcons icon; + + private EDisplayInfo(int id, String name, ModGuiIcons icon) { + this.name = name; + this.id = id; + this.icon = icon; + } + + public String getInfoTypeName() { + return this.name; + } + + public int getId() { + return this.id; + } + + public ModGuiIcons getIcon() { + return icon; + } + + public static EDisplayInfo getTypeById(int id) { + return Arrays.stream(values()).filter(x -> x.getId() == id).findFirst().orElse(EDisplayInfo.SIMPLE); + } + + @Override + public String getSerializedName() { + return name; + } + + @Override + public String getEnumName() { + return "display_info_type"; + } + + @Override + public String getEnumValueName() { + return this.name; + } +} diff --git a/src/main/java/de/mrjulsen/crn/data/EDisplayType.java b/src/main/java/de/mrjulsen/crn/data/EDisplayType.java new file mode 100644 index 00000000..ce4a2961 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/data/EDisplayType.java @@ -0,0 +1,79 @@ +package de.mrjulsen.crn.data; + +import java.util.Arrays; + +import de.mrjulsen.crn.client.gui.ModGuiIcons; +import de.mrjulsen.mcdragonlib.common.ITranslatableEnum; +import net.minecraft.util.StringRepresentable; + +public enum EDisplayType implements StringRepresentable, ITranslatableEnum{ + TRAIN_DESTINATION(0, "train_destination", ModGuiIcons.TRAIN_DESTINATION, EDisplayTypeDataSource.TRAIN_INFORMATION), + PASSENGER_INFORMATION(1, "passenger_information", ModGuiIcons.PASSENGER_INFORMATION, EDisplayTypeDataSource.TRAIN_INFORMATION), + PLATFORM(2, "platform", ModGuiIcons.PLATFORM_INFORMATION, EDisplayTypeDataSource.PLATFORM); + + private String name; + private int id; + private ModGuiIcons icon; + private EDisplayTypeDataSource source; + + private EDisplayType(int id, String name, ModGuiIcons icon, EDisplayTypeDataSource source) { + this.name = name; + this.id = id; + this.icon = icon; + this.source = source; + } + + public String getInfoTypeName() { + return this.name; + } + + public int getId() { + return this.id; + } + + public ModGuiIcons getIcon() { + return icon; + } + + public EDisplayTypeDataSource getSource() { + return source; + } + + public static EDisplayType getTypeById(int id) { + return Arrays.stream(values()).filter(x -> x.getId() == id).findFirst().orElse(EDisplayType.TRAIN_DESTINATION); + } + + @Override + public String getSerializedName() { + return name; + } + + @Override + public String getEnumName() { + return "display_type"; + } + + @Override + public String getEnumValueName() { + return this.name; + } + + public static enum EDisplayTypeDataSource { + TRAIN_INFORMATION(0), + PLATFORM(1); + + private int index; + + EDisplayTypeDataSource(int index) { + this.index = index; + } + + public int getIndex() { + return index; + } + + public static EDisplayTypeDataSource getByIndex(int index) { + return Arrays.stream(EDisplayTypeDataSource.values()).filter(x -> x.getIndex() == index).findFirst().orElse(PLATFORM); + } + } +} diff --git a/src/main/java/de/mrjulsen/crn/data/ESide.java b/src/main/java/de/mrjulsen/crn/data/ESide.java new file mode 100644 index 00000000..1018c815 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/data/ESide.java @@ -0,0 +1,47 @@ +package de.mrjulsen.crn.data; + +import java.util.Arrays; + +import de.mrjulsen.mcdragonlib.common.ITranslatableEnum; +import net.minecraft.util.StringRepresentable; + +public enum ESide implements StringRepresentable, ITranslatableEnum { + FRONT(0, "front"), + BACK(1, "back"), + BOTH(2, "both"); + + private String name; + private int index; + + private ESide(int index, String name) { + this.name = name; + this.index = index; + } + + public String getName() { + return this.name; + } + + public int getId() { + return this.index; + } + + public static ESide getSideById(int index) { + return Arrays.stream(values()).filter(x -> x.getId() == index).findFirst().orElse(FRONT); + } + + @Override + public String getSerializedName() { + return name; + } + + @Override + public String getEnumName() { + return "side"; + } + + @Override + public String getEnumValueName() { + return name; + } +} diff --git a/src/main/java/de/mrjulsen/crn/data/GlobalSettings.java b/src/main/java/de/mrjulsen/crn/data/GlobalSettings.java index 18d7fb4d..29258279 100644 --- a/src/main/java/de/mrjulsen/crn/data/GlobalSettings.java +++ b/src/main/java/de/mrjulsen/crn/data/GlobalSettings.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.ArrayList; import java.util.Optional; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; import com.simibubi.create.content.trains.entity.Train; @@ -24,10 +25,10 @@ public class GlobalSettings { private static final String NBT_TRAIN_BLACKLIST = "TrainBlacklist"; private static final String NBT_TRAIN_GROUP_REGISTRY = "RegisteredTrainGroups"; - private final Collection registeredAlias = new ArrayList<>(); - private final Collection registeredTrainGroups = new ArrayList<>(); - private final Collection blacklist = new ArrayList<>(); - private final Collection trainsBlacklist = new ArrayList<>(); + private final Collection registeredAlias = new CopyOnWriteArrayList<>(); + private final Collection registeredTrainGroups = new CopyOnWriteArrayList<>(); + private final Collection blacklist = new CopyOnWriteArrayList<>(); + private final Collection trainsBlacklist = new CopyOnWriteArrayList<>(); protected GlobalSettings() { diff --git a/src/main/java/de/mrjulsen/crn/data/GlobalTrainData.java b/src/main/java/de/mrjulsen/crn/data/GlobalTrainData.java index 9fb4ffb6..c9a3b41e 100644 --- a/src/main/java/de/mrjulsen/crn/data/GlobalTrainData.java +++ b/src/main/java/de/mrjulsen/crn/data/GlobalTrainData.java @@ -7,10 +7,10 @@ import java.util.List; import java.util.Map; import java.util.HashMap; -import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.content.trains.station.GlobalStation; @@ -31,14 +31,17 @@ private GlobalTrainData(long updateTime) { instance = this; trains = TrainUtils.getAllTrains(); - stationByName = new HashMap<>(); + stationByName = TrainUtils.getAllStations().stream().collect(Collectors.groupingBy(x -> x.name, Collectors.toSet())); + /* for (GlobalStation sta : TrainUtils.getAllStations()) { + stationByName.computeIfAbsent(sta.name, x -> new HashSet<>()).add(sta); if (stationByName.containsKey(sta.name)) { stationByName.get(sta.name).add(sta); } else { stationByName.put(sta.name, new HashSet<>(Set.of(sta))); } } + */ TrainUtils.getMappedDeparturePredictions(aliasPredictions, trainPredictions); this.updateTime = updateTime; } diff --git a/src/main/java/de/mrjulsen/crn/data/IBlockEntitySerializable.java b/src/main/java/de/mrjulsen/crn/data/IBlockEntitySerializable.java new file mode 100644 index 00000000..41368041 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/data/IBlockEntitySerializable.java @@ -0,0 +1,8 @@ +package de.mrjulsen.crn.data; + +import net.minecraft.nbt.CompoundTag; + +public interface IBlockEntitySerializable { + CompoundTag serialize(); + void deserialize(CompoundTag nbt); +} diff --git a/src/main/java/de/mrjulsen/crn/data/SimpleRoute.java b/src/main/java/de/mrjulsen/crn/data/SimpleRoute.java index ff3848ca..05f2d764 100644 --- a/src/main/java/de/mrjulsen/crn/data/SimpleRoute.java +++ b/src/main/java/de/mrjulsen/crn/data/SimpleRoute.java @@ -323,7 +323,7 @@ public static class StationEntry { public StationEntry(TrainStop stop, long refreshTime) { this( stop.getStationAlias().getAliasName().get(), - stop.getStationAlias().getInfoForStation(stop.getPrediction().getNextStopStation()), + stop.getStationAlias().getInfoForStation(stop.getPrediction().getStationName()), stop.getPrediction().getTicks(), refreshTime ); } diff --git a/src/main/java/de/mrjulsen/crn/data/SimpleTrainSchedule.java b/src/main/java/de/mrjulsen/crn/data/SimpleTrainSchedule.java index 16c11cbf..47d9f2e1 100644 --- a/src/main/java/de/mrjulsen/crn/data/SimpleTrainSchedule.java +++ b/src/main/java/de/mrjulsen/crn/data/SimpleTrainSchedule.java @@ -50,6 +50,17 @@ public SimpleTrainSchedule copy() { return new SimpleTrainSchedule(stops.stream().map(x -> x.copy()).toList()); } + public SimpleTrainSchedule makeScheduleUntilNextRepeat() { + List newList = new ArrayList<>(); + for (TrainStop stop : getAllStops()) { + if (newList.contains(stop)) { + break; + } + newList.add(stop); + } + return SimpleTrainSchedule.of(newList); + } + public SimpleTrainSchedule makeScheduleFrom(TrainStationAlias alias, boolean preventDuplicates) { List newList = new ArrayList<>(); int idx = 0; @@ -127,6 +138,10 @@ public List getAllStopsOf(TrainStationAlias alias) { return this.getAllStops().stream().filter(x -> x.getStationAlias().equals(alias)).toList(); } + public List getAllStopsOf(String station) { + return this.getAllStops().stream().filter(x -> x.getPrediction().getStationName().equals(station)).toList(); + } + public boolean isInDirection(TrainStationAlias start, TrainStationAlias end) { for (TrainStop stop : getAllStops()) { if (stop.getStationAlias().equals(start)) { @@ -204,10 +219,33 @@ public SimulatedTrainSchedule simulate(Train train, int simulationTime, TrainSta cycle++; } cycle += x.getPrediction().getCycle(); - return new TrainStop(x.getStationAlias(), new DeparturePrediction(x.getPrediction().getTrain(), estimatedTicks, x.getPrediction().getScheduleTitle(), x.getPrediction().getNextStopStation(), cycle, x.getPrediction().getInfo())); + return new TrainStop(x.getStationAlias(), new DeparturePrediction(x.getPrediction().getTrain(), estimatedTicks, x.getPrediction().getScheduleTitle(), x.getPrediction().getStationName(), cycle, x.getPrediction().getInfo())); }).sorted(Comparator.comparingInt(x -> x.getPrediction().getTicks())).toList(), new SimulationData(getFirstStop().get().getPrediction().getTrain(), simulationTime, timeToTargetAfterSim)); } + public SimulatedTrainSchedule simulate(Train train, int simulationTime, String simulationTarget) { + final int cycleDuration = getTrainCycleDuration(train); + + int timeToTargetAfterSim = getAllStopsOf(simulationTarget).stream().mapToInt(x -> { + int v = (int)((double)(x.getPrediction().getTicks() - simulationTime) % cycleDuration); + if (v < 0) { + v += cycleDuration; + } + return v; + }).min().getAsInt(); + int simToTargetTime = simulationTime + timeToTargetAfterSim; + + return new SimulatedTrainSchedule(getAllStops().parallelStream().map(x -> { + int cycle = (int)((double)(x.getPrediction().getTicks() - simToTargetTime) / cycleDuration); + int estimatedTicks = (x.getPrediction().getTicks() - simToTargetTime) % cycleDuration; + while (estimatedTicks < 0) { + estimatedTicks += cycleDuration; + cycle++; + } + cycle += x.getPrediction().getCycle(); + return new TrainStop(x.getStationAlias(), new DeparturePrediction(x.getPrediction().getTrain(), estimatedTicks, x.getPrediction().getScheduleTitle(), x.getPrediction().getStationName(), cycle, x.getPrediction().getInfo())); + }).sorted(Comparator.comparingInt(x -> x.getPrediction().getTicks())).toList(), new SimulationData(getFirstStop().get().getPrediction().getTrain(), simulationTime, timeToTargetAfterSim)); + } public SimpleTrainSchedule simulate(Train train, int simulationTime) { final int cycleDuration = getTrainCycleDuration(train); @@ -220,7 +258,7 @@ public SimpleTrainSchedule simulate(Train train, int simulationTime) { cycle++; } cycle += x.getPrediction().getCycle(); - return new TrainStop(x.getStationAlias(), new DeparturePrediction(x.getPrediction().getTrain(), estimatedTicks, x.getPrediction().getScheduleTitle(), x.getPrediction().getNextStopStation(), cycle, x.getPrediction().getInfo())); + return new TrainStop(x.getStationAlias(), new DeparturePrediction(x.getPrediction().getTrain(), estimatedTicks, x.getPrediction().getScheduleTitle(), x.getPrediction().getStationName(), cycle, x.getPrediction().getInfo())); }).sorted(Comparator.comparingInt(x -> x.getPrediction().getTicks())).toList()); } diff --git a/src/main/java/de/mrjulsen/crn/event/ClientEvents.java b/src/main/java/de/mrjulsen/crn/event/ClientEvents.java index 87a02d52..9b78a5d2 100644 --- a/src/main/java/de/mrjulsen/crn/event/ClientEvents.java +++ b/src/main/java/de/mrjulsen/crn/event/ClientEvents.java @@ -2,16 +2,20 @@ import net.minecraftforge.event.TickEvent.ClientTickEvent; import net.minecraftforge.event.TickEvent.Phase; +import net.minecraftforge.event.level.LevelEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; +import org.lwjgl.glfw.GLFW; + import de.mrjulsen.crn.ModMain; import de.mrjulsen.crn.client.gui.overlay.HudOverlays; -import de.mrjulsen.crn.client.input.KeyBinding; +import de.mrjulsen.crn.client.input.ModKeys; import de.mrjulsen.crn.data.ClientTrainStationSnapshot; import de.mrjulsen.crn.event.listeners.JourneyListenerManager; import de.mrjulsen.crn.event.listeners.TrainListener; import de.mrjulsen.crn.network.InstanceManager; +import de.mrjulsen.crn.registry.ModExtras; import net.minecraft.client.Minecraft; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ClientPlayerNetworkEvent.LoggingIn; @@ -19,6 +23,8 @@ import net.minecraftforge.client.event.CustomizeGuiOverlayEvent; import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; import net.minecraftforge.client.event.RegisterKeyMappingsEvent; +import net.minecraftforge.client.settings.KeyConflictContext; +import net.minecraftforge.client.settings.KeyModifier; @Mod.EventBusSubscriber(modid = ModMain.MOD_ID, value = Dist.CLIENT) public class ClientEvents { @@ -32,6 +38,11 @@ public static void onTick(ClientTickEvent event) { JourneyListenerManager.tick(); } + @SubscribeEvent + public static void onWorldLoad(LevelEvent.Load event) { + ModExtras.register(); + } + @SubscribeEvent public static void onWorldLeave(LoggingOut event) { int count = HudOverlays.removeAll(); @@ -68,13 +79,12 @@ public static void onDebugOverlay(CustomizeGuiOverlayEvent.DebugText event) { public static class ClientModBusEvents { @SubscribeEvent public static void registerGuiOverlay(final RegisterGuiOverlaysEvent event) { - event.registerAboveAll("route_details_overlay", HudOverlays.HUD_ROUTE_DETAILS); + event.registerBelowAll("route_details_overlay", HudOverlays.HUD_ROUTE_DETAILS); } - @SubscribeEvent public static void onKeyRegister(RegisterKeyMappingsEvent event) { - event.register(KeyBinding.OPEN_SETTINGS_KEY); + event.register(ModKeys.keyRouteOverlayOptions = ModKeys.registerKey("route_overlay_options", "crn", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, GLFW.GLFW_KEY_R)); } } } diff --git a/src/main/java/de/mrjulsen/crn/event/ModEvents.java b/src/main/java/de/mrjulsen/crn/event/ModEvents.java index efe5f643..6eeb70de 100644 --- a/src/main/java/de/mrjulsen/crn/event/ModEvents.java +++ b/src/main/java/de/mrjulsen/crn/event/ModEvents.java @@ -4,11 +4,13 @@ import de.mrjulsen.crn.event.listeners.TrainListener; import de.mrjulsen.crn.network.NetworkManager; import de.mrjulsen.crn.network.packets.stc.TimeCorrectionPacket; +import de.mrjulsen.crn.registry.ModExtras; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraftforge.event.RegisterCommandsEvent; import net.minecraftforge.event.TickEvent.Phase; import net.minecraftforge.event.TickEvent.ServerTickEvent; +import net.minecraftforge.event.level.LevelEvent; import net.minecraftforge.event.server.ServerStartedEvent; import net.minecraftforge.event.server.ServerStoppingEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -30,6 +32,11 @@ public static void onServerStarted(ServerStartedEvent event) { server = event.getServer().overworld(); } + @SubscribeEvent + public static void onWorldJoin(LevelEvent.Load event) { + ModExtras.register(); + } + @SubscribeEvent public static void onServerStopped(ServerStoppingEvent event) { TrainListener.stop(); diff --git a/src/main/java/de/mrjulsen/crn/event/listeners/JourneyListener.java b/src/main/java/de/mrjulsen/crn/event/listeners/JourneyListener.java index e946f352..24fd5a75 100644 --- a/src/main/java/de/mrjulsen/crn/event/listeners/JourneyListener.java +++ b/src/main/java/de/mrjulsen/crn/event/listeners/JourneyListener.java @@ -22,17 +22,16 @@ import de.mrjulsen.crn.network.InstanceManager; import de.mrjulsen.crn.network.NetworkManager; import de.mrjulsen.crn.network.packets.cts.RealtimeRequestPacket; +import de.mrjulsen.crn.util.ModUtils; import de.mrjulsen.mcdragonlib.utils.TimeUtils; import de.mrjulsen.mcdragonlib.utils.Utils; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; public class JourneyListener { public static final int ID = 1; private static final int REALTIME_REFRESH_TIME = 100; - private static final Component TEXT_CONCAT = Utils.text(" *** "); private final SimpleRoute route; private int stationIndex = 0; @@ -98,7 +97,6 @@ public static record AnnounceNextStopData(State state, Component infoText, Strin private boolean beginAnnounced = false; - public JourneyListener(SimpleRoute route) { this.route = route; } @@ -318,7 +316,7 @@ private void requestRealtimeData() { final Collection ids = Arrays.stream(route.getStationArray()).map(x -> x.getTrain().trainId()).distinct().toList(); long id = InstanceManager.registerClientRealtimeResponseAction((predictions, time) -> { - Map> predMap = predictions.stream().collect(Collectors.groupingBy(SimpleDeparturePrediction::id)); + Map> predMap = predictions.stream().collect(Collectors.groupingBy(SimpleDeparturePrediction::trainId)); if (predMap.containsKey(currentStation().getTrain().trainId())) { SimpleDeparturePrediction currentTrainNextStop = predMap.get(currentStation().getTrain().trainId()).get(0); @@ -326,7 +324,7 @@ private void requestRealtimeData() { if (currentState != State.BEFORE_JOURNEY && currentState != State.JOURNEY_INTERRUPTED) { if (currentState != State.WHILE_TRAVELING && currentState != State.WHILE_TRANSFER) { - while (!currentTrainNextStop.station().equals(currentStation().getStationName()) && currentState != State.AFTER_JOURNEY) { + while (!currentTrainNextStop.stationTagName().equals(currentStation().getStationName()) && currentState != State.AFTER_JOURNEY) { if (currentStation().getTag() != StationTag.END) { nextStop(); } @@ -437,7 +435,7 @@ private boolean isStationValidForShedule(List schedul filteredStationEntryList.add(entry.getStationName()); } String[] filteredStationEntries = filteredStationEntryList.toArray(String[]::new); - String[] sched = schedule.stream().map(x -> x.station()).toArray(String[]::new); + String[] sched = schedule.stream().map(x -> x.stationTagName()).toArray(String[]::new); int k = 0; for (int i = 0; i < filteredStationEntries.length; i++) { @@ -468,15 +466,15 @@ private void updateRealtime(List schedule, List lastTime/* && newTime + EARLY_ARRIVAL_THRESHOLD > route.get(k).station().getScheduleTime()*/) { - route.get(k).updateRealtimeData(current.ticks(), updateTime, current.info(), () -> { + route.get(k).updateRealtimeData(current.departureTicks(), updateTime, current.stationInfo(), () -> { }); lastTime = route.get(k).getCurrentTime(); @@ -562,19 +560,6 @@ public NotificationData getLastNotification() { return lastNotification; } - private Component concat(Component... components) { - if (components.length <= 0) { - return Utils.emptyText(); - } - - MutableComponent c = components[0].copy(); - for (int i = 1; i < components.length; i++) { - c.append(TEXT_CONCAT); - c.append(components[i]); - } - return c; - } - private void setState(State state) { this.currentState = state; onStateChange.values().forEach(x -> { @@ -663,7 +648,7 @@ private void announceNextStop() { nextStation().get().getTrain().scheduleTitle(), nextStation().get().getInfo().platform() ); - text = concat(text, transferText); + text = ModUtils.concat(text, transferText); setState(State.BEFORE_TRANSFER); setNotificationText(new NotificationData(currentState, Utils.translate(keyNotificationTransferTitle), Utils.translate(keyNotificationTransfer, nextStation().get().getTrain().trainName(), @@ -723,7 +708,7 @@ private void reachTransferStop() { } private void reachTransferStopConnectionMissed() { - Component text = concat( + Component text = ModUtils.concat( Utils.text(currentStation().getStationName()), Utils.translate(keyConnectionMissedInfo) ); diff --git a/src/main/java/de/mrjulsen/crn/event/listeners/TrainListener.java b/src/main/java/de/mrjulsen/crn/event/listeners/TrainListener.java index 48c6b140..a098e9e0 100644 --- a/src/main/java/de/mrjulsen/crn/event/listeners/TrainListener.java +++ b/src/main/java/de/mrjulsen/crn/event/listeners/TrainListener.java @@ -59,7 +59,7 @@ private boolean performTask(TrainListener instance, Level level, int iteration) return; } - OptionalInt maxTrainDuration = TrainUtils.getTrainDeparturePredictions(train.id).stream().mapToInt(x -> x.getTicks()).max(); + OptionalInt maxTrainDuration = TrainUtils.getTrainDeparturePredictions(train.id, null).stream().mapToInt(x -> x.getTicks()).max(); if (maxTrainDuration.isPresent()) { if (!lastTicks.containsKey(train.id)) { @@ -117,7 +117,8 @@ private void stopInstance() { public int getApproximatedTrainDuration(Train train) { - return getApproximatedTrainDuration(train.id); + int a = getApproximatedTrainDuration(train.id); + return a == 0 ? 1 : a; } public int getApproximatedTrainDuration(UUID trainId) { diff --git a/src/main/java/de/mrjulsen/crn/item/ModItems.java b/src/main/java/de/mrjulsen/crn/item/ModItems.java deleted file mode 100644 index b1dd7ddb..00000000 --- a/src/main/java/de/mrjulsen/crn/item/ModItems.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.mrjulsen.crn.item; - -import java.util.function.Supplier; - -import de.mrjulsen.crn.ModMain; -import de.mrjulsen.crn.item.creativemodetab.ModCreativeModeTab; -import de.mrjulsen.crn.item.creativemodetab.ModCreativeModeTab.ModTab; -import net.minecraft.world.item.Item; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; - -public class ModItems { - public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, ModMain.MOD_ID); - - - public static final RegistryObject NAVIGATOR = registerItem("navigator", () -> new NavigatorItem(), ModTab.MAIN); - - - private static RegistryObject registerItem(String id, Supplier sup, ModTab tab) { - RegistryObject item = ITEMS.register(id, sup); - ModCreativeModeTab.put(tab, item); - return item; - } - - public static void register(IEventBus eventBus) { - ITEMS.register(eventBus); - } -} diff --git a/src/main/java/de/mrjulsen/crn/item/NavigatorItem.java b/src/main/java/de/mrjulsen/crn/item/NavigatorItem.java index a07cd43a..06aa8030 100644 --- a/src/main/java/de/mrjulsen/crn/item/NavigatorItem.java +++ b/src/main/java/de/mrjulsen/crn/item/NavigatorItem.java @@ -10,8 +10,8 @@ public class NavigatorItem extends Item { - public NavigatorItem() { - super(new Properties().stacksTo(1)); + public NavigatorItem(Properties props) { + super(props); } @Override diff --git a/src/main/java/de/mrjulsen/crn/mixin/BakedGlyphAccessor.java b/src/main/java/de/mrjulsen/crn/mixin/BakedGlyphAccessor.java new file mode 100644 index 00000000..37f8b394 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/mixin/BakedGlyphAccessor.java @@ -0,0 +1,41 @@ +package de.mrjulsen.crn.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.client.gui.font.glyphs.BakedGlyph; + +@Mixin(BakedGlyph.class) +public interface BakedGlyphAccessor { + + @Mutable + @Accessor("u0") + void setU0(float value); + + @Accessor("u0") + float getU0(); + + @Mutable + @Accessor("u1") + void setU1(float value); + + @Accessor("u1") + float getU1(); + + + @Mutable + @Accessor("v0") + void setV0(float value); + + @Accessor("v0") + float getV0(); + + @Mutable + @Accessor("v1") + void setV1(float value); + + @Accessor("v1") + float getV1(); + +} diff --git a/src/main/java/de/mrjulsen/crn/mixin/MountedStorageManagerMixin.java b/src/main/java/de/mrjulsen/crn/mixin/MountedStorageManagerMixin.java new file mode 100644 index 00000000..2d37d40a --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/mixin/MountedStorageManagerMixin.java @@ -0,0 +1,34 @@ +package de.mrjulsen.crn.mixin; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.MountedStorageManager; + +import de.mrjulsen.crn.block.be.IContraptionBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; + +@Mixin(MountedStorageManager.class) +public class MountedStorageManagerMixin { + + @Inject(method = "entityTick", remap = false, at = @At(value = "HEAD")) + public void tick$inject(AbstractContraptionEntity entity, CallbackInfo ci) { + Set beList = new LinkedHashSet<>(); + beList.addAll(entity.getContraption().maybeInstancedBlockEntities); + beList.addAll(entity.getContraption().specialRenderedBlockEntities); + + for (BlockEntity be : beList) { + if (be instanceof IContraptionBlockEntity tile) { + tile.contraptionTick(entity.level(), be.getBlockPos(), be.getBlockState(), entity.getContraption()); + } + } + + beList.clear(); + } +} diff --git a/src/main/java/de/mrjulsen/crn/network/NetworkManager.java b/src/main/java/de/mrjulsen/crn/network/NetworkManager.java index 4f82efb3..eaa03ec8 100644 --- a/src/main/java/de/mrjulsen/crn/network/NetworkManager.java +++ b/src/main/java/de/mrjulsen/crn/network/NetworkManager.java @@ -4,6 +4,7 @@ import java.util.List; import de.mrjulsen.crn.ModMain; +import de.mrjulsen.crn.network.packets.cts.AdvancedDisplayUpdatePacket; import de.mrjulsen.crn.network.packets.cts.GlobalSettingsRequestPacket; import de.mrjulsen.crn.network.packets.cts.GlobalSettingsUpdatePacket; import de.mrjulsen.crn.network.packets.cts.NavigationRequestPacket; @@ -33,7 +34,7 @@ public NetworkManager(String modid, String channelName, String protocolVersion) } public static void create() { - instance = NetworkManagerBase.create(NetworkManager.class, ModMain.MOD_ID, "crn_network", "3"); + instance = NetworkManagerBase.create(NetworkManager.class, ModMain.MOD_ID, "crn_network", "5"); } public static NetworkManager getInstance() { @@ -52,6 +53,7 @@ public Collection>> packets() { RealtimeRequestPacket.class, TrackStationsRequestPacket.class, TrainDataRequestPacket.class, + AdvancedDisplayUpdatePacket.class, // stc GlobalSettingsResponsePacket.class, diff --git a/src/main/java/de/mrjulsen/crn/network/packets/cts/AdvancedDisplayUpdatePacket.java b/src/main/java/de/mrjulsen/crn/network/packets/cts/AdvancedDisplayUpdatePacket.java new file mode 100644 index 00000000..f8fa5978 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/network/packets/cts/AdvancedDisplayUpdatePacket.java @@ -0,0 +1,90 @@ +package de.mrjulsen.crn.network.packets.cts; + +import java.util.function.Supplier; + +import de.mrjulsen.crn.block.AbstractAdvancedDisplayBlock; +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.data.EDisplayInfo; +import de.mrjulsen.crn.data.EDisplayType; +import de.mrjulsen.crn.data.ESide; +import de.mrjulsen.mcdragonlib.network.IPacketBase; +import de.mrjulsen.mcdragonlib.network.NetworkManagerBase; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import net.minecraftforge.network.NetworkDirection; +import net.minecraftforge.network.NetworkEvent; + +public class AdvancedDisplayUpdatePacket implements IPacketBase { + private BlockPos pos; + private EDisplayType type; + private EDisplayInfo info; + private ESide side; + + public AdvancedDisplayUpdatePacket() {} + + public AdvancedDisplayUpdatePacket(Level level, BlockPos pos, EDisplayType type, EDisplayInfo info, ESide side) { + this.pos = pos; + this.info = info; + this.type = type; + this.side = side; + apply(level, this); + } + + protected AdvancedDisplayUpdatePacket(BlockPos pos, EDisplayType type, EDisplayInfo info, ESide side) { + this.pos = pos; + this.info = info; + this.type = type; + this.side = side; + } + + @Override + public void encode(AdvancedDisplayUpdatePacket packet, FriendlyByteBuf buffer) { + buffer.writeBlockPos(packet.pos); + buffer.writeInt(packet.info.getId()); + buffer.writeInt(packet.type.getId()); + buffer.writeEnum(packet.side); + } + + @Override + public AdvancedDisplayUpdatePacket decode(FriendlyByteBuf buffer) { + BlockPos pos = buffer.readBlockPos(); + EDisplayInfo info = EDisplayInfo.getTypeById(buffer.readInt()); + EDisplayType type = EDisplayType.getTypeById(buffer.readInt()); + ESide side = buffer.readEnum(ESide.class); + + return new AdvancedDisplayUpdatePacket(pos, type, info, side); + } + + private void apply(Level level, AdvancedDisplayUpdatePacket packet) { + if (level.isLoaded(packet.pos)) { + if (level.getBlockEntity(packet.pos) instanceof AdvancedDisplayBlockEntity blockEntity) { + blockEntity.applyToAll(be -> { + be.setDisplayType(packet.type); + be.setInfoType(packet.info); + if (level.getBlockState(be.getBlockPos()).getBlock() instanceof AbstractAdvancedDisplayBlock) { + level.setBlockAndUpdate(be.getBlockPos(), level.getBlockState(be.getBlockPos()).setValue(AbstractAdvancedDisplayBlock.SIDE, packet.side)); + } + be.notifyUpdate(); + }); + } + } + } + + @Override + public void handle(AdvancedDisplayUpdatePacket packet, Supplier context) { + NetworkManagerBase.handlePacket(packet, context, () -> { + ServerPlayer player = context.get().getSender(); + if (player != null) { + Level level = player.level(); + apply(level, packet); + } + }); + } + + @Override + public NetworkDirection getDirection() { + return NetworkDirection.PLAY_TO_SERVER; + } +} diff --git a/src/main/java/de/mrjulsen/crn/network/packets/cts/RealtimeRequestPacket.java b/src/main/java/de/mrjulsen/crn/network/packets/cts/RealtimeRequestPacket.java index 444a30d2..d0845909 100644 --- a/src/main/java/de/mrjulsen/crn/network/packets/cts/RealtimeRequestPacket.java +++ b/src/main/java/de/mrjulsen/crn/network/packets/cts/RealtimeRequestPacket.java @@ -12,6 +12,7 @@ import de.mrjulsen.crn.network.packets.stc.RealtimeResponsePacket; import de.mrjulsen.crn.util.TrainUtils; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.Level; import net.minecraftforge.network.NetworkDirection; import net.minecraftforge.network.NetworkEvent; @@ -51,14 +52,16 @@ public RealtimeRequestPacket decode(FriendlyByteBuf buffer) { public void handle(RealtimeRequestPacket packet, Supplier context) { context.get().enqueueWork(() -> { + final Level level = context.get().getSender().level(); new Thread(() -> { - final long updateTime = context.get().getSender().level().getDayTime(); + final long updateTime = level.getDayTime(); Collection predictions = new ArrayList<>(); packet.ids.forEach(x -> { if (!TrainUtils.isTrainIdValid(x)) { return; } - predictions.addAll(TrainUtils.getTrainDeparturePredictions(x).stream().map(a -> a.simplify()).sorted(Comparator.comparingInt(a -> a.ticks())).toList()); + + predictions.addAll(TrainUtils.getTrainDeparturePredictions(x, context.get().getSender().level()).stream().map(a -> a.simplify()).sorted(Comparator.comparingInt(a -> a.departureTicks())).toList()); }); NetworkManager.getInstance().sendToClient(new RealtimeResponsePacket(packet.requestId, predictions, updateTime), context.get().getSender()); }, "Realtime Provider").run(); diff --git a/src/main/java/de/mrjulsen/crn/network/packets/cts/TrainDataRequestPacket.java b/src/main/java/de/mrjulsen/crn/network/packets/cts/TrainDataRequestPacket.java index 28de962b..dc1fb152 100644 --- a/src/main/java/de/mrjulsen/crn/network/packets/cts/TrainDataRequestPacket.java +++ b/src/main/java/de/mrjulsen/crn/network/packets/cts/TrainDataRequestPacket.java @@ -1,15 +1,32 @@ package de.mrjulsen.crn.network.packets.cts; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.function.Supplier; import com.simibubi.create.content.trains.entity.Train; + +import de.mrjulsen.crn.Constants; +import de.mrjulsen.crn.data.DeparturePrediction.TrainExitSide; +import de.mrjulsen.crn.data.DeparturePrediction.SimpleDeparturePrediction; +import de.mrjulsen.crn.data.GlobalSettingsManager; +import de.mrjulsen.crn.data.SimpleTrainSchedule; +import de.mrjulsen.crn.data.TrainStop; import de.mrjulsen.crn.network.NetworkManager; import de.mrjulsen.mcdragonlib.network.IPacketBase; +import de.mrjulsen.mcdragonlib.utils.Utils; import de.mrjulsen.crn.network.packets.stc.TrainDataResponsePacket; +import de.mrjulsen.crn.util.Cache; import de.mrjulsen.crn.util.TrainUtils; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.Level; import net.minecraftforge.network.NetworkDirection; import net.minecraftforge.network.NetworkEvent; @@ -17,63 +34,159 @@ public class TrainDataRequestPacket implements IPacketBase context) { - context.get().enqueueWork(() -> - { + context.get().enqueueWork(() -> { + final Level level = context.get().getSender().level(); + final long updateTime = level.getDayTime(); Train train = TrainUtils.getTrain(packet.trainId); + List departurePredictions = new ArrayList<>(); + if (packet.getPredictions && train != null) { + Collection stops = new ArrayList<>(TrainUtils.getTrainStopsSorted(packet.trainId, level).stream().filter(x -> !GlobalSettingsManager.getInstance().getSettingsData().isBlacklisted(x.getStationAlias())).toList()); + if (stops != null) { + departurePredictions.addAll(SimpleTrainSchedule.of(stops).makeScheduleUntilNextRepeat().getAllStops().stream().map(x -> x.getPrediction().simplify()).toList()); + } + } + NetworkManager.getInstance().sendToClient(new TrainDataResponsePacket(packet.requestId, new TrainData( packet.trainId, + train.name.getString(), + departurePredictions, train.speed, - train.navigation.ticksWaitingForSignal - ), context.get().getSender().level().getDayTime()), context.get().getSender()); + train.navigation.ticksWaitingForSignal, + train.currentlyBackwards + ), updateTime), context.get().getSender()); }); context.get().setPacketHandled(true); } - public static record TrainData(UUID trainId, double speed, int ticksWaitingForSignal) { + public static class TrainData { private static final String NBT_TRAIN_ID = "Id"; private static final String NBT_SPEED = "Speed"; private static final String NBT_WAITING_FOR_SIGNAL = "WaitingForSignal"; + private static final String NBT_NAME = "Name"; + private static final String NBT_PREDICTIONS = "Predictions"; + private static final String NBT_TRAIN_DIRECTION = "Direction"; + + private final UUID trainId; + private final String trainName; + private final List predictions; + private final double speed; + private final int ticksWaitingForSignal; + private final boolean oppositeDirection; + + private final Cache> stopovers = new Cache<>(() -> { + List s = new ArrayList<>(); + if (predictions().size() >= 2) { + for (int i = 1; i < predictions().size() - 1; i++) { + s.add(predictions().get(i)); + } + } + return s; + }); + + public TrainData(UUID trainId, String trainName, List predictions, double speed, int ticksWaitingForSignal, boolean oppositeDirection) { + this.trainId = trainId; + this.trainName = trainName; + this.predictions = predictions; + this.speed = speed; + this.ticksWaitingForSignal = ticksWaitingForSignal; + this.oppositeDirection = oppositeDirection; + } + + public UUID trainId() { + return trainId; + } + + public String trainName() { + return trainName; + } + + public List predictions() { + return predictions; + } + + public double speed() { + return speed; + } + + public int ticksWaitingForSignal() { + return ticksWaitingForSignal; + } + + public List stopovers() { + return stopovers.get(); + } + + public boolean isOppositeDirection() { + return oppositeDirection; + } public CompoundTag toNbt() { CompoundTag nbt = new CompoundTag(); nbt.putUUID(NBT_TRAIN_ID, trainId); nbt.putDouble(NBT_SPEED, speed); nbt.putInt(NBT_WAITING_FOR_SIGNAL, ticksWaitingForSignal); + nbt.putString(NBT_NAME, trainName); + nbt.putBoolean(NBT_TRAIN_DIRECTION, oppositeDirection); + + ListTag list = new ListTag(); + list.addAll(predictions().stream().map(x -> x.toNbt()).toList()); + nbt.put(NBT_PREDICTIONS, list); return nbt; } public static TrainData fromNbt(CompoundTag nbt) { return new TrainData( nbt.getUUID(NBT_TRAIN_ID), + nbt.getString(NBT_NAME), + nbt.getList(NBT_PREDICTIONS, Tag.TAG_COMPOUND).stream().map(x -> SimpleDeparturePrediction.fromNbt(((CompoundTag)x))).toList(), nbt.getDouble(NBT_SPEED), - nbt.getInt(NBT_WAITING_FOR_SIGNAL) + nbt.getInt(NBT_WAITING_FOR_SIGNAL), + nbt.getBoolean(NBT_TRAIN_DIRECTION) ); } + + public Optional getNextStop() { + return predictions().size() > 0 ? Optional.of(predictions().get(0)) : Optional.empty(); + } + + public Optional getLastStop() { + return predictions().size() > 0 ? Optional.of(predictions().get(predictions().size() - 1)) : Optional.empty(); + } + + public static TrainData empty() { + MutableComponent text = Utils.translate("block.createrailwaysnavigator.advanced_display.ber.not_in_service"); + return new TrainData(Constants.ZERO_UUID, "CRN", List.of(new SimpleDeparturePrediction("", "", 0, text.getString(), "", Constants.ZERO_UUID, null, TrainExitSide.UNKNOWN)), 0, 0, false); + } + } @Override diff --git a/src/main/java/de/mrjulsen/crn/proxy/ClientInit.java b/src/main/java/de/mrjulsen/crn/proxy/ClientInit.java index 5aef8477..0d2c8932 100644 --- a/src/main/java/de/mrjulsen/crn/proxy/ClientInit.java +++ b/src/main/java/de/mrjulsen/crn/proxy/ClientInit.java @@ -1,10 +1,25 @@ package de.mrjulsen.crn.proxy; +import com.mojang.blaze3d.platform.NativeImage; + +import de.mrjulsen.crn.registry.ModDisplayTags; import de.mrjulsen.crn.util.ModGuiUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.resources.ResourceLocation; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; public class ClientInit { + + public static ResourceLocation blankTextureLocation; + + @SuppressWarnings("resource") public static void setup(final FMLClientSetupEvent event) { ModGuiUtils.init(); + ModDisplayTags.register(); + + NativeImage img = new NativeImage(1, 1, false); + img.setPixelRGBA(0, 0, 0xFFFFFFFF); + blankTextureLocation = Minecraft.getInstance().textureManager.register("blank", new DynamicTexture(img)); } } diff --git a/src/main/java/de/mrjulsen/crn/registry/ModBlockEntities.java b/src/main/java/de/mrjulsen/crn/registry/ModBlockEntities.java new file mode 100644 index 00000000..f8f50e8f --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/registry/ModBlockEntities.java @@ -0,0 +1,34 @@ +package de.mrjulsen.crn.registry; + +import com.tterrag.registrate.util.entry.BlockEntityEntry; + +import de.mrjulsen.crn.ModMain; +import de.mrjulsen.crn.block.be.AdvancedDisplayBlockEntity; +import de.mrjulsen.crn.block.be.TrainStationClockBlockEntity; +import de.mrjulsen.crn.client.ber.base.StaticBlockEntityRenderer; + +public class ModBlockEntities { + + public static final BlockEntityEntry ADVANCED_DISPLAY_BLOCK_ENTITY = ModMain.REGISTRATE + .blockEntity("advanced_display_block_entity", AdvancedDisplayBlockEntity::new) + .validBlocks( + ModBlocks.ADVANCED_DISPLAY, + ModBlocks.ADVANCED_DISPLAY_BLOCK, + ModBlocks.ADVANCED_DISPLAY_PANEL, + ModBlocks.ADVANCED_DISPLAY_SMALL + ) + .renderer(() -> StaticBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry TRAIN_STATION_CLOCK_BLOCK_ENTITY = ModMain.REGISTRATE + .blockEntity("train_station_clock_block_entity", TrainStationClockBlockEntity::new) + .validBlocks( + ModBlocks.TRAIN_STATION_CLOCK + ) + .renderer(() -> StaticBlockEntityRenderer::new) + .register(); + + + public static void register() { + } +} diff --git a/src/main/java/de/mrjulsen/crn/registry/ModBlocks.java b/src/main/java/de/mrjulsen/crn/registry/ModBlocks.java new file mode 100644 index 00000000..296dd4a4 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/registry/ModBlocks.java @@ -0,0 +1,120 @@ +package de.mrjulsen.crn.registry; + +import java.util.function.Supplier; + +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours; +import com.simibubi.create.foundation.block.connected.AllCTTypes; +import com.simibubi.create.foundation.block.connected.CTModel; +import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; +import com.simibubi.create.foundation.block.connected.CTSpriteShifter; +import com.simibubi.create.foundation.block.connected.CTType; +import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; +import com.simibubi.create.foundation.data.SharedProperties; +import com.simibubi.create.foundation.data.TagGen; +import com.simibubi.create.foundation.utility.RegisteredObjects; +import com.tterrag.registrate.util.entry.BlockEntry; +import com.tterrag.registrate.util.nullness.NonNullConsumer; + +import de.mrjulsen.crn.ModMain; +import de.mrjulsen.crn.block.AdvancedDisplayBlock; +import de.mrjulsen.crn.block.AdvancedDisplayBoardBlock; +import de.mrjulsen.crn.block.AdvancedDisplayPanelBlock; +import de.mrjulsen.crn.block.AdvancedDisplaySmallBlock; +import de.mrjulsen.crn.block.TrainStationClockBlock; +import de.mrjulsen.crn.block.connected.AdvancedDisplayCTBehaviour; +import de.mrjulsen.crn.block.connected.AdvancedDisplaySmallCTBehaviour; +import de.mrjulsen.crn.block.display.AdvancedDisplayTarget; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class ModBlocks { + + static { + ModMain.REGISTRATE.setCreativeTab(ModCreativeModeTab.MAIN_TAB); + } + + public static final CTSpriteShiftEntry CT_ADVANCED_DISPLAY_ALL = getCT(AllCTTypes.OMNIDIRECTIONAL, "advanced_display", "advanced_display"); + + public static final CTSpriteShiftEntry CT_ADVANCED_DISPLAY = getCT(AllCTTypes.OMNIDIRECTIONAL, "advanced_display", "advanced_display"); + public static final CTSpriteShiftEntry CT_HORIZONTAL_ADVANCED_DISPLAY = getCT(AllCTTypes.HORIZONTAL_KRYPPERS, "advanced_display", "advanced_display"); + + public static final CTSpriteShiftEntry CT_ADVANCED_DISPLAY_SMALL = getCT(AllCTTypes.OMNIDIRECTIONAL, "advanced_display_small", "advanced_display_small"); + public static final CTSpriteShiftEntry CT_HORIZONTAL_ADVANCED_DISPLAY_SMALL = getCT(AllCTTypes.HORIZONTAL_KRYPPERS, "advanced_display_small", "advanced_display_small"); + + public static final BlockEntry ADVANCED_DISPLAY_BLOCK = ModMain.REGISTRATE.block("advanced_display_block", AdvancedDisplayBlock::new) + .onRegister(connectedTextures(() -> new AdvancedDisplayCTBehaviour(CT_ADVANCED_DISPLAY_ALL))) + .initialProperties(SharedProperties::softMetal) + .transform(TagGen.pickaxeOnly()) + .onRegister(AllDisplayBehaviours.assignDataBehaviour(new AdvancedDisplayTarget())) + .item() + .tab(ModCreativeModeTab.MAIN_TAB.getKey()) + .build() + .register(); + + public static final BlockEntry ADVANCED_DISPLAY = ModMain.REGISTRATE.block("advanced_display", AdvancedDisplayBoardBlock::new) + .onRegister(connectedTextures(() -> new AdvancedDisplayCTBehaviour(CT_ADVANCED_DISPLAY))) + .initialProperties(SharedProperties::softMetal) + .transform(TagGen.pickaxeOnly()) + .onRegister(AllDisplayBehaviours.assignDataBehaviour(new AdvancedDisplayTarget())) + .item() + .tab(ModCreativeModeTab.MAIN_TAB.getKey()) + .build() + .register(); + + public static final BlockEntry ADVANCED_DISPLAY_SMALL = ModMain.REGISTRATE.block("advanced_display_small", AdvancedDisplaySmallBlock::new) + .onRegister(connectedTextures(() -> new AdvancedDisplaySmallCTBehaviour(CT_HORIZONTAL_ADVANCED_DISPLAY_SMALL, CT_ADVANCED_DISPLAY_SMALL))) + .initialProperties(SharedProperties::softMetal) + .transform(TagGen.pickaxeOnly()) + .onRegister(AllDisplayBehaviours.assignDataBehaviour(new AdvancedDisplayTarget())) + .item() + .tab(ModCreativeModeTab.MAIN_TAB.getKey()) + .build() + .register(); + + public static final BlockEntry ADVANCED_DISPLAY_PANEL = ModMain.REGISTRATE.block("advanced_display_panel", AdvancedDisplayPanelBlock::new) + .onRegister(connectedTextures(() -> new AdvancedDisplayCTBehaviour(CT_ADVANCED_DISPLAY))) + .initialProperties(SharedProperties::softMetal) + .transform(TagGen.pickaxeOnly()) + .onRegister(AllDisplayBehaviours.assignDataBehaviour(new AdvancedDisplayTarget())) + .item() + .tab(ModCreativeModeTab.MAIN_TAB.getKey()) + .build() + .register(); + + public static final BlockEntry TRAIN_STATION_CLOCK = ModMain.REGISTRATE.block("train_station_clock", TrainStationClockBlock::new) + .initialProperties(SharedProperties::softMetal) + .transform(TagGen.pickaxeOnly()) + .item() + .tab(ModCreativeModeTab.MAIN_TAB.getKey()) + .build() + .register(); + + + public static NonNullConsumer connectedTextures( + Supplier behavior) { + return entry -> onClient(() -> () -> registerCTBehviour(entry, behavior)); + } + + protected static void onClient(Supplier toRun) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, toRun); + } + + @OnlyIn(Dist.CLIENT) + private static void registerCTBehviour(Block entry, Supplier behaviorSupplier) { + ConnectedTextureBehaviour behavior = behaviorSupplier.get(); + CreateClient.MODEL_SWAPPER.getCustomBlockModels() + .register(RegisteredObjects.getKeyOrThrow(entry), model -> new CTModel(model, behavior)); + } + + private static CTSpriteShiftEntry getCT(CTType type, String blockTextureName, String connectedTextureName) { + return CTSpriteShifter.getCT(type, new ResourceLocation(ModMain.MOD_ID, "block/" + blockTextureName), + new ResourceLocation(ModMain.MOD_ID, "block/" + connectedTextureName + "_connected")); + } + + public static void register() { + } +} diff --git a/src/main/java/de/mrjulsen/crn/item/creativemodetab/ModCreativeModeTab.java b/src/main/java/de/mrjulsen/crn/registry/ModCreativeModeTab.java similarity index 74% rename from src/main/java/de/mrjulsen/crn/item/creativemodetab/ModCreativeModeTab.java rename to src/main/java/de/mrjulsen/crn/registry/ModCreativeModeTab.java index 326ec01f..3141ee5c 100644 --- a/src/main/java/de/mrjulsen/crn/item/creativemodetab/ModCreativeModeTab.java +++ b/src/main/java/de/mrjulsen/crn/registry/ModCreativeModeTab.java @@ -1,13 +1,11 @@ -package de.mrjulsen.crn.item.creativemodetab; +package de.mrjulsen.crn.registry; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; import de.mrjulsen.crn.ModMain; -import de.mrjulsen.crn.item.ModItems; import de.mrjulsen.mcdragonlib.utils.Utils; import net.minecraft.core.registries.Registries; import net.minecraft.world.item.CreativeModeTab; @@ -20,12 +18,12 @@ @Mod.EventBusSubscriber(modid = ModMain.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public class ModCreativeModeTab { - - private static final Map>> CREATIVE_MODE_TAB_REGISTRY = new HashMap<>(); + + private static final Map>> CREATIVE_MODE_TAB_REGISTRY = new HashMap<>(); public static final DeferredRegister CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, ModMain.MOD_ID); - public static final RegistryObject MAIN_TAB = registerTab("createrailwaysnavigatortab", () -> CreativeModeTab.builder() + public static final RegistryObject MAIN_TAB = registerTab("crn_tab", () -> CreativeModeTab.builder() .icon(() -> new ItemStack(ModItems.NAVIGATOR.get())) .title(Utils.translate("itemGroup.createrailwaysnavigatortab")) .displayItems((pParameters, pOutput) -> { @@ -46,14 +44,7 @@ public static void register(IEventBus event) { CREATIVE_MODE_TABS.register(event); } - public static void put(ModTab tab, RegistryObject item) { - if (!CREATIVE_MODE_TAB_REGISTRY.containsKey(tab)) { - CREATIVE_MODE_TAB_REGISTRY.put(tab, new ArrayList<>()); - } - CREATIVE_MODE_TAB_REGISTRY.get(tab).add(item); - } - public static enum ModTab { MAIN; } -} +} \ No newline at end of file diff --git a/src/main/java/de/mrjulsen/crn/registry/ModDisplayTags.java b/src/main/java/de/mrjulsen/crn/registry/ModDisplayTags.java new file mode 100644 index 00000000..37dfa462 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/registry/ModDisplayTags.java @@ -0,0 +1,15 @@ +package de.mrjulsen.crn.registry; + +import com.simibubi.create.foundation.ponder.PonderRegistry; +import com.simibubi.create.infrastructure.ponder.AllPonderTags; + +public class ModDisplayTags { + public static void register() { + PonderRegistry.TAGS.forTag(AllPonderTags.DISPLAY_TARGETS) + .add(ModBlocks.ADVANCED_DISPLAY) + .add(ModBlocks.ADVANCED_DISPLAY_BLOCK) + .add(ModBlocks.ADVANCED_DISPLAY_PANEL) + .add(ModBlocks.ADVANCED_DISPLAY_SMALL) + ; + } +} diff --git a/src/main/java/de/mrjulsen/crn/registry/ModExtras.java b/src/main/java/de/mrjulsen/crn/registry/ModExtras.java new file mode 100644 index 00000000..90562ccd --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/registry/ModExtras.java @@ -0,0 +1,33 @@ +package de.mrjulsen.crn.registry; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.Create; +import com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours; + +import de.mrjulsen.crn.block.display.AdvancedDisplaySource; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.block.Block; + +public class ModExtras { + + public static boolean registeredTrackStationSource = false; + + public static void register() { + Block maybeRegistered = null; + try { + maybeRegistered = AllBlocks.TRACK_STATION.get(); + } catch (NullPointerException ignored) { + maybeRegistered = null; + } + Create.REGISTRATE.addRegisterCallback("track_station", Registries.BLOCK, ModExtras::addSignalSource); + if (maybeRegistered != null) { + addSignalSource(maybeRegistered); + } + } + + public static void addSignalSource(Block block) { + if (registeredTrackStationSource) return; + AllDisplayBehaviours.assignDataBehaviour(new AdvancedDisplaySource()).accept(block); + registeredTrackStationSource = true; + } +} diff --git a/src/main/java/de/mrjulsen/crn/registry/ModItems.java b/src/main/java/de/mrjulsen/crn/registry/ModItems.java new file mode 100644 index 00000000..ef8cfb0a --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/registry/ModItems.java @@ -0,0 +1,21 @@ +package de.mrjulsen.crn.registry; + +import com.tterrag.registrate.util.entry.ItemEntry; + +import de.mrjulsen.crn.ModMain; +import de.mrjulsen.crn.item.NavigatorItem; + +public class ModItems { + + static { + ModMain.REGISTRATE.setCreativeTab(ModCreativeModeTab.MAIN_TAB); + } + + public static final ItemEntry NAVIGATOR = ModMain.REGISTRATE.item("navigator", NavigatorItem::new) + .properties(p -> p.stacksTo(1)) + .tab(ModCreativeModeTab.MAIN_TAB.getKey()) + .register(); + + public static void register() { + } +} diff --git a/src/main/java/de/mrjulsen/crn/util/BERUtils.java b/src/main/java/de/mrjulsen/crn/util/BERUtils.java new file mode 100644 index 00000000..b52fe504 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/util/BERUtils.java @@ -0,0 +1,60 @@ +package de.mrjulsen.crn.util; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import de.mrjulsen.crn.proxy.ClientInit; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public class BERUtils { + + public void initRenderEngine() { + RenderSystem.enableBlend(); + RenderSystem.enableDepthTest(); + RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + } + + public void setTint(int r, int g, int b, int a) { + RenderSystem.setShaderColor(r, g, b, a); + } + + public void renderTexture(ResourceLocation texture, MultiBufferSource bufferSource, BlockEntity blockEntity, PoseStack poseStack, float x, float y, float z, float w, float h, float u0, float v0, float u1, float v1, Direction facing, int tint, int light) { + VertexConsumer vertexconsumer = bufferSource.getBuffer(RenderType.text(texture)); + byte[] color = ModUtils.decodeColor(tint); + addQuadSide(blockEntity, blockEntity.getBlockState(), facing, vertexconsumer, poseStack, + x, y, z, + x + w, y + h, z, + u0, v0, + u1, v1, + (float)color[1] / 255.0F, (float)color[2] / 255.0F, (float)color[3] / 255.0F, (float)color[0] / 255.0F, + light + ); + } + + public static void addVert(VertexConsumer builder, PoseStack pPoseStack, float x, float y, float z, float u, float v, float r, float g, float b, float a, int lu, int lv) { + builder.vertex(pPoseStack.last().pose(), x, y, z).color(r, g, b, a).uv(u, v).uv2(lu, lv).overlayCoords(OverlayTexture.NO_OVERLAY).normal(pPoseStack.last().normal(), 0, 0, 1).endVertex(); + } + + private static void renderWithoutAO(VertexConsumer builder, PoseStack pPoseStack, float x0, float y0, float z0, float x1, float y1, float z1, float u0, float v0, float u1, float v1, float r, float g, float b, float a, int packedLight) { + addVert(builder, pPoseStack, x0, y0, z0, u0, v0, r, g, b, a, packedLight & 0xFFFF, (packedLight >> 16) & 0xFFFF); + addVert(builder, pPoseStack, x0, y1, z0, u0, v1, r, g, b, a, packedLight & 0xFFFF, (packedLight >> 16) & 0xFFFF); + addVert(builder, pPoseStack, x1, y1, z1, u1, v1, r, g, b, a, packedLight & 0xFFFF, (packedLight >> 16) & 0xFFFF); + addVert(builder, pPoseStack, x1, y0, z1, u1, v0, r, g, b, a, packedLight & 0xFFFF, (packedLight >> 16) & 0xFFFF); + } + + @SuppressWarnings("resources") + public static void addQuadSide(BlockEntity be, BlockState state, Direction direction, VertexConsumer builder, PoseStack pPoseStack, float x0, float y0, float z0, float x1, float y1, float z1, float u0, float v0, float u1, float v1, float r, float g, float b, float a, int packedLight) { + renderWithoutAO(builder, pPoseStack, x0, y0, z0, x1, y1, z1, u0, v0, u1, v1, r, g, b, a, packedLight); + } + + public void fillColor(MultiBufferSource pBufferSource, BlockEntity blockEntity, int color, PoseStack poseStack, float x, float y, float z, float w, float h, Direction facing, int light) { + renderTexture(ClientInit.blankTextureLocation, pBufferSource, blockEntity, poseStack, x, y, z, w, h, 0, 0, 1, 1, facing, color, light); + } +} diff --git a/src/main/java/de/mrjulsen/crn/util/Cache.java b/src/main/java/de/mrjulsen/crn/util/Cache.java new file mode 100644 index 00000000..f4022d1e --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/util/Cache.java @@ -0,0 +1,29 @@ +package de.mrjulsen.crn.util; + +import java.util.Optional; +import java.util.function.Supplier; + +public class Cache { + private T obj = null; + private Supplier provider; + + public Cache(Supplier provider) { + this.provider = provider; + } + + public boolean isCached() { + return this.obj != null; + } + + public T get() { + return !this.isCached() ? this.obj = this.provider.get() : this.obj; + } + + public Optional getIfAvailable() { + return !this.isCached() ? Optional.empty() : Optional.of(this.obj); + } + + public void clear() { + this.obj = null; + } +} \ No newline at end of file diff --git a/src/main/java/de/mrjulsen/crn/util/DataCache.java b/src/main/java/de/mrjulsen/crn/util/DataCache.java new file mode 100644 index 00000000..cee46ea7 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/util/DataCache.java @@ -0,0 +1,29 @@ +package de.mrjulsen.crn.util; + +import java.util.Optional; +import java.util.function.Function; + +public class DataCache { + private T obj = null; + private Function provider; + + public DataCache(Function provider) { + this.provider = provider; + } + + public boolean isCached() { + return this.obj != null; + } + + public T get(D data) { + return !this.isCached() ? this.obj = this.provider.apply(data) : this.obj; + } + + public Optional getIfAvailable() { + return !this.isCached() ? Optional.empty() : Optional.of(this.obj); + } + + public void clear() { + this.obj = null; + } +} \ No newline at end of file diff --git a/src/main/java/de/mrjulsen/crn/util/FontUtils.java b/src/main/java/de/mrjulsen/crn/util/FontUtils.java new file mode 100644 index 00000000..d52ecb41 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/util/FontUtils.java @@ -0,0 +1,74 @@ +package de.mrjulsen.crn.util; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; +import com.mojang.blaze3d.font.GlyphInfo; + +import de.mrjulsen.crn.mixin.BakedGlyphAccessor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.font.FontSet; +import net.minecraft.client.gui.font.glyphs.BakedGlyph; +import net.minecraft.resources.ResourceLocation; + +public class FontUtils { + public final Font font; + public final FontSet fontSet; + + protected static record UVData(float u0, float v0, float u1, float v1) {} + protected static final Map> uvStack = new HashMap<>(); + + @SuppressWarnings("resource") + public FontUtils(ResourceLocation fontStyle) { + this.font = Minecraft.getInstance().font; + this.fontSet = this.font.getFontSet(fontStyle); + } + + public BakedGlyphAccessor getGlyphAccessor(int charCode) { + return (BakedGlyphAccessor)getGlyph(charCode); + } + + public void pushUV(int charCode) { + BakedGlyphAccessor glyph = getGlyphAccessor(charCode); + pushUV(charCode, glyph.getU0(), glyph.getV0(), glyph.getU1(), glyph.getV1()); + } + + protected void pushUV(int charCode, float u0, float v0, float u1, float v1) { + if (!uvStack.containsKey(charCode)) { + uvStack.put(charCode, new ArrayDeque<>()); + } + uvStack.get(charCode).addLast(new UVData(u0, v0, u1, v1)); + } + + public boolean popUV(int charCode) { + if (!uvStack.containsKey(charCode)) { + return false; + } + + UVData data = uvStack.get(charCode).pollLast(); + if (uvStack.get(charCode).isEmpty()) { + uvStack.remove(charCode); + } + + BakedGlyphAccessor glyph = getGlyphAccessor(charCode); + glyph.setU0(data.u0()); + glyph.setV0(data.v0()); + glyph.setU1(data.u1()); + glyph.setV1(data.v1()); + return true; + } + + public GlyphInfo getGlyphInfo(int charCode) { + return fontSet.getGlyphInfo(charCode, false); + } + + public BakedGlyph getGlyph(int charCode) { + return fontSet.getGlyph(charCode); + } + + public void reset() { + uvStack.clear(); + } +} diff --git a/src/main/java/de/mrjulsen/crn/util/MathUtils.java b/src/main/java/de/mrjulsen/crn/util/MathUtils.java new file mode 100644 index 00000000..c6c9174b --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/util/MathUtils.java @@ -0,0 +1,9 @@ +package de.mrjulsen.crn.util; + +import net.minecraft.world.phys.Vec3; + +public class MathUtils { + public static double getVectorAngle(Vec3 vec) { + return Math.round(Math.atan2(vec.x(), -vec.z()) * (180.0 / Math.PI)); + } +} diff --git a/src/main/java/de/mrjulsen/crn/util/ModGuiUtils.java b/src/main/java/de/mrjulsen/crn/util/ModGuiUtils.java index d7f07fd1..fab6497a 100644 --- a/src/main/java/de/mrjulsen/crn/util/ModGuiUtils.java +++ b/src/main/java/de/mrjulsen/crn/util/ModGuiUtils.java @@ -131,9 +131,9 @@ public static int lightenColor(int color, float factor) { int green = (color >> 8) & 0xFF; int blue = color & 0xFF; - red = (int) ((red * (1 - factor)) + (255 * factor)); - green = (int) ((green * (1 - factor)) + (255 * factor)); - blue = (int) ((blue * (1 - factor)) + (255 * factor)); + red = (int) ((red * (1 - factor)) + (factor < 0 ? 0 : (255 * factor))); + green = (int) ((green * (1 - factor)) + (factor < 0 ? 0 : (255 * factor))); + blue = (int) ((blue * (1 - factor)) + (factor < 0 ? 0 : (255 * factor))); red = Math.min(255, Math.max(0, red)); green = Math.min(255, Math.max(0, green)); @@ -141,4 +141,14 @@ public static int lightenColor(int color, float factor) { return 0xFF000000 | (red << 16) | (green << 8) | blue; } + + public static int darkenColor(int color, float darkenFactor) { + int red = (color >> 16) & 0xFF; + int green = (color >> 8) & 0xFF; + int blue = color & 0xFF; + int r = (int) (red * (1 - darkenFactor)); + int g = (int) (green * (1 - darkenFactor)); + int b = (int) (blue * (1 - darkenFactor)); + return 0xFF000000 | (r << 16) | (g << 8) | b; + } } diff --git a/src/main/java/de/mrjulsen/crn/util/ModUtils.java b/src/main/java/de/mrjulsen/crn/util/ModUtils.java new file mode 100644 index 00000000..b1491a97 --- /dev/null +++ b/src/main/java/de/mrjulsen/crn/util/ModUtils.java @@ -0,0 +1,57 @@ +package de.mrjulsen.crn.util; + +import java.util.Collection; +import java.util.Iterator; +import java.util.function.BiPredicate; + +import de.mrjulsen.mcdragonlib.utils.Utils; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; + +public class ModUtils { + + private static final Component TEXT_CONCAT = Utils.text(" *** "); + + public static Component concat(Component... components) { + if (components.length <= 0) { + return Utils.emptyText(); + } + + MutableComponent c = components[0].copy(); + for (int i = 1; i < components.length; i++) { + c.append(TEXT_CONCAT); + c.append(components[i]); + } + return c; + } + + public static boolean compareCollections(Collection a, Collection b, BiPredicate compare) { + if (a.size() != b.size()) { + return false; + } + + Iterator i = a.iterator(); + Iterator k = b.iterator(); + + while (i.hasNext() && k.hasNext()) { + if (!compare.test(i.next(), k.next())) { + return false; + } + } + + return true; + } + + public static float clockHandDegrees(long time, int divisor) { + return 360.0F / divisor * (time % divisor); + } + + public static byte[] decodeColor(int color) { + byte a = (byte)((color >> 24) & 0xFF); + byte r = (byte)((color >> 16) & 0xFF); + byte g = (byte)((color >> 8) & 0xFF); + byte b = (byte)(color & 0xFF); + + return new byte[] {a, r, g, b}; + } +} diff --git a/src/main/java/de/mrjulsen/crn/util/TrainUtils.java b/src/main/java/de/mrjulsen/crn/util/TrainUtils.java index d10df61b..21cbf16b 100644 --- a/src/main/java/de/mrjulsen/crn/util/TrainUtils.java +++ b/src/main/java/de/mrjulsen/crn/util/TrainUtils.java @@ -1,5 +1,6 @@ package de.mrjulsen.crn.util; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -7,18 +8,22 @@ import java.util.Optional; import java.util.Set; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; import com.simibubi.create.Create; +import com.simibubi.create.content.decoration.slidingDoor.DoorControlBehaviour; import com.simibubi.create.content.trains.GlobalRailwayManager; import com.simibubi.create.content.trains.display.GlobalTrainDisplayData; import com.simibubi.create.content.trains.display.GlobalTrainDisplayData.TrainDeparturePrediction; import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; import com.simibubi.create.content.trains.station.GlobalStation; - +import com.simibubi.create.content.trains.station.StationBlockEntity; import de.mrjulsen.crn.data.DeparturePrediction; import de.mrjulsen.crn.data.GlobalSettingsManager; import de.mrjulsen.crn.data.NearestTrackStationResult; @@ -27,8 +32,12 @@ import de.mrjulsen.crn.data.SimulatedTrainSchedule; import de.mrjulsen.crn.data.TrainStationAlias; import de.mrjulsen.crn.data.TrainStop; +import de.mrjulsen.crn.data.DeparturePrediction.TrainExitSide; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; public class TrainUtils { @@ -70,19 +79,30 @@ public static void getMappedDeparturePredictions(Map getTrainDeparturePredictions(UUID trainId) { - return Gott().values().stream().flatMap(x -> x.stream()).filter(x -> x.train.id.equals(trainId)).map(x -> new DeparturePrediction(x)).toList(); - } - + public static Collection getTrainDeparturePredictions(UUID trainId, Level level) { + final Map> edges = level != null ? getAllEdgesMapped() : new HashMap<>(); + final Map> stationsByName = level != null ? getAllStations().stream().collect(Collectors.groupingBy(x -> x.name, Collectors.toSet())) : new HashMap<>(); + Collection preds = Gott().values().stream().flatMap(x -> x.stream()).filter(x -> x.train.id.equals(trainId)).map(x -> { + DeparturePrediction prediction = new DeparturePrediction(x); + if (stationsByName.containsKey(prediction.getStationName())) { + Set exitSides = stationsByName.get(prediction.getStationName()).stream().filter(a -> edges.containsKey(a.id)).map(a -> getTrainStationExit(a, Direction.fromYRot(angleOn(a, edges.get(a.id).stream().findFirst().get())), level)).collect(Collectors.toSet()); + if (exitSides.size() == 1) { + prediction.setExit(exitSides.stream().findFirst().get()); + } + } + return prediction; + }).toList(); + return preds; + } - public static Collection getTrainStopsSorted(UUID trainId) { - return getTrainDeparturePredictions(trainId).parallelStream().map(x -> new TrainStop(x.getNextStop(), x)).sorted(Comparator.comparingInt(x -> x.getPrediction().getTicks())).toList(); + public static Collection getTrainStopsSorted(UUID trainId, Level level) { + return getTrainDeparturePredictions(trainId, level).stream().map(x -> new TrainStop(x.getNextStop(), x)).filter(x -> !GlobalSettingsManager.getInstance().getSettingsData().isBlacklisted(x.getStationAlias())).sorted(Comparator.comparingInt(x -> x.getPrediction().getTicks())).toList(); } - public static Set getConnectionsAt(String stationName, UUID currentTrainId, int ticksToNextStop) { + public static List getConnectionsAt(String stationName, UUID currentTrainId, int ticksToNextStop) { TrainStationAlias alias = GlobalSettingsManager.getInstance().getSettingsData().getAliasFor(stationName); - SimpleTrainSchedule ownSchedule = SimpleTrainSchedule.of(getTrainStopsSorted(currentTrainId)); + SimpleTrainSchedule ownSchedule = SimpleTrainSchedule.of(getTrainStopsSorted(currentTrainId, null)); GlobalTrainDisplayData.refresh(); List excludedSchedules = new ArrayList<>(); @@ -92,7 +112,7 @@ public static Set getConnectionsAt(String stationName, UU return Gott().entrySet().stream().filter(x -> alias.contains(x.getKey())).map(x -> x.getValue()) .flatMap(x -> x.parallelStream().map(y -> new DeparturePrediction(y))) .peek(x -> { - SimpleTrainSchedule schedule = SimpleTrainSchedule.of(getTrainStopsSorted(x.getTrain().id)); + SimpleTrainSchedule schedule = SimpleTrainSchedule.of(getTrainStopsSorted(x.getTrain().id, null)); scheduleByPrediction.put(x, schedule); simulatedScheduleByPrediction.put(x, schedule.simulate(x.getTrain(), ticksToNextStop, alias)); }) @@ -106,9 +126,9 @@ public static Set getConnectionsAt(String stationName, UU } boolean b = !x.getTrain().id.equals(currentTrainId) && - !schedule.equals(ownSchedule) && TrainUtils.isTrainValid(x.getTrain()) && - !GlobalSettingsManager.getInstance().getSettingsData().isTrainBlacklisted(x.getTrain()); + !GlobalSettingsManager.getInstance().getSettingsData().isTrainBlacklisted(x.getTrain()) && + !schedule.equals(ownSchedule); if (b) { excludedSchedules.add(directionalSchedule); @@ -124,9 +144,9 @@ public static Set getConnectionsAt(String stationName, UU x.getTrain().icon.getId(), sched.getSimulationData().simulationTime() + sched.getSimulationData().simulationCorrection(), firstStop.isPresent() ? firstStop.get().getPrediction().getScheduleTitle() : x.getScheduleTitle(), - firstStop.isPresent() ? firstStop.get().getStationAlias().getInfoForStation(x.getNextStopStation()) : x.getInfo() + firstStop.isPresent() ? firstStop.get().getStationAlias().getInfoForStation(firstStop.get().getPrediction().getStationName()) : x.getInfo() ); - }).sorted(Comparator.comparingInt(x -> x.ticks())).collect(Collectors.toSet()); + }).sorted(Comparator.comparingInt(x -> x.ticks())).toList(); } @@ -141,7 +161,7 @@ public static boolean GottKnows(String station) { * A list of all stations in the world. * @return a list containing all track stations. */ - public static Collection getAllStations() { + public static Collection getAllStations() { final Collection stations = new ArrayList<>(); RAILWAY_MANAGER.trackNetworks.forEach((uuid, graph) -> { Collection foundStations = graph.getPoints(EdgePointType.STATION); @@ -150,10 +170,36 @@ public static Collection getAllStations() { return stations; } + public static Collection getAllEdges() { + final Set edges = new HashSet<>(); + RAILWAY_MANAGER.trackNetworks.forEach((uuid, graph) -> { + edges.addAll(graph.getNodes().stream().map(x -> graph.locateNode(x)).flatMap(x -> graph.getConnectionsFrom(x).values().stream()).collect(Collectors.toSet())); + }); + return edges; + } + + public static Map> getAllEdgesMapped() { + final Map> edges = new HashMap<>(); + RAILWAY_MANAGER.trackNetworks.forEach((uuid, graph) -> { + edges.putAll(graph.getNodes().stream() + .map(x -> graph.locateNode(x)) + .flatMap(x -> graph.getConnectionsFrom(x).values().stream()) + .distinct() + .flatMap(edge -> edge.getEdgeData().getPoints().stream().map(point -> new AbstractMap.SimpleEntry<>(point.id, edge))) + .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toSet()))) + ); + }); + return edges; + } + + public static Optional getEdgeForStation(GlobalStation station) { + return getAllEdges().stream().filter(x -> x.getEdgeData().getPoints().stream().anyMatch(y -> y.equals(station))).findFirst(); + } + public static NearestTrackStationResult getNearestTrackStation(Level level, Vec3i pos) { Optional station = getAllStations().stream().filter(x -> GottKnows(x.name) && - x.getBlockEntityDimension().equals(level.dimension()) && + x.getBlockEntityDimension().equals(level.dimension()) && !GlobalSettingsManager.getInstance().getSettingsData().isBlacklisted(x.name) ).min((a, b) -> Double.compare(a.getBlockEntityPos().distSqr(pos), b.getBlockEntityPos().distSqr(pos))); @@ -161,6 +207,68 @@ public static NearestTrackStationResult getNearestTrackStation(Level level, Vec3 return new NearestTrackStationResult(station, distance); } + public static double getStationAngle(GlobalStation station) { + return angleOn(station, getEdgeForStation(station).get()); + } + + public static Direction getStationDirection(GlobalStation station) { + return Direction.fromYRot(getStationAngle(station)); + } + + public static double angleOn(TrackEdgePoint point, TrackEdge edge) { + double basePos = point.isPrimary(edge.node1) ? edge.getLength() - point.position : point.position; + Vec3 vec = edge.getDirectionAt(basePos); + return point.isPrimary(edge.node1) ? MathUtils.getVectorAngle(vec) : MathUtils.getVectorAngle(vec.reverse()); + } + + public static DoorControlBehaviour getTrainStationDoorControl(GlobalStation station, Level level) { + BlockPos stationPos = station.getBlockEntityPos(); + if (level == null || !level.isLoaded(stationPos)) { + return null; + } + if (level.getBlockEntity(stationPos) instanceof StationBlockEntity be) { + return be.doorControls; + } + return null; + } + + /** + * + * @param station + * @param server + * @return 1 = right, -1 = left, 0 = unknown + */ + public static TrainExitSide getTrainStationExitDirection(GlobalStation station, Level level) { + DoorControlBehaviour dcb = getTrainStationDoorControl(station, level); + if (dcb == null) { + return TrainExitSide.UNKNOWN; + } + Direction stationDirection = getStationDirection(station); + + if (dcb.mode.matches(stationDirection.getClockWise())) { + return TrainExitSide.RIGHT; + } else if (dcb.mode.matches(stationDirection.getCounterClockWise())) { + return TrainExitSide.LEFT; + } + return TrainExitSide.UNKNOWN; + } + + public static TrainExitSide getTrainStationExit(GlobalStation station, Direction stationDirection, Level level) { + DoorControlBehaviour dcb = getTrainStationDoorControl(station, level); + if (dcb == null) { + return TrainExitSide.UNKNOWN; + } + + if (dcb.mode.matches(stationDirection.getClockWise())) { + return TrainExitSide.RIGHT; + } else if (dcb.mode.matches(stationDirection.getCounterClockWise())) { + return TrainExitSide.LEFT; + } + return TrainExitSide.UNKNOWN; + } + + + /** * A list of all trains in the world. * @return a list containing all trains. diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index e69de29b..32fa0746 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,7 @@ +public net.minecraft.client.renderer.block.ModelBlockRenderer$AmbientOcclusionFace +public net.minecraft.client.renderer.block.ModelBlockRenderer$AmbientOcclusionFace f_111149_ # brightness +public net.minecraft.client.renderer.block.ModelBlockRenderer$AmbientOcclusionFace f_111150_ # lightmap + +public net.minecraft.client.gui.chat.NarratorChatListener f_93313_ # narrator +public net.minecraft.client.gui.Font m_92863_(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/gui/font/FontSet; # getFontSet +public net.minecraft.client.gui.Font$StringRenderOutput \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display.json b/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display.json new file mode 100644 index 00000000..b7047553 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display.json @@ -0,0 +1,51 @@ +{ + "variants": { + "facing=north,side=front": { + "model": "createrailwaysnavigator:block/advanced_display" + }, + "facing=east,side=front": { + "model": "createrailwaysnavigator:block/advanced_display", + "y": 90 + }, + "facing=south,side=front": { + "model": "createrailwaysnavigator:block/advanced_display", + "y": 180 + }, + "facing=west,side=front": { + "model": "createrailwaysnavigator:block/advanced_display", + "y": 270 + }, + + "facing=north,side=back": { + "model": "createrailwaysnavigator:block/advanced_display", + "y": 180 + }, + "facing=east,side=back": { + "model": "createrailwaysnavigator:block/advanced_display", + "y": 270 + }, + "facing=south,side=back": { + "model": "createrailwaysnavigator:block/advanced_display" + }, + "facing=west,side=back": { + "model": "createrailwaysnavigator:block/advanced_display", + "y": 90 + }, + + "facing=north,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_double" + }, + "facing=east,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_double", + "y": 90 + }, + "facing=south,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_double", + "y": 180 + }, + "facing=west,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_double", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display_block.json b/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display_block.json new file mode 100644 index 00000000..42503136 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display_block.json @@ -0,0 +1,51 @@ +{ + "variants": { + "facing=north,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_block" + }, + "facing=east,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_block", + "y": 90 + }, + "facing=south,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_block", + "y": 180 + }, + "facing=west,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_block", + "y": 270 + }, + + "facing=north,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_block", + "y": 180 + }, + "facing=east,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_block", + "y": 270 + }, + "facing=south,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_block" + }, + "facing=west,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_block", + "y": 90 + }, + + "facing=north,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_block_double" + }, + "facing=east,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_block_double", + "y": 90 + }, + "facing=south,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_block_double", + "y": 180 + }, + "facing=west,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_block_double", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display_panel.json b/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display_panel.json new file mode 100644 index 00000000..0c375fcd --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display_panel.json @@ -0,0 +1,51 @@ +{ + "variants": { + "facing=north,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_panel" + }, + "facing=east,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_panel", + "y": 90 + }, + "facing=south,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_panel", + "y": 180 + }, + "facing=west,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_panel", + "y": 270 + }, + + "facing=north,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_panel_back" + }, + "facing=east,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_panel_back", + "y": 90 + }, + "facing=south,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_panel_back", + "y": 180 + }, + "facing=west,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_panel_back", + "y": 270 + }, + + "facing=north,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_panel_double" + }, + "facing=east,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_panel_double", + "y": 90 + }, + "facing=south,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_panel_double", + "y": 180 + }, + "facing=west,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_panel_double", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display_small.json b/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display_small.json new file mode 100644 index 00000000..b58364ce --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/blockstates/advanced_display_small.json @@ -0,0 +1,99 @@ +{ + "variants": { + "half=bottom,facing=north,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_small" + }, + "half=bottom,facing=east,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_small", + "y": 90 + }, + "half=bottom,facing=south,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_small", + "y": 180 + }, + "half=bottom,facing=west,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_small", + "y": 270 + }, + + "half=top,facing=north,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_small_top" + }, + "half=top,facing=east,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_small_top", + "y": 90 + }, + "half=top,facing=south,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_small_top", + "y": 180 + }, + "half=top,facing=west,side=front": { + "model": "createrailwaysnavigator:block/advanced_display_small_top", + "y": 270 + }, + + "half=bottom,facing=north,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_small_back" + }, + "half=bottom,facing=east,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_small_back", + "y": 90 + }, + "half=bottom,facing=south,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_small_back", + "y": 180 + }, + "half=bottom,facing=west,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_small_back", + "y": 270 + }, + + "half=top,facing=north,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_small_top_back" + }, + "half=top,facing=east,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_small_top_back", + "y": 90 + }, + "half=top,facing=south,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_small_top_back", + "y": 180 + }, + "half=top,facing=west,side=back": { + "model": "createrailwaysnavigator:block/advanced_display_small_top_back", + "y": 270 + }, + + "half=bottom,facing=north,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_small_double" + }, + "half=bottom,facing=east,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_small_double", + "y": 90 + }, + "half=bottom,facing=south,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_small_double", + "y": 180 + }, + "half=bottom,facing=west,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_small_double", + "y": 270 + }, + + "half=top,facing=north,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_small_top_double" + }, + "half=top,facing=east,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_small_top_double", + "y": 90 + }, + "half=top,facing=south,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_small_top_double", + "y": 180 + }, + "half=top,facing=west,side=both": { + "model": "createrailwaysnavigator:block/advanced_display_small_top_double", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/blockstates/train_station_clock.json b/src/main/resources/assets/createrailwaysnavigator/blockstates/train_station_clock.json new file mode 100644 index 00000000..81088b7d --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/blockstates/train_station_clock.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=north": { + "model": "createrailwaysnavigator:block/train_station_clock" + }, + "facing=east": { + "model": "createrailwaysnavigator:block/train_station_clock", + "y": 90 + }, + "facing=south": { + "model": "createrailwaysnavigator:block/train_station_clock", + "y": 180 + }, + "facing=west": { + "model": "createrailwaysnavigator:block/train_station_clock", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/lang/de_de.json b/src/main/resources/assets/createrailwaysnavigator/lang/de_de.json index 6fbf071f..b0ac96ba 100644 --- a/src/main/resources/assets/createrailwaysnavigator/lang/de_de.json +++ b/src/main/resources/assets/createrailwaysnavigator/lang/de_de.json @@ -1,12 +1,33 @@ { - "advancement.createrailwaysnavigator.root": "Sänk ju for träweling", - "advancement.createrailwaysnavigator.root.description": "Stelle einen Navigator her, um Zugverbindungen zwischen zwei verschiedenen Bahnhöfen zu finden.", + "advancement.createrailwaysnavigator.navigator": "Sänk ju for träweling", + "advancement.createrailwaysnavigator.navigator.description": "Stelle einen Navigator her, um Zugverbindungen zwischen zwei verschiedenen Bahnhöfen zu finden.", + "advancement.createrailwaysnavigator.advanced_display": "Nicht ganz 4k", + "advancement.createrailwaysnavigator.advanced_display.description": "Verbessere deine Anzeigetafel, um mehr Informationen darzustellen und sie sogar auf Zügen zu verwenden.", - "common.createrailwaysnavigator.search": "Suchen", + "itemGroup.createrailwaysnavigatortab": "Create Railways Navigator", "item.createrailwaysnavigator.navigator": "Create Railways Navigator", + "item.createrailwaysnavigator.navigator.tooltip.summary": "Der _Navigator_ zeigt mögliche _Zugverbindungen_ mit zusätzlichen Informationen, wie _Zwischenhalte_, _Echtzeitdaten_ und mehr.", - "itemGroup.createrailwaysnavigatortab": "Create Railways Navigator", + "block.createrailwaysnavigator.train_station_clock": "Bahnhofsuhr", + "block.createrailwaysnavigator.advanced_display_block": "Verbesserter Anzeige-Block", + "block.createrailwaysnavigator.advanced_display_block.tooltip.summary": "Benutze den Block auf _Zügen_ als _Zugzielanzeigen_ oder _Fahrgastinformationsanzeigen_ oder an _Bahnhöfen_ als verbesserte _Bahnsteiganzeigen_, die auch mehr Informationen anzeigen als normale Anzeigetafeln.", + "block.createrailwaysnavigator.advanced_display_block.tooltip.condition1": "R-Klick mit einem Schraubenschlüssel", + "block.createrailwaysnavigator.advanced_display_block.tooltip.behaviour1": "Öffne ein _Menü_, um die Anzeige zu _konfigurieren_.", + "block.createrailwaysnavigator.advanced_display": "Verbesserte Anzeige", + "block.createrailwaysnavigator.advanced_display.tooltip.summary": "Benutze den Block auf _Zügen_ als _Zugzielanzeigen_ oder _Fahrgastinformationsanzeigen_ oder an _Bahnhöfen_ als verbesserte _Bahnsteiganzeigen_, die auch mehr Informationen anzeigen als normale Anzeigetafeln.", + "block.createrailwaysnavigator.advanced_display.tooltip.condition1": "R-Klick mit einem Schraubenschlüssel", + "block.createrailwaysnavigator.advanced_display.tooltip.behaviour1": "Öffne ein _Menü_, um die Anzeige zu _konfigurieren_.", + "block.createrailwaysnavigator.advanced_display_small": "Kleine verbesserte Anzeige", + "block.createrailwaysnavigator.advanced_display_small.tooltip.summary": "Benutze den Block auf _Zügen_ als _Zugzielanzeigen_ oder _Fahrgastinformationsanzeigen_ oder an _Bahnhöfen_ als verbesserte _Bahnsteiganzeigen_, die auch mehr Informationen anzeigen als normale Anzeigetafeln.", + "block.createrailwaysnavigator.advanced_display_small.tooltip.condition1": "R-Klick mit einem Schraubenschlüssel", + "block.createrailwaysnavigator.advanced_display_small.tooltip.behaviour1": "Öffne ein _Menü_, um die Anzeige zu _konfigurieren_.", + "block.createrailwaysnavigator.advanced_display_panel": "Verbesserte Anzeigetafel", + "block.createrailwaysnavigator.advanced_display_panel.tooltip.summary": "Benutze den Block auf _Zügen_ als _Zugzielanzeigen_ oder _Fahrgastinformationsanzeigen_ oder an _Bahnhöfen_ als verbesserte _Bahnsteiganzeigen_, die auch mehr Informationen anzeigen als normale Anzeigetafeln.", + "block.createrailwaysnavigator.advanced_display_panel.tooltip.condition1": "R-Klick mit einem Schraubenschlüssel", + "block.createrailwaysnavigator.advanced_display_panel.tooltip.behaviour1": "Öffne ein _Menü_, um die Anzeige zu _konfigurieren_.", + + "block.createrailwaysnavigator.advanced_display.ber.not_in_service": "Außer Betrieb", "key.createrailwaysnavigator.category.crn": "Create Railways Navigator", "key.createrailwaysnavigator.route_overlay_options": "Routenanzeige Einstellungen", @@ -18,6 +39,7 @@ "enum.createrailwaysnavigator.overlay_position.info.bottom_right": "Ecke unten rechts", "gui.createrailwaysnavigator.loading.title": "Daten werden heruntergeladen...", + "gui.createrailwaysnavigator.overlay_settings.title": "Routenanzeige Einstellungen", "gui.createrailwaysnavigator.route_overlay_settings.show_details": "Details anzeigen", "gui.createrailwaysnavigator.route_overlay_settings.unpin": "Anzeige entfernen", @@ -39,6 +61,7 @@ "gui.createrailwaysnavigator.common.count": "Anzahl", "gui.createrailwaysnavigator.common.true": "Ja", "gui.createrailwaysnavigator.common.false": "Nein", + "gui.createrailwaysnavigator.common.search": "Suchen", "gui.createrailwaysnavigator.common.server_error": "Fehler beim Ausführen der Aufgabe. Schaue in die Serverkonsole.", "gui.createrailwaysnavigator.navigator.title": "Create Railways Navigator", @@ -71,7 +94,7 @@ "gui.createrailwaysnavigator.route_overview.transfer": "Umstieg in %s → %s auf Gleis %s", "gui.createrailwaysnavigator.route_overview.journey_completed": "Reise abgeschlossen", "gui.createrailwaysnavigator.route_overview.after_journey": "Sie haben %s erreicht. Wir bedanken uns für Ihre Reise und wünschen einen schönen Tag.", - "gui.createrailwaysnavigator.route_overview.next_connections": "Nächste Anschlüsse:", + "gui.createrailwaysnavigator.route_overview.next_connections": "Nächste Anschlüsse", "gui.createrailwaysnavigator.route_overview.schedule_transfer": "Umstieg", "gui.createrailwaysnavigator.route_overview.train_canceled": "Zug fällt aus", "gui.createrailwaysnavigator.route_overview.train_cancellation_info": "Information zu %s", @@ -101,6 +124,7 @@ "gui.createrailwaysnavigator.route_overview.notification.connection_missed": "Sie haben Ihren Anschlusszug %s nach %s verpasst.", "gui.createrailwaysnavigator.route_overview.notification.journey_completed.title": "Sie haben Ihr Ziel erreicht!", "gui.createrailwaysnavigator.route_overview.notification.journey_completed": "Wir bedanken uns für Ihre Reise und wünschen einen schönen Tag.", + "gui.createrailwaysnavigator.route_overview.date": "Tag %s, %s", "gui.createrailwaysnavigator.global_settings.title": "Globale Einstellungen", "gui.createrailwaysnavigator.global_settings.option.tooltip": "Zum Bearbeiten klicken", @@ -151,10 +175,58 @@ "gui.createrailwaysnavigator.new_text_entry.add.tooltip": "Hinzufügen", + "gui.createrailwaysnavigator.time": "Zeit: %s", "gui.createrailwaysnavigator.time.now": "jetzt", "gui.createrailwaysnavigator.time_format.dhm": "%s Tage %s Std. %s min.", "gui.createrailwaysnavigator.time_format.hm": "%s Std. %s min.", "gui.createrailwaysnavigator.time_format.m": "%s min.", + + "gui.createrailwaysnavigator.platform": "Gleis", + "gui.createrailwaysnavigator.departure": "Abfahrt", + "gui.createrailwaysnavigator.destination": "Ziel", + "gui.createrailwaysnavigator.line": "Linie", + "gui.createrailwaysnavigator.following_trains": "Folgezüge:", + + "gui.createrailwaysnavigator.advanced_display_settings.title": "Verbesserte Anzeige Einstellungen", + "gui.createrailwaysnavigator.advanced_display_settings.display_type": "Anzeigetyp", + "gui.createrailwaysnavigator.advanced_display_settings.display_type.description": "Die Informationen, die angezeigt werden sollen.", + "gui.createrailwaysnavigator.advanced_display_settings.info_type": "Informationsart", + "gui.createrailwaysnavigator.advanced_display_settings.info_type.description": "Gibt an, wie detailliert die Informationen sind.", + "gui.createrailwaysnavigator.advanced_display_settings.sides": "Seite", + "gui.createrailwaysnavigator.advanced_display_settings.sides.description": "Auf welchen Seiten des Blocks etwas angezeigt wird.", + + "enum.createrailwaysnavigator.display_info_type": "Informationsart", + "enum.createrailwaysnavigator.display_info_type.description": "Gibt an, wie viele Informationen dargestellt werden sollen.", + "enum.createrailwaysnavigator.display_info_type.simple": "Einfach", + "enum.createrailwaysnavigator.display_info_type.info.simple": "Es werden nur die wichtigsten Informationen ohne zusätzliche Details dargestellt.", + "enum.createrailwaysnavigator.display_info_type.detailed": "Detailliert", + "enum.createrailwaysnavigator.display_info_type.info.detailed": "Die wichtigsten Informationen mit einigen Details, wie z.B Zwischenhalte.", + "enum.createrailwaysnavigator.display_info_type.informative": "Informativ", + "enum.createrailwaysnavigator.display_info_type.info.informative": "Zeigt alle Informationen, die relevant sein können, und stellt sie möglichst anschaulich dar. Nicht für kleine Anzeigen empfohlen.", + + "enum.createrailwaysnavigator.display_type": "Anzeigetyp", + "enum.createrailwaysnavigator.display_type.description": "Die Art der Anzeige, was von ihrem Zweck abhängt.", + "enum.createrailwaysnavigator.display_type.train_destination": "Zugzielanzeige", + "enum.createrailwaysnavigator.display_type.info.train_destination": "Für die Verwendung außen an Zügen vorgesehen, da Informationen wie Zugname oder Endhalt dargestellt werden, die für Fahrgäste außerhalb des Fahrzeugs interessant sind.", + "enum.createrailwaysnavigator.display_type.passenger_information": "Fahrgastinformationsanzeige", + "enum.createrailwaysnavigator.display_type.info.passenger_information": "Repräsentieren die Anzeigen, die in Zügen vorkommen. Dargestellt werden der nächste Halt, die Ausstiegsseite und (je nach Einstellung) noch weitere Informationen.", + "enum.createrailwaysnavigator.display_type.platform": "Bahnsteiganzeige", + "enum.createrailwaysnavigator.display_type.info.platform": "Diese Anzeigen werden an Bahnsteigen verwendet und zeigen die nächsten abfahrenden Züge mit zusätzlichen Informationen an. Funktioniert nicht auf Zügen!", + + "enum.createrailwaysnavigator.side": "Seite", + "enum.createrailwaysnavigator.side.description": "Die Seite des Blocks, auf dem die Informationen angezeigt werden sollen.", + "enum.createrailwaysnavigator.side.front": "Vorderseite", + "enum.createrailwaysnavigator.side.info.front": "Die Informationen werden nur auf der Vorderseite dargestellt.", + "enum.createrailwaysnavigator.side.back": "Rückseite", + "enum.createrailwaysnavigator.side.info.back": "Die Informationen werden nur auf der Rückseite dargestellt.", + "enum.createrailwaysnavigator.side.both": "Beidseitig", + "enum.createrailwaysnavigator.side.info.both": "Die Informationen werden auf beiden Seiten dargestellt.", + + "create.display_source.advanced_display": "Verbesserte Anzeige", + "gui.createrailwaysnavigator.display_source.advanced_display.train_name_width": "Zugname Spaltenbreite", + "gui.createrailwaysnavigator.display_source.advanced_display.train_name_width.description": "Die Breite der Spalte für den Zugname in Pixel. (Standard: 16)", + "gui.createrailwaysnavigator.display_source.advanced_display.platform_width": "Gleis Spaltenbreite", + "gui.createrailwaysnavigator.display_source.advanced_display.platform_width.description": "Die Breite der Spalte für das Gleis in Pixel. (-1 = Autom., Standard: -1)", "createrailwaysnavigator.moin": "moin" } diff --git a/src/main/resources/assets/createrailwaysnavigator/lang/en_us.json b/src/main/resources/assets/createrailwaysnavigator/lang/en_us.json index 68dcab61..2b2efeaf 100644 --- a/src/main/resources/assets/createrailwaysnavigator/lang/en_us.json +++ b/src/main/resources/assets/createrailwaysnavigator/lang/en_us.json @@ -1,12 +1,33 @@ { - "advancement.createrailwaysnavigator.root": "Thank you for traveling", - "advancement.createrailwaysnavigator.root.description": "Craft a Create Railways Navigator Item to look for train connections from one train station to another.", + "advancement.createrailwaysnavigator.navigator": "Thank you for traveling", + "advancement.createrailwaysnavigator.navigator.description": "Craft a Navigator to search for train connections from one train station to another.", + "advancement.createrailwaysnavigator.advanced_display": "Not quite 4k", + "advancement.createrailwaysnavigator.advanced_display.description": "Upgrade your display boards to display more information and even place them in your trains.", - "common.createrailwaysnavigator.search": "Search", + "itemGroup.createrailwaysnavigatortab": "Create Railways Navigator", "item.createrailwaysnavigator.navigator": "Create Railways Navigator", + "item.createrailwaysnavigator.navigator.tooltip.summary": "The _navigator_ shows possible _train connections_ with additional information such as _stopovers_, _real-time data_ and more.", - "itemGroup.createrailwaysnavigatortab": "Create Railways Navigator", + "block.createrailwaysnavigator.train_station_clock": "Train Station Clock", + "block.createrailwaysnavigator.advanced_display_block": "Advanced Display Block", + "block.createrailwaysnavigator.advanced_display_block.tooltip.summary": "Use it on _trains_, as a _train destination display_ or _passenger information display_, or at _train stations_ as improved _platform displays_ which also shows more information than regular display boards.", + "block.createrailwaysnavigator.advanced_display_block.tooltip.condition1": "When R-Clicked using a Wrench", + "block.createrailwaysnavigator.advanced_display_block.tooltip.behaviour1": "Open a menu to _configure_ the _display_.", + "block.createrailwaysnavigator.advanced_display": "Advanced Display", + "block.createrailwaysnavigator.advanced_display.tooltip.summary": "Use it on _trains_, as a _train destination display_ or _passenger information display_, or at _train stations_ as improved _platform displays_ which also shows more information than regular display boards.", + "block.createrailwaysnavigator.advanced_display.tooltip.condition1": "When R-Clicked using a Wrench", + "block.createrailwaysnavigator.advanced_display.tooltip.behaviour1": "Open a menu to _configure_ the _display_.", + "block.createrailwaysnavigator.advanced_display_small": "Small Advanced Display", + "block.createrailwaysnavigator.advanced_display_small.tooltip.summary": "Use it on _trains_, as a _train destination display_ or _passenger information display_, or at _train stations_ as improved _platform displays_ which also shows more information than regular display boards.", + "block.createrailwaysnavigator.advanced_display_small.tooltip.condition1": "When R-Clicked using a Wrench", + "block.createrailwaysnavigator.advanced_display_small.tooltip.behaviour1": "Open a menu to _configure_ the _display_.", + "block.createrailwaysnavigator.advanced_display_panel": "Advanced Display Panel", + "block.createrailwaysnavigator.advanced_display_panel.tooltip.summary": "Use it on _trains_, as a _train destination display_ or _passenger information display_, or at _train stations_ as improved _platform displays_ which also shows more information than regular display boards.", + "block.createrailwaysnavigator.advanced_display_panel.tooltip.condition1": "When R-Clicked using a Wrench", + "block.createrailwaysnavigator.advanced_display_panel.tooltip.behaviour1": "Open a menu to _configure_ the _display_.", + + "block.createrailwaysnavigator.advanced_display.ber.not_in_service": "Out of service!", "key.createrailwaysnavigator.category.crn": "Create Railways Navigator", "key.createrailwaysnavigator.route_overlay_options": "Show Route Overlay Options", @@ -18,6 +39,7 @@ "enum.createrailwaysnavigator.overlay_position.info.bottom_right": "Bottom Right Corner", "gui.createrailwaysnavigator.loading.title": "Downloading data from server...", + "gui.createrailwaysnavigator.overlay_settings.title": "Route Overlay Settings", "gui.createrailwaysnavigator.route_overlay_settings.show_details": "Show details", "gui.createrailwaysnavigator.route_overlay_settings.unpin": "Remove route overlay", @@ -39,6 +61,7 @@ "gui.createrailwaysnavigator.common.count": "Count", "gui.createrailwaysnavigator.common.true": "Yes", "gui.createrailwaysnavigator.common.false": "No", + "gui.createrailwaysnavigator.common.search": "Search", "gui.createrailwaysnavigator.common.server_error": "Server error while executing task. Look console for details.", "gui.createrailwaysnavigator.navigator.title": "Create Railways Navigator", @@ -71,7 +94,7 @@ "gui.createrailwaysnavigator.route_overview.transfer": "Change to %s → %s on platform %s", "gui.createrailwaysnavigator.route_overview.journey_completed": "Journey completed", "gui.createrailwaysnavigator.route_overview.after_journey": "You have reached %s. Thank you for traveling and have a nice day.", - "gui.createrailwaysnavigator.route_overview.next_connections": "Next connections:", + "gui.createrailwaysnavigator.route_overview.next_connections": "Next connections", "gui.createrailwaysnavigator.route_overview.schedule_transfer": "Transfer", "gui.createrailwaysnavigator.route_overview.train_canceled": "Train Canceled", "gui.createrailwaysnavigator.route_overview.train_cancellation_info": "Information about %s", @@ -101,6 +124,7 @@ "gui.createrailwaysnavigator.route_overview.notification.connection_missed": "You missed your connecting train %s to %s.", "gui.createrailwaysnavigator.route_overview.notification.journey_completed.title": "You have reached your destination!", "gui.createrailwaysnavigator.route_overview.notification.journey_completed": "Thank you for traveling and have a nice day", + "gui.createrailwaysnavigator.route_overview.date": "Day %s, %s", "gui.createrailwaysnavigator.global_settings.title": "Global Settings", "gui.createrailwaysnavigator.global_settings.option.tooltip": "Click to edit", @@ -151,10 +175,58 @@ "gui.createrailwaysnavigator.new_text_entry.add.tooltip": "Add", + "gui.createrailwaysnavigator.time": "Time: %s", "gui.createrailwaysnavigator.time.now": "now", "gui.createrailwaysnavigator.time_format.dhm": "%s days %s hrs. %s min.", "gui.createrailwaysnavigator.time_format.hm": "%s hrs. %s min.", "gui.createrailwaysnavigator.time_format.m": "%s min.", + + "gui.createrailwaysnavigator.platform": "Platform", + "gui.createrailwaysnavigator.departure": "Departure", + "gui.createrailwaysnavigator.destination": "Destination", + "gui.createrailwaysnavigator.line": "Line", + "gui.createrailwaysnavigator.following_trains": "Following trains:", + + "gui.createrailwaysnavigator.advanced_display_settings.title": "Advanced Display Settings", + "gui.createrailwaysnavigator.advanced_display_settings.display_type": "Display Type", + "gui.createrailwaysnavigator.advanced_display_settings.display_type.description": "Determines the information displayed.", + "gui.createrailwaysnavigator.advanced_display_settings.info_type": "Information Type", + "gui.createrailwaysnavigator.advanced_display_settings.info_type.description": "Determines how detailed the information is.", + "gui.createrailwaysnavigator.advanced_display_settings.sides": "Render Sides", + "gui.createrailwaysnavigator.advanced_display_settings.sides.description": "Determines which sides the content should be rendered on.", + + "enum.createrailwaysnavigator.display_info_type": "Display Info Type", + "enum.createrailwaysnavigator.display_info_type.description": "Determines how much information should be displayed on your display board.", + "enum.createrailwaysnavigator.display_info_type.simple": "Simple", + "enum.createrailwaysnavigator.display_info_type.info.simple": "The display will only show the most important information without additional details.", + "enum.createrailwaysnavigator.display_info_type.detailed": "Detailed", + "enum.createrailwaysnavigator.display_info_type.info.detailed": "The most important information with some details will be shown, such as train speed, stopovers, etc.", + "enum.createrailwaysnavigator.display_info_type.informative": "Informative", + "enum.createrailwaysnavigator.display_info_type.info.informative": "Shows all information that could be interesting and displays it in a fancy layout. Not recommended for small displays as the text might become very small.", + + "enum.createrailwaysnavigator.display_type": "Display Type", + "enum.createrailwaysnavigator.display_type.description": "The type of your display which depends on their purpose.", + "enum.createrailwaysnavigator.display_type.train_destination": "Train Destination", + "enum.createrailwaysnavigator.display_type.info.train_destination": "Inteded to be used outside of trains as it shows information about the train itself such as the name, destination and (if selected) stopovers and other information.", + "enum.createrailwaysnavigator.display_type.passenger_information": "Passenger Information", + "enum.createrailwaysnavigator.display_type.info.passenger_information": "Represents the displays found inside of trains. These displays will show the next stop, the exit direction and (if selected) train speed and a route overview.", + "enum.createrailwaysnavigator.display_type.platform": "Platform Display", + "enum.createrailwaysnavigator.display_type.info.platform": "These displays should be used on train station platforms and shows the next ariving trains with additional details if selected. Cannot be used in trains!", + + "enum.createrailwaysnavigator.side": "Side", + "enum.createrailwaysnavigator.side.description": "The side of the block where the information should be rendered on.", + "enum.createrailwaysnavigator.side.front": "Front side", + "enum.createrailwaysnavigator.side.info.front": "The information will only be rendered on the front side. This is the default behaviour.", + "enum.createrailwaysnavigator.side.back": "Back side", + "enum.createrailwaysnavigator.side.info.back": "The information will only be rendered on the back side.", + "enum.createrailwaysnavigator.side.both": "Both sides", + "enum.createrailwaysnavigator.side.info.both": "The information will be rendered on both sides.", + + "create.display_source.advanced_display": "Advanced Displays", + "gui.createrailwaysnavigator.display_source.advanced_display.train_name_width": "Train Name Column Width", + "gui.createrailwaysnavigator.display_source.advanced_display.train_name_width.description": "The width of the train name column in block pixels. (Default: 16)", + "gui.createrailwaysnavigator.display_source.advanced_display.platform_width": "Platform Column Width", + "gui.createrailwaysnavigator.display_source.advanced_display.platform_width.description": "The width of the platform column in block pixels. (-1 = Auto, Default: -1)", "createrailwaysnavigator.moin": "moin" } diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display.json new file mode 100644 index 00000000..d92d7184 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display.json @@ -0,0 +1,55 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "1": "createrailwaysnavigator:block/advanced_display", + "2": "createrailwaysnavigator:block/advanced_display_back", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 3], + "to": [16, 16, 13], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "east": {"uv": [8, 0, 13, 8], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 8, 8], "texture": "#2"}, + "west": {"uv": [13, 0, 8, 8], "texture": "#2", "cullface": "west"}, + "up": {"uv": [8, 0, 13, 8], "rotation": 90, "texture": "#2", "cullface": "up"}, + "down": {"uv": [8, 0, 13, 8], "rotation": 90, "texture": "#2", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 225, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_block.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_block.json new file mode 100644 index 00000000..3f2e9994 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_block.json @@ -0,0 +1,55 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "1": "createrailwaysnavigator:block/advanced_display", + "2": "createrailwaysnavigator:block/advanced_display_back", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#1", "cullface": "north"}, + "east": {"uv": [0, 0, 8, 8], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 8, 8], "texture": "#2", "cullface": "south"}, + "west": {"uv": [8, 0, 0, 8], "texture": "#2", "cullface": "west"}, + "up": {"uv": [0, 0, 8, 8], "rotation": 90, "texture": "#2", "cullface": "up"}, + "down": {"uv": [0, 0, 8, 8], "rotation": 90, "texture": "#2", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 225, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_block_double.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_block_double.json new file mode 100644 index 00000000..856ccbac --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_block_double.json @@ -0,0 +1,55 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "1": "createrailwaysnavigator:block/advanced_display", + "2": "createrailwaysnavigator:block/advanced_display_back", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#1", "cullface": "north"}, + "east": {"uv": [0, 0, 8, 8], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#1", "cullface": "south"}, + "west": {"uv": [8, 0, 0, 8], "texture": "#2", "cullface": "west"}, + "up": {"uv": [0, 0, 8, 8], "rotation": 90, "texture": "#2", "cullface": "up"}, + "down": {"uv": [0, 0, 8, 8], "rotation": 90, "texture": "#2", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 225, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_double.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_double.json new file mode 100644 index 00000000..98061785 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_double.json @@ -0,0 +1,55 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "1": "createrailwaysnavigator:block/advanced_display", + "2": "createrailwaysnavigator:block/advanced_display_back", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 3], + "to": [16, 16, 13], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "east": {"uv": [8, 0, 13, 8], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "west": {"uv": [13, 0, 8, 8], "texture": "#2", "cullface": "west"}, + "up": {"uv": [8, 0, 13, 8], "rotation": 90, "texture": "#2", "cullface": "up"}, + "down": {"uv": [8, 0, 13, 8], "rotation": 90, "texture": "#2", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 225, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_panel.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_panel.json new file mode 100644 index 00000000..26cbae70 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_panel.json @@ -0,0 +1,62 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "1": "createrailwaysnavigator:block/advanced_display", + "2": "createrailwaysnavigator:block/advanced_display_back", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 13], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "east": {"uv": [13, 0, 14.5, 8], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 8, 8], "texture": "#2", "cullface": "south"}, + "west": {"uv": [14.5, 0, 13, 8], "texture": "#2", "cullface": "west"}, + "up": {"uv": [13, 0, 14.5, 8], "rotation": 90, "texture": "#2", "cullface": "up"}, + "down": {"uv": [13, 0, 14.5, 8], "rotation": 90, "texture": "#2", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, -1.5], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [3, -1.5, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "translation": [0, 0, -12.75] + }, + "fixed": { + "translation": [0, 0, -2.75], + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_panel_back.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_panel_back.json new file mode 100644 index 00000000..f2133094 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_panel_back.json @@ -0,0 +1,62 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "1": "createrailwaysnavigator:block/advanced_display", + "2": "createrailwaysnavigator:block/advanced_display_back", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 13], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 8, 8], "texture": "#2"}, + "east": {"uv": [13, 0, 14.5, 8], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#1", "cullface": "south"}, + "west": {"uv": [14.5, 0, 13, 8], "texture": "#2", "cullface": "west"}, + "up": {"uv": [13, 0, 14.5, 8], "rotation": 90, "texture": "#2", "cullface": "up"}, + "down": {"uv": [13, 0, 14.5, 8], "rotation": 90, "texture": "#2", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, -1.5], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [3, -1.5, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "translation": [0, 0, -12.75] + }, + "fixed": { + "translation": [0, 0, -2.75], + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_panel_double.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_panel_double.json new file mode 100644 index 00000000..a7984230 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_panel_double.json @@ -0,0 +1,62 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "1": "createrailwaysnavigator:block/advanced_display", + "2": "createrailwaysnavigator:block/advanced_display_back", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 13], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "east": {"uv": [13, 0, 14.5, 8], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "west": {"uv": [14.5, 0, 13, 8], "texture": "#2"}, + "up": {"uv": [13, 0, 14.5, 8], "rotation": 90, "texture": "#2"}, + "down": {"uv": [13, 0, 14.5, 8], "rotation": 90, "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, -1.5], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [3, -1.5, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "translation": [0, 0, -12.75] + }, + "fixed": { + "translation": [0, 0, -2.75], + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small.json new file mode 100644 index 00000000..b5ad186f --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small.json @@ -0,0 +1,62 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "2": "createrailwaysnavigator:block/advanced_display_back", + "3": "createrailwaysnavigator:block/advanced_display_small", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 8], + "to": [16, 8, 16], + "faces": { + "north": {"uv": [0, 0, 16, 8], "texture": "#3"}, + "east": {"uv": [8, 8, 12, 12], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 8, 8, 12], "texture": "#2", "cullface": "south"}, + "west": {"uv": [12, 8, 8, 12], "texture": "#2", "cullface": "west"}, + "up": {"uv": [0, 8, 8, 12], "texture": "#2"}, + "down": {"uv": [0, 8, 8, 12], "texture": "#2", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, -1], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [1.75, 1, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "translation": [0, 0, -8] + }, + "fixed": { + "translation": [0, 0, -0.75], + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_back.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_back.json new file mode 100644 index 00000000..2ca81291 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_back.json @@ -0,0 +1,62 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "2": "createrailwaysnavigator:block/advanced_display_back", + "3": "createrailwaysnavigator:block/advanced_display_small", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 8], + "to": [16, 8, 16], + "faces": { + "north": {"uv": [0, 8, 8, 12], "texture": "#2"}, + "east": {"uv": [8, 8, 12, 12], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 8], "texture": "#3", "cullface": "south"}, + "west": {"uv": [12, 8, 8, 12], "texture": "#2", "cullface": "west"}, + "up": {"uv": [0, 8, 8, 12], "texture": "#2"}, + "down": {"uv": [0, 8, 8, 12], "texture": "#2", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, -1], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [1.75, 1, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "translation": [0, 0, -8] + }, + "fixed": { + "translation": [0, 0, -0.75], + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_double.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_double.json new file mode 100644 index 00000000..c4087028 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_double.json @@ -0,0 +1,62 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "2": "createrailwaysnavigator:block/advanced_display_back", + "3": "createrailwaysnavigator:block/advanced_display_small", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 0, 8], + "to": [16, 8, 16], + "faces": { + "north": {"uv": [0, 0, 16, 8], "texture": "#3"}, + "east": {"uv": [8, 8, 12, 12], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 8], "texture": "#3", "cullface": "south"}, + "west": {"uv": [12, 8, 8, 12], "texture": "#2", "cullface": "west"}, + "up": {"uv": [0, 8, 8, 12], "texture": "#2"}, + "down": {"uv": [0, 8, 8, 12], "texture": "#2", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, -1], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [1.75, 1, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "translation": [0, 0, -8] + }, + "fixed": { + "translation": [0, 0, -0.75], + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_top.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_top.json new file mode 100644 index 00000000..72143e95 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_top.json @@ -0,0 +1,58 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "2": "createrailwaysnavigator:block/advanced_display_back", + "4": "createrailwaysnavigator:block/advanced_display_small", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 8, 8], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "east": {"uv": [8, 8, 12, 12], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 8, 8, 12], "texture": "#2", "cullface": "south"}, + "west": {"uv": [12, 8, 8, 12], "texture": "#2", "cullface": "west"}, + "up": {"uv": [0, 8, 8, 12], "texture": "#2", "cullface": "up"}, + "down": {"uv": [0, 8, 8, 12], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 1.5], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 1.5], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [0, 1.5, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [0, 1.5, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [2, 1.5, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_top_back.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_top_back.json new file mode 100644 index 00000000..b73ae5aa --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_top_back.json @@ -0,0 +1,58 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "2": "createrailwaysnavigator:block/advanced_display_back", + "4": "createrailwaysnavigator:block/advanced_display_small", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 8, 8], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 8, 8, 12], "texture": "#2"}, + "east": {"uv": [8, 8, 12, 12], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 8], "texture": "#4", "cullface": "south"}, + "west": {"uv": [12, 8, 8, 12], "texture": "#2", "cullface": "west"}, + "up": {"uv": [0, 8, 8, 12], "texture": "#2", "cullface": "up"}, + "down": {"uv": [0, 8, 8, 12], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 1.5], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 1.5], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [0, 1.5, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [0, 1.5, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [2, 1.5, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_top_double.json b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_top_double.json new file mode 100644 index 00000000..5f26d63d --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/advanced_display_small_top_double.json @@ -0,0 +1,58 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "texture_size": [64, 64], + "textures": { + "2": "createrailwaysnavigator:block/advanced_display_back", + "4": "createrailwaysnavigator:block/advanced_display_small", + "particle": "createrailwaysnavigator:block/advanced_display" + }, + "elements": [ + { + "from": [0, 8, 8], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "east": {"uv": [8, 8, 12, 12], "texture": "#2", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 8], "texture": "#4", "cullface": "south"}, + "west": {"uv": [12, 8, 8, 12], "texture": "#2", "cullface": "west"}, + "up": {"uv": [0, 8, 8, 12], "texture": "#2", "cullface": "up"}, + "down": {"uv": [0, 8, 8, 12], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 1.5], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 1.5], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [0, 1.5, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [0, 1.5, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [2, 1.5, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/block/train_station_clock.json b/src/main/resources/assets/createrailwaysnavigator/models/block/train_station_clock.json new file mode 100644 index 00000000..9d61ba9c --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/block/train_station_clock.json @@ -0,0 +1,327 @@ +{ + "credit": "Made with Blockbench", + "render_type": "minecraft:cutout", + "textures": { + "0": "block/anvil", + "2": "block/black_concrete", + "3": "createrailwaysnavigator:block/dial", + "6": "createrailwaysnavigator:block/crn_logo", + "particle": "block/anvil" + }, + "elements": [ + { + "from": [4.6, 15, 4], + "to": [11.4, 16, 12], + "faces": { + "north": {"uv": [0, 0, 6.8, 1], "texture": "#0"}, + "east": {"uv": [0, 0, 8, 1], "texture": "#0"}, + "south": {"uv": [0, 0, 6.8, 1], "texture": "#0"}, + "west": {"uv": [0, 0, 8, 1], "texture": "#0"}, + "up": {"uv": [0, 0, 6.8, 8], "texture": "#0", "cullface": "up"}, + "down": {"uv": [0, 0, 6.8, 8], "texture": "#0"} + } + }, + { + "from": [4.6, 0, 4], + "to": [11.4, 1, 12], + "faces": { + "north": {"uv": [0, 0, 6.8, 1], "texture": "#0"}, + "east": {"uv": [0, 0, 8, 1], "texture": "#0"}, + "south": {"uv": [0, 0, 6.8, 1], "texture": "#0"}, + "west": {"uv": [0, 0, 8, 1], "texture": "#0"}, + "up": {"uv": [0, 0, 6.8, 8], "texture": "#0"}, + "down": {"uv": [0, 0, 6.8, 8], "texture": "#0", "cullface": "down"} + } + }, + { + "from": [15, 4.6, 4], + "to": [16, 11.4, 12], + "rotation": {"angle": 0, "axis": "y", "origin": [0.5, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 6.8], "texture": "#0"}, + "east": {"uv": [0, 0, 8, 6.8], "texture": "#0", "cullface": "east"}, + "south": {"uv": [0, 0, 1, 6.8], "texture": "#0"}, + "west": {"uv": [0, 0, 8, 6.8], "texture": "#0"}, + "up": {"uv": [0, 0, 1, 8], "texture": "#0"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#0"} + } + }, + { + "from": [0, 4.6, 4], + "to": [1, 11.4, 12], + "faces": { + "north": {"uv": [0, 0, 1, 6.8], "texture": "#0"}, + "east": {"uv": [0, 0, 8, 6.8], "texture": "#0"}, + "south": {"uv": [0, 0, 1, 6.8], "texture": "#0"}, + "west": {"uv": [0, 0, 8, 6.8], "texture": "#0", "cullface": "west"}, + "up": {"uv": [0, 0, 1, 8], "texture": "#0"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#0"} + } + }, + { + "from": [2.15074, 10.09926, 4], + "to": [3.15074, 16.59926, 12], + "rotation": {"angle": -45, "axis": "z", "origin": [2.65074, 13.34926, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 6.5], "texture": "#0"}, + "east": {"uv": [0, 0, 8, 6.5], "texture": "#0"}, + "south": {"uv": [0, 0, 1, 6.5], "texture": "#0"}, + "west": {"uv": [0, 0, 8, 6.5], "texture": "#0"}, + "up": {"uv": [0, 0, 1, 8], "texture": "#0"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#0"} + } + }, + { + "from": [4.75, -0.06, 4], + "to": [11.25, 0.94, 12], + "rotation": {"angle": 45, "axis": "z", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 6.5], "rotation": 90, "texture": "#0"}, + "east": {"uv": [0, 0, 1, 8], "rotation": 270, "texture": "#0"}, + "south": {"uv": [0, 0, 1, 6.5], "rotation": 270, "texture": "#0"}, + "west": {"uv": [0, 0, 1, 8], "rotation": 270, "texture": "#0"}, + "up": {"uv": [0, 0, 8, 6.5], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 0, 8, 6.5], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [4.75, -0.06, 4], + "to": [11.25, 0.94, 12], + "rotation": {"angle": -45, "axis": "z", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 6.5], "rotation": 90, "texture": "#0"}, + "east": {"uv": [0, 0, 1, 8], "rotation": 270, "texture": "#0"}, + "south": {"uv": [0, 0, 1, 6.5], "rotation": 270, "texture": "#0"}, + "west": {"uv": [0, 0, 1, 8], "rotation": 270, "texture": "#0"}, + "up": {"uv": [0, 0, 8, 6.5], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 0, 8, 6.5], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [4.75, 15.06, 4], + "to": [11.25, 16.06, 12], + "rotation": {"angle": -45, "axis": "z", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 6.5], "rotation": 270, "texture": "#0"}, + "east": {"uv": [0, 0, 1, 8], "rotation": 90, "texture": "#0"}, + "south": {"uv": [0, 0, 1, 6.5], "rotation": 90, "texture": "#0"}, + "west": {"uv": [0, 0, 1, 8], "rotation": 90, "texture": "#0"}, + "up": {"uv": [0, 0, 8, 6.5], "rotation": 90, "texture": "#0"}, + "down": {"uv": [0, 0, 8, 6.5], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [7, 11.3, 4.9], + "to": [9, 12.7, 11.1], + "faces": { + "north": {"uv": [0, 0, 16, 8.5], "texture": "#6"}, + "south": {"uv": [0, 0, 16, 8.5], "texture": "#6"} + } + }, + { + "name": "dial", + "from": [1, 1, 5], + "to": [15, 15, 11], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#3"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#3"} + } + }, + { + "from": [7.5, 1, 4.9], + "to": [8.5, 2.5, 11.1], + "faces": { + "north": {"uv": [0, 0, 1, 1.5], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1.5], "texture": "#2"} + } + }, + { + "from": [1, 7.5, 4.9], + "to": [2.5, 8.5, 11.1], + "faces": { + "north": {"uv": [0, 0, 1.5, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 1.5, 1], "texture": "#2"} + } + }, + { + "from": [13.5, 7.5, 4.9], + "to": [15, 8.5, 11.1], + "faces": { + "north": {"uv": [0, 0, 1.5, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 1.5, 1], "texture": "#2"} + } + }, + { + "from": [7.25, 7.25, 4.65], + "to": [8.75, 8.75, 11.35], + "rotation": {"angle": 0, "axis": "z", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 1.5, 1.5], "texture": "#0"}, + "east": {"uv": [0, 0, 6.7, 1.5], "texture": "#0"}, + "south": {"uv": [0, 0, 1.5, 1.5], "texture": "#0"}, + "west": {"uv": [0, 0, 6.7, 1.5], "texture": "#0"}, + "up": {"uv": [0, 0, 1.5, 6.7], "texture": "#0"}, + "down": {"uv": [0, 0, 1.5, 6.7], "texture": "#0"} + } + }, + { + "from": [10.90901, 2.96967, 4.9], + "to": [11.90901, 3.96967, 11.1], + "rotation": {"angle": 45, "axis": "z", "origin": [13.03033, 2.96967, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1], "texture": "#2"} + } + }, + { + "from": [13.32322, 3.96967, 4.9], + "to": [14.32322, 4.96967, 11.1], + "rotation": {"angle": 45, "axis": "z", "origin": [13.82322, 4.46967, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1], "texture": "#2"} + } + }, + { + "from": [10.90901, 16.21967, 4.9], + "to": [11.90901, 17.21967, 11.1], + "rotation": {"angle": 45, "axis": "z", "origin": [13.03033, 2.96967, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1], "texture": "#2"} + } + }, + { + "from": [13.32322, 17.21967, 4.9], + "to": [14.32322, 18.21967, 11.1], + "rotation": {"angle": 45, "axis": "z", "origin": [13.82322, 4.46967, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1], "texture": "#2"} + } + }, + { + "from": [1.40901, 1.46967, 4.9], + "to": [2.40901, 2.46967, 11.1], + "rotation": {"angle": -45, "axis": "z", "origin": [5.03033, 2.96967, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1], "texture": "#2"} + } + }, + { + "from": [4.65165, 1.46967, 4.9], + "to": [5.65165, 2.46967, 11.1], + "rotation": {"angle": -45, "axis": "z", "origin": [5.03033, 2.96967, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 1], "rotation": 270, "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1], "rotation": 90, "texture": "#2"} + } + }, + { + "from": [1.40901, 14.71967, 4.9], + "to": [2.40901, 15.71967, 11.1], + "rotation": {"angle": -45, "axis": "z", "origin": [5.03033, 2.96967, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1], "texture": "#2"} + } + }, + { + "from": [4.65165, 14.71967, 4.9], + "to": [5.65165, 15.71967, 11.1], + "rotation": {"angle": -45, "axis": "z", "origin": [5.03033, 2.96967, 8]}, + "faces": { + "north": {"uv": [0, 0, 1, 1], "rotation": 270, "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1], "rotation": 90, "texture": "#2"} + } + }, + { + "from": [7.5, 13.5, 4.9], + "to": [8.5, 15, 11.1], + "faces": { + "north": {"uv": [0, 0, 1, 1.5], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 1.5], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [1, 2, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [1, 2, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, -45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, -45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "translation": [0, 14.25, 0] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + }, + "groups": [ + { + "name": "Border", + "origin": [8, 8, 8], + "color": 0, + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8] + }, + 9, + { + "name": "markers", + "origin": [8, 8, 8], + "color": 0, + "children": [ + 10, + 11, + 12, + 13, + { + "name": "group", + "origin": [13.03033, 2.96967, 8], + "color": 0, + "children": [14, 15] + }, + { + "name": "group", + "origin": [13.03033, 2.96967, 8], + "color": 0, + "children": [16, 17] + }, + { + "name": "group", + "origin": [13.03033, 2.96967, 8], + "color": 0, + "children": [18, 19] + }, + { + "name": "group", + "origin": [13.03033, 2.96967, 8], + "color": 0, + "children": [20, 21] + }, + 22 + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display.json b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display.json new file mode 100644 index 00000000..789c143e --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display.json @@ -0,0 +1,3 @@ +{ + "parent": "createrailwaysnavigator:block/advanced_display" +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_block.json b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_block.json new file mode 100644 index 00000000..42386846 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_block.json @@ -0,0 +1,3 @@ +{ + "parent": "createrailwaysnavigator:block/advanced_display_block" +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_panel.json b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_panel.json new file mode 100644 index 00000000..4e558ba1 --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_panel.json @@ -0,0 +1,3 @@ +{ + "parent": "createrailwaysnavigator:block/advanced_display_panel" +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_sloped.json b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_sloped.json new file mode 100644 index 00000000..07b19dce --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_sloped.json @@ -0,0 +1,103 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [32, 32], + "textures": { + "1": "createrailwaysnavigator:block/advanced_display_small", + "2": "createrailwaysnavigator:block/advanced_display_back", + "particle": "createrailwaysnavigator:block/advanced_display_small_connected" + }, + "elements": [ + { + "from": [0.2, 8, 5.25], + "to": [15.8, 10, 10.75], + "faces": { + "east": {"uv": [2.625, 7, 5.375, 8], "texture": "#2"}, + "west": {"uv": [2.625, 7, 5.375, 8], "texture": "#2"}, + "down": {"uv": [0, 8.625, 8.1, 11.375], "texture": "#2"} + } + }, + { + "from": [0.2, 10, 4.5], + "to": [15.8, 12, 11.5], + "faces": { + "east": {"uv": [2.25, 6, 5.75, 7], "texture": "#2"}, + "west": {"uv": [2.25, 6, 5.75, 7], "texture": "#2"} + } + }, + { + "from": [0.2, 12, 3.5], + "to": [15.8, 14, 12.5], + "faces": { + "east": {"uv": [1.75, 2, 6.25, 3], "texture": "#2"}, + "west": {"uv": [1.75, 2, 6.25, 3], "texture": "#2"} + } + }, + { + "from": [0.2, 14, 2.75], + "to": [15.8, 16, 13.25], + "faces": { + "east": {"uv": [1.375, 0, 6.625, 1], "texture": "#2"}, + "west": {"uv": [1.375, 0, 6.625, 1], "texture": "#2"}, + "up": {"uv": [0, 1.375, 8, 6.625], "texture": "#2"} + } + }, + { + "from": [0, 7, 10], + "to": [16, 16, 11], + "rotation": {"angle": 22.5, "axis": "x", "origin": [8, 8, 12]}, + "faces": { + "north": {"uv": [0, 8, 8, 12], "texture": "#2"}, + "east": {"uv": [0, 0, 0.5, 4], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 8], "texture": "#1"}, + "west": {"uv": [0, 0, 0.5, 4], "texture": "#2"}, + "up": {"uv": [0, 0, 8, 0.5], "texture": "#2"}, + "down": {"uv": [0, 0, 8, 0.5], "texture": "#2"} + } + }, + { + "from": [0, 7, 5], + "to": [16, 16, 6], + "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 8, 4]}, + "faces": { + "north": {"uv": [0, 0, 15.8, 8], "texture": "#1"}, + "east": {"uv": [0, 0, 0.5, 4], "texture": "#2"}, + "south": {"uv": [0, 8, 8, 12], "texture": "#2"}, + "west": {"uv": [0, 0, 0.5, 4], "texture": "#2"}, + "up": {"uv": [0, 0, 8, 0.5], "texture": "#2"}, + "down": {"uv": [0, 0, 8, 0.5], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0.5, 1.25, -1.5], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0.5, 1.25, -1.5], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, -45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, -45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [0, -2.25, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_small.json b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_small.json new file mode 100644 index 00000000..262fa34c --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/item/advanced_display_small.json @@ -0,0 +1,3 @@ +{ + "parent": "createrailwaysnavigator:block/advanced_display_small" +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/models/item/train_station_clock.json b/src/main/resources/assets/createrailwaysnavigator/models/item/train_station_clock.json new file mode 100644 index 00000000..9428c15c --- /dev/null +++ b/src/main/resources/assets/createrailwaysnavigator/models/item/train_station_clock.json @@ -0,0 +1,3 @@ +{ + "parent": "createrailwaysnavigator:block/train_station_clock" +} \ No newline at end of file diff --git a/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display.png b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display.png new file mode 100644 index 00000000..ae15e2bd Binary files /dev/null and b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display.png differ diff --git a/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_back.png b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_back.png new file mode 100644 index 00000000..07681a5d Binary files /dev/null and b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_back.png differ diff --git a/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_connected.png b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_connected.png new file mode 100644 index 00000000..256bd1f0 Binary files /dev/null and b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_connected.png differ diff --git a/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_small.png b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_small.png new file mode 100644 index 00000000..05d3150e Binary files /dev/null and b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_small.png differ diff --git a/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_small_connected.png b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_small_connected.png new file mode 100644 index 00000000..99f70336 Binary files /dev/null and b/src/main/resources/assets/createrailwaysnavigator/textures/block/advanced_display_small_connected.png differ diff --git a/src/main/resources/assets/createrailwaysnavigator/textures/block/crn_logo.png b/src/main/resources/assets/createrailwaysnavigator/textures/block/crn_logo.png new file mode 100644 index 00000000..ccd359b2 Binary files /dev/null and b/src/main/resources/assets/createrailwaysnavigator/textures/block/crn_logo.png differ diff --git a/src/main/resources/assets/createrailwaysnavigator/textures/block/dial.png b/src/main/resources/assets/createrailwaysnavigator/textures/block/dial.png new file mode 100644 index 00000000..898543b7 Binary files /dev/null and b/src/main/resources/assets/createrailwaysnavigator/textures/block/dial.png differ diff --git a/src/main/resources/assets/createrailwaysnavigator/textures/gui/advanced_display_settings.png b/src/main/resources/assets/createrailwaysnavigator/textures/gui/advanced_display_settings.png new file mode 100644 index 00000000..efacd0e2 Binary files /dev/null and b/src/main/resources/assets/createrailwaysnavigator/textures/gui/advanced_display_settings.png differ diff --git a/src/main/resources/assets/createrailwaysnavigator/textures/gui/icons.png b/src/main/resources/assets/createrailwaysnavigator/textures/gui/icons.png index 909f70e2..3adddf9a 100644 Binary files a/src/main/resources/assets/createrailwaysnavigator/textures/gui/icons.png and b/src/main/resources/assets/createrailwaysnavigator/textures/gui/icons.png differ diff --git a/src/main/resources/createrailwaysnavigator.mixins.json b/src/main/resources/createrailwaysnavigator.mixins.json index 03e8b407..73b2f6f7 100644 --- a/src/main/resources/createrailwaysnavigator.mixins.json +++ b/src/main/resources/createrailwaysnavigator.mixins.json @@ -6,9 +6,11 @@ "compatibilityLevel": "JAVA_17", "refmap": "createrailwaysnavigator.refmap.json", "mixins": [ - "ScheduleDataAccessor" + "ScheduleDataAccessor", + "MountedStorageManagerMixin" ], "client": [ + "BakedGlyphAccessor" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/data/createrailwaysnavigator/advancements/advanced_display.json b/src/main/resources/data/createrailwaysnavigator/advancements/advanced_display.json new file mode 100644 index 00000000..c7f31437 --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/advancements/advanced_display.json @@ -0,0 +1,31 @@ +{ + "display": { + "icon": { + "item": "createrailwaysnavigator:advanced_display" + }, + "title": { + "translate": "advancement.createrailwaysnavigator.advanced_display" + }, + "description": { + "color": "#DBA213", + "translate": "advancement.createrailwaysnavigator.advanced_display.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true + }, + "parent": "create:display_board_0", + "criteria": { + "requirement": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "createrailwaysnavigator:advanced_displays" + } + ] + } + } + } + } + \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/advancements/root.json b/src/main/resources/data/createrailwaysnavigator/advancements/navigator.json similarity index 68% rename from src/main/resources/data/createrailwaysnavigator/advancements/root.json rename to src/main/resources/data/createrailwaysnavigator/advancements/navigator.json index 166d81b5..25e6f7eb 100644 --- a/src/main/resources/data/createrailwaysnavigator/advancements/root.json +++ b/src/main/resources/data/createrailwaysnavigator/advancements/navigator.json @@ -4,16 +4,17 @@ "item": "createrailwaysnavigator:navigator" }, "title": { - "translate": "advancement.createrailwaysnavigator.root" + "translate": "advancement.createrailwaysnavigator.navigator" }, "description": { - "translate": "advancement.createrailwaysnavigator.root.description" + "color": "#DBA213", + "translate": "advancement.createrailwaysnavigator.navigator.description" }, - "frame": "task", + "frame": "goal", "show_toast": true, "announce_to_chat": true }, - "parent": "create:display_board_0", + "parent": "create:conductor", "criteria": { "requirement": { "trigger": "minecraft:inventory_changed", diff --git a/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display.json b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display.json new file mode 100644 index 00000000..ce40d833 --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "createrailwaysnavigator:advanced_display" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] + } \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display_block.json b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display_block.json new file mode 100644 index 00000000..b2c9edaa --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display_block.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "createrailwaysnavigator:advanced_display_block" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] + } \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display_panel.json b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display_panel.json new file mode 100644 index 00000000..528643ed --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display_panel.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "createrailwaysnavigator:advanced_display_panel" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] + } \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display_small.json b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display_small.json new file mode 100644 index 00000000..feccab35 --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/advanced_display_small.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "createrailwaysnavigator:advanced_display_small" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/train_station_clock.json b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/train_station_clock.json new file mode 100644 index 00000000..94eb4c4b --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/loot_tables/blocks/train_station_clock.json @@ -0,0 +1,150 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "bonus_rolls": 0, + "entries": [ + { + "type": "minecraft:item", + "name": "createrailwaysnavigator:train_station_clock", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "createrailwaysnavigator:train_station_clock", + "conditions": [ + { + "condition": "minecraft:random_chance", + "chance": 0.5 + } + ] + }, + { + "type": "minecraft:item", + "name": "minecraft:gold_nugget", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "min": 1, + "max": 9 + } + } + ], + "conditions": [ + { + "condition": "minecraft:random_chance", + "chance": 0.3 + } + ] + }, + { + "type": "minecraft:item", + "name": "create:crushed_raw_gold", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "min": 1, + "max": 3 + } + } + ], + "conditions": [ + { + "condition": "minecraft:random_chance", + "chance": 0.3 + } + ] + }, + { + "type": "minecraft:item", + "name": "minecraft:gold_ingot", + "conditions": [ + { + "condition": "minecraft:random_chance", + "chance": 0.1 + } + ] + }, + { + "type": "minecraft:item", + "name": "minecraft:iron_nugget", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "min": 3, + "max": 15 + } + } + ], + "conditions": [ + { + "condition": "minecraft:random_chance", + "chance": 0.5 + } + ] + }, + { + "type": "minecraft:item", + "name": "create:crushed_raw_iron", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "min": 2, + "max": 3 + } + } + ], + "conditions": [ + { + "condition": "minecraft:random_chance", + "chance": 0.5 + } + ] + } + ], + "conditions": [ + { + "condition": "minecraft:inverted", + "term": { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1, + "max": 0 + } + } + ] + } + } + } + ] + } + ] + } + ] +} diff --git a/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display.json b/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display.json new file mode 100644 index 00000000..14c79a99 --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "AZA", + "BBB", + "AZA" + ], + "key": { + "A": { + "item": "create:andesite_alloy" + }, + "Z": { + "tag": "forge:plates/obsidian" + }, + "B": { + "item": "create:display_board" + } + }, + "result": { + "item": "createrailwaysnavigator:advanced_display", + "count": 6 + } + } \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display_block.json b/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display_block.json new file mode 100644 index 00000000..3c30096d --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display_block.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "BBB", + "BZB", + "BBB" + ], + "key": { + "B": { + "item": "createrailwaysnavigator:advanced_display" + }, + "Z": { + "tag": "forge:ingots/zinc" + } + }, + "result": { + "item": "createrailwaysnavigator:advanced_display_block", + "count": 6 + } + } \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display_panel.json b/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display_panel.json new file mode 100644 index 00000000..36c8dd66 --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display_panel.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "BB", + "BB" + ], + "key": { + "B": { + "item": "createrailwaysnavigator:advanced_display" + } + }, + "result": { + "item": "createrailwaysnavigator:advanced_display_panel", + "count": 8 + } + } \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display_small.json b/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display_small.json new file mode 100644 index 00000000..824736bc --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/recipes/advanced_display_small.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "BB" + ], + "key": { + "B": { + "item": "createrailwaysnavigator:advanced_display" + } + }, + "result": { + "item": "createrailwaysnavigator:advanced_display_small", + "count": 4 + } + } \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/recipes/navigator.json b/src/main/resources/data/createrailwaysnavigator/recipes/navigator.json index 6b851787..21f8f85b 100644 --- a/src/main/resources/data/createrailwaysnavigator/recipes/navigator.json +++ b/src/main/resources/data/createrailwaysnavigator/recipes/navigator.json @@ -6,16 +6,16 @@ "item": "create:andesite_alloy" }, "I": { - "item": "create:iron_sheet" + "tag": "forge:plates/iron" }, "G": { - "item": "minecraft:glass_pane" + "tag": "forge:glass_panes/colorless" }, "P": { "item": "create:precision_mechanism" }, "C": { - "item": "create:copper_sheet" + "tag": "forge:plates/copper" } }, "pattern": [ diff --git a/src/main/resources/data/createrailwaysnavigator/recipes/train_station_clock.json b/src/main/resources/data/createrailwaysnavigator/recipes/train_station_clock.json new file mode 100644 index 00000000..5ce6ff7b --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/recipes/train_station_clock.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " I ", + "ICI", + " P " + ], + "key": { + "I": { + "tag": "forge:plates/iron" + }, + "C": { + "item": "minecraft:clock" + }, + "P": { + "item": "create:precision_mechanism" + } + }, + "result": { + "item": "createrailwaysnavigator:train_station_clock", + "count": 1 + } + } \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/tags/blocks/advanced_displays.json b/src/main/resources/data/createrailwaysnavigator/tags/blocks/advanced_displays.json new file mode 100644 index 00000000..e143ca8f --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/tags/blocks/advanced_displays.json @@ -0,0 +1,9 @@ +{ + "replace": false, + "values": [ + "createrailwaysnavigator:advanced_display", + "createrailwaysnavigator:advanced_display_block", + "createrailwaysnavigator:advanced_display_panel", + "createrailwaysnavigator:advanced_display_small" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/createrailwaysnavigator/tags/items/advanced_displays.json b/src/main/resources/data/createrailwaysnavigator/tags/items/advanced_displays.json new file mode 100644 index 00000000..e143ca8f --- /dev/null +++ b/src/main/resources/data/createrailwaysnavigator/tags/items/advanced_displays.json @@ -0,0 +1,9 @@ +{ + "replace": false, + "values": [ + "createrailwaysnavigator:advanced_display", + "createrailwaysnavigator:advanced_display_block", + "createrailwaysnavigator:advanced_display_panel", + "createrailwaysnavigator:advanced_display_small" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json new file mode 100644 index 00000000..53ba1a59 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -0,0 +1,10 @@ +{ + "replace": false, + "values": [ + "createrailwaysnavigator:advanced_display", + "createrailwaysnavigator:advanced_display_block", + "createrailwaysnavigator:advanced_display_panel", + "createrailwaysnavigator:advanced_display_small", + "createrailwaysnavigator:train_station_clock" + ] +} \ No newline at end of file diff --git a/update.json b/update.json index fd0f98a4..2b594be5 100644 --- a/update.json +++ b/update.json @@ -1,7 +1,7 @@ { "promos": { - "1.20.1-latest": "0.3.0-1.20.1", - "1.20.1-recommended": "0.3.0-1.20.1" + "1.20.1-latest": "0.4.0-1.20.1", + "1.20.1-recommended": "0.4.0-1.20.1" }, "homepage": "https://www.curseforge.com/minecraft/mc-mods/create-railways-navigator" } \ No newline at end of file