Special Delivery

- Added train schedule instructions for delivering or retrieving packages
- Moved schedule instruction logic into their respective subclasses
- Fixed schedule screen no longer showing tooltips in the entry editor
This commit is contained in:
simibubi 2025-01-11 18:14:30 +01:00
parent dfb0ff65c3
commit 0e69f537f2
14 changed files with 555 additions and 68 deletions

View file

@ -1,4 +1,4 @@
// 1.20.1 2025-01-08T12:42:08.2186069 Registrate Provider for create [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)]
// 1.20.1 2025-01-11T18:12:51.5905299 Registrate Provider for create [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)]
60bbdf92d2ac9824ea6144955c74043a6005f79d assets/create/blockstates/acacia_window.json
6a67703c2697d81b7dc83e9d72a66f9c9ff08383 assets/create/blockstates/acacia_window_pane.json
c3ae87b62e81d8e9476eccd793bb1548d74c66a1 assets/create/blockstates/adjustable_chain_gearshift.json
@ -642,8 +642,8 @@ b0d8f08968763a5f74e5cd5644377a76a9f39753 assets/create/blockstates/yellow_toolbo
fe8c497aacc641c2f01cec90bba9f19e59cc2ed2 assets/create/blockstates/yellow_valve_handle.json
e819e93fdcbe9fd9c050a052d2718ff3b3539365 assets/create/blockstates/zinc_block.json
64121dcb216381c83b4fe28aa361ea07c24c9ad0 assets/create/blockstates/zinc_ore.json
c1d7b1f496afa2f971078caf90f20255292d760b assets/create/lang/en_ud.json
ce3c58e8401db1c42f3e1187bec1343fbf15009e assets/create/lang/en_us.json
913f3794fb772a0736ae66dff722b3c468bcde79 assets/create/lang/en_ud.json
1f6031cb19932ad54d645fbca1f2773385dd47ed assets/create/lang/en_us.json
a97e1060e00ae701a02e39cd4ef8054cf345fac4 assets/create/models/block/acacia_window.json
103e032c0b1a0a6a27c67da8c91179a564bd281c assets/create/models/block/acacia_window_pane_noside.json
fb00b627abda76ad4fea867ca57dbfadd24fffa3 assets/create/models/block/acacia_window_pane_noside_alt.json

View file

@ -1692,6 +1692,12 @@
"create.ponder.cart_assembler_rails.text_2": "pǝɹǝʍoԀ s,ʇı ןıʇun ǝɔɐןd uı pןǝɥ ǝq ןןıʍ sʇɹɐɔ ǝɥʇ 'ןıɐᴚ ɹǝןןoɹʇuoƆ ɹo pǝɹǝʍoԀ uo uǝɥM",
"create.ponder.cart_assembler_rails.text_3": "ɹoɥɔuɐ ǝɥʇ sɐ pǝsn ǝq uɐɔ sʇɹɐɔǝuıW ɟo sǝdʎʇ ɹǝɥʇO",
"create.ponder.cart_assembler_rails.text_4": "sǝıɹoʇuǝʌuı pǝɥɔɐʇʇɐ ʎuɐ ɯoɹɟ ןǝnɟ buıןןnd 'pǝɹǝʍod sǝʌןǝsɯǝɥʇ dǝǝʞ ןןıʍ sʇɹɐƆ ǝɔɐuɹnℲ",
"create.ponder.chain_conveyor.header": "sɹoʎǝʌuoƆ uıɐɥƆ buısn ǝɔɹoɟ ןɐuoıʇɐʇoɹ buıʎɐןǝᴚ",
"create.ponder.chain_conveyor.text_1": "ɯǝɥʇ ʇɔǝuuoɔ oʇ suıɐɥɔ ɥʇıʍ sɹoʎǝʌuoɔ oʍʇ ʞɔıןɔ-ʇɥbıᴚ",
"create.ponder.chain_conveyor.text_2": "˙˙ʎןqıןɟ ʎɹǝʌ ɹǝɥʇo ɥɔɐǝ oʇ ɹǝʍod ןɐuoıʇɐʇoɹ ʎɐןǝɹ ǝsǝɥ⟘",
"create.ponder.chain_conveyor.text_3": "ɯǝɥʇ ʍoןǝq ɹo ǝʌoqɐ sʇɟɐɥs oʇ ʇɔǝuuoɔ puɐ˙˙",
"create.ponder.chain_conveyor.text_4": "uıɐɥɔ ǝɥʇ uo buıןןǝʌɐɹʇ ʇɹɐʇs oʇ ɥɔuǝɹʍ ɐ buıpןoɥ ʞɔıןɔ-ʇɥbıᴚ",
"create.ponder.chain_conveyor.text_5": "ʇı ʍoןןoɟ oʇ uıɐɥɔ ɐ spɹɐʍoʇ ǝɔɐɟ 'uoıʇɔunظ ɐ ʇⱯ",
"create.ponder.chain_drive.header": "sǝʌıɹᗡ uıɐɥƆ ɥʇıʍ ǝɔɹoɟ ןɐuoıʇɐʇoɹ buıʎɐןǝᴚ",
"create.ponder.chain_drive.text_1": "ʍoɹ ɐ uı ɹǝɥʇo ɥɔɐǝ oʇ uoıʇɐʇoɹ ʎɐןǝɹ sǝʌıɹᗡ uıɐɥƆ",
"create.ponder.chain_drive.text_2": "uoıʇɔǝɹıp ǝɯɐs ǝɥʇ uı ǝʇɐʇoɹ ןןıʍ sıɥʇ ǝʞıן pǝʇɔǝuuoɔ sʇɟɐɥs ןןⱯ",
@ -2124,6 +2130,46 @@
"create.ponder.nixie_tube.text_1": "ɥʇbuǝɹʇs ןɐubıs ǝɥʇ ʎɐןdsıp ןןıʍ sǝqn⟘ ǝıxıN 'ǝuoʇspǝᴚ ʎq pǝɹǝʍod uǝɥM",
"create.ponder.nixie_tube.text_2": "pǝʎɐןdsıp ǝq uɐɔ ʇxǝʇ ɯoʇsnɔ 'spɹɐoqdıןƆ uǝʇʇıɹʍ buıs∩",
"create.ponder.nixie_tube.text_3": "ɹnoןoɔ ʎɐןdsıp ɹıǝɥʇ ǝbuɐɥɔ oʇ ǝʎᗡ ɥʇıʍ ʞɔıןƆ-ʇɥbıᴚ",
"create.ponder.package_frogport.header": "sʇɹodboɹℲ ɥʇıʍ sǝbɐʞɔɐd buıʇɹodsuɐɹ⟘",
"create.ponder.package_frogport.text_1": "ʎqɹɐǝu ʇɹodboɹℲ ǝɥʇ ǝɔɐןd puɐ ɹoʎǝʌuoƆ uıɐɥƆ ɐ ʞɔıןɔ-ʇɥbıᴚ",
"create.ponder.package_frogport.text_10": "ʞɹoʍʇǝu uıɐɥɔ ǝɥʇ uo boɹɟ buıɥɔʇɐɯ ɐ oʇ ɥʇɐd ɹıǝɥʇ puıɟ sǝbɐʞɔɐԀ",
"create.ponder.package_frogport.text_11": "ɹǝʇǝԀ",
"create.ponder.package_frogport.text_12": "ɹǝʇǝԀ →",
"create.ponder.package_frogport.text_13": "ɯǝɥʇ ʍoןǝq sǝıɹoʇuǝʌuı ɥʇıʍ ǝɔɐɟɹǝʇuı ʎןʇɔǝɹıp uɐɔ sʇɹodboɹℲ",
"create.ponder.package_frogport.text_14": ןʇɔǝɹıp pǝddıɥs puɐ pǝʞɔɐd ǝq uɐɔ sɯǝʇı 'sɹǝbɐʞɔɐd ɥʇıʍ sʞɹoʍ sıɥ⟘",
"create.ponder.package_frogport.text_15": "ʇɹǝqןⱯ",
"create.ponder.package_frogport.text_16": "ɹǝʇǝԀ",
"create.ponder.package_frogport.text_17": ",ɹǝʇǝԀ, oʇ sǝbɐʞɔɐd sǝssǝɹppⱯ",
"create.ponder.package_frogport.text_18": "ssǝɹppɐ ɹıǝɥʇ ʇɔǝןןoɔ oʇ pɹɐoqdıןɔ ɐ ɥʇıʍ sʇɹodboɹℲ ʞɔıןɔ-ʇɥbıᴚ",
"create.ponder.package_frogport.text_19": "sI∩ ɹǝɥʇo uı sʇnduı ssǝɹppɐ ǝʇǝןdɯoɔ-oʇnɐ dןǝɥ uɐɔ sǝɯɐu pǝʇɔǝןןoɔ ɥʇıʍ spɹɐoqdıןƆ",
"create.ponder.package_frogport.text_2": "I∩ ʎɹoʇuǝʌuı ɹıǝɥʇ uı ǝɯɐu ɐ uǝʌıb ǝq uɐɔ ʎǝɥ⟘",
"create.ponder.package_frogport.text_3": "˙˙ǝɯɐu ʇuǝɹǝɟɟıp ɐ oʇ pǝssǝɹppɐ sı ǝbɐʞɔɐd ɐ ɟI",
"create.ponder.package_frogport.text_4": "ʇɹǝqןⱯ",
"create.ponder.package_frogport.text_5": "ɹǝʇǝԀ →",
"create.ponder.package_frogport.text_6": "ɹoʎǝʌuoɔ ǝɥʇ uo ǝbɐʞɔɐd ǝɥʇ ǝɔɐןd ןןıʍ ʇɹodboɹℲ ǝɥʇ˙˙",
"create.ponder.package_frogport.text_7": "uoıʇɐuıʇsǝp pıןɐʌ ou ǝʌɐɥ ʎǝɥʇ ɟı ǝɔɐןd uı uıds sǝbɐʞɔɐԀ",
"create.ponder.package_frogport.text_8": "ʞɹoʍʇǝu uıɐɥɔ ǝɥʇ uo ǝɹǝɥʍʎuɐ pǝppɐ ǝq uɐɔ sʇɹodboɹℲ ǝɹoW",
"create.ponder.package_frogport.text_9": "ɹǝʇǝԀ",
"create.ponder.packager.header": "sǝbɐʞɔɐd buıddɐɹʍun puɐ buıʇɐǝɹƆ",
"create.ponder.packager.text_1": "ʇǝbɹɐʇ pןnoɥs ʎǝɥʇ ʎɹoʇuǝʌuı ǝɥʇ oʇ ʇxǝu sɹǝbɐʞɔɐd ǝɔɐןԀ",
"create.ponder.packager.text_2": "ǝbɐʞɔɐd ɐ oʇuı ʎɹoʇuǝʌuı ǝɥʇ ɯoɹɟ sɯǝʇı ʞɔɐd ןןıʍ ʇı 'ɹǝʍod ǝuoʇspǝɹ uǝʌı⅁",
"create.ponder.packager.text_3": "ɯǝʇı ɹǝɥʇo ʎuɐ ǝʞıן pǝʇɹodsuɐɹʇ puɐ dn pǝʞɔıd ǝq uɐɔ ǝsǝɥ⟘",
"create.ponder.packager.text_4": "ʎɹoʇuǝʌuı ǝɥʇ oʇuı sʇuǝʇuoɔ ǝɥʇ buıʞɔɐdun 'pǝʎoɹʇsǝp ǝq ןןıʍ pǝʇɹǝsuı sǝbɐʞɔɐԀ",
"create.ponder.packager.text_5": "ןןnℲ",
"create.ponder.packager.text_6": "ʞɔɐdun ʎןןnɟ ʇouuɐɔ ʎǝɥʇ sǝbɐʞɔɐd ʇdǝɔɔɐ ʇou ןןıʍ sɹǝbɐʞɔɐԀ",
"create.ponder.packager_address.header": "ssǝɹppɐ uɐ ɥʇıʍ sǝbɐʞɔɐd buıʇnoᴚ",
"create.ponder.packager_address.text_1": "ǝsnoɥǝɹɐM",
"create.ponder.packager_address.text_10": ןǝq ɐ oʇuo ʇɥbıɐɹʇs sǝbɐʞɔɐd dɐɹʍun uɐɔ sʍɐs ןɐɔıuɐɥɔǝɯ 'ssǝuʇɔɐdɯoɔ ɹoℲ",
"create.ponder.packager_address.text_11": "sǝıʇıןıqɐdɐɔ buıʇnoɹ ǝbɐʞɔɐd ǝʌɐɥ sǝxoqʇsoԀ puɐ sʇɹodboɹℲ 'sɹǝʇןıɟ ǝsoɥʇ ɯoɹɟ ǝpısⱯ",
"create.ponder.packager_address.text_12": "ɹnoıʌɐɥǝq ɹıǝɥʇ ʇnoqɐ ǝɹoɯ ʇno puıɟ oʇ ɯǝɥʇ ʇɔǝdsuI",
"create.ponder.packager_address.text_2": "˙˙ɹǝbɐʞɔɐd ɐ uo pǝɔɐןd sı ubıs ɐ uǝɥM",
"create.ponder.packager_address.text_3": "ǝsnoɥǝɹɐM →",
"create.ponder.packager_address.text_4": "ssǝɹppɐ ɹıǝɥʇ sɐ ʇxǝʇ ɟo ǝuıן uǝʇʇıɹʍ ǝɥʇ ʎɹɹɐɔ ןןıʍ sǝbɐʞɔɐd pǝʇɐǝɹƆ",
"create.ponder.packager_address.text_5": "ssǝɹppɐ ɹıǝɥʇ uo pǝsɐq sǝbɐʞɔɐd ǝʇnoɹ sɹǝʇןıɟ ǝbɐʞɔɐԀ",
"create.ponder.packager_address.text_6": "ǝsnoɥǝɹɐM →",
"create.ponder.packager_address.text_7": "ʎɹoʇɔɐℲ",
"create.ponder.packager_address.text_8": "ʎɹoʇɔɐℲ →",
"create.ponder.packager_address.text_9": "ʎɹoʇɔɐℲ",
"create.ponder.piston_pole.header": "sǝןoԀ uoısuǝʇxƎ uoʇsıԀ",
"create.ponder.piston_pole.text_1": "ǝʌoɯ ʇouuɐɔ uoʇsıԀ ןɐɔıuɐɥɔǝW ɐ 'sǝןoԀ pǝɥɔɐʇʇɐ ʇnoɥʇıM",
"create.ponder.piston_pole.text_2": "ǝbuɐᴚ uoısuǝʇxƎ ǝɥʇ sǝuıɯɹǝʇǝp ʞɔɐq sʇı ʇɐ pǝppɐ ǝןod ɟo ɥʇbuǝꞀ ǝɥ⟘",
@ -2596,6 +2642,10 @@
"create.schedule.condition.unloaded.status": "pɐoןun ʞunɥɔ ɹoɟ buıʇıɐM",
"create.schedule.condition_type": ":ɹǝʇɟɐ/ɟı ǝnuıʇuoƆ",
"create.schedule.continued": "pǝɯnsǝɹ ǝןnpǝɥɔS",
"create.schedule.instruction.address_filter_edit_box": "ssǝɹppⱯ sıɥʇ ɥʇıʍ sǝbɐʞɔɐԀ ǝʌǝıɹʇǝᴚ",
"create.schedule.instruction.address_filter_edit_box_1": "pɹɐɔpןıʍ ʇxǝʇ ɐ sɐ * ǝs∩",
"create.schedule.instruction.address_filter_edit_box_2": "ʇı ʇɔǝןןoɔ oʇ ǝɹǝɥʍʎuɐ ǝʇɐbıʌɐu ʎɐɯ uıɐɹ⟘",
"create.schedule.instruction.address_filter_edit_box_3": "uɹnʇǝɹ ʇı ǝʞɐɯ oʇ uoıʇɔnɹʇsuı ɹǝɥʇouɐ ppⱯ",
"create.schedule.instruction.destination": "uoıʇɐʇS oʇ ןǝʌɐɹ⟘",
"create.schedule.instruction.destination.summary": ":doʇS ʇxǝN",
"create.schedule.instruction.editor": "ɹoʇıpƎ uoıʇɔnɹʇsuI",
@ -2606,6 +2656,14 @@
"create.schedule.instruction.name_edit_box": "ǝןʇı⟘ ǝןnpǝɥɔS",
"create.schedule.instruction.name_edit_box_1": "sʎɐןdsıp uo uʍoɥs ʇxǝʇ sʇɔǝɟɟⱯ",
"create.schedule.instruction.name_edit_box_2": ɯɐu s,uoıʇɐuıʇsǝp ʇxǝu oʇ sʇןnɐɟǝᗡ",
"create.schedule.instruction.package_delivery": "ǝbɐʞɔɐԀ ɹǝʌıןǝᗡ",
"create.schedule.instruction.package_delivery.summary": "obɹɐɔ uı ǝbɐʞɔɐd ʇsɹıɟ ɹǝʌıןǝᗡ",
"create.schedule.instruction.package_delivery.summary_1": "ɥʇıʍ uoıʇɐʇs ǝɥʇ oʇ sǝʌıɹᗡ",
"create.schedule.instruction.package_delivery.summary_2": "xoqʇsod ʇɔǝɹɹoɔ ǝɥʇ",
"create.schedule.instruction.package_retrieval": "ǝbɐʞɔɐԀ ǝʌǝıɹʇǝᴚ",
"create.schedule.instruction.package_retrieval.summary": ":oʇ pǝssǝɹppɐ ǝbɐʞɔɐd ɐ ɥɔʇǝℲ",
"create.schedule.instruction.package_retrieval.summary_1": "ɥʇıʍ xoqʇsod ɐ oʇ sǝʌıɹᗡ",
"create.schedule.instruction.package_retrieval.summary_2": "ǝbɐʞɔɐd pǝɹǝʌıןǝpun uɐ",
"create.schedule.instruction.rename": "ǝןʇı⟘ ǝןnpǝɥɔS ǝʇɐpd∩",
"create.schedule.instruction.rename.summary": ":ǝןʇı⟘ ʍǝN",
"create.schedule.instruction.throttle": "pǝǝdS xɐW ʇıɯıꞀ",

View file

@ -1692,6 +1692,12 @@
"create.ponder.cart_assembler_rails.text_2": "When on Powered or Controller Rail, the carts will be held in place until it's Powered",
"create.ponder.cart_assembler_rails.text_3": "Other types of Minecarts can be used as the anchor",
"create.ponder.cart_assembler_rails.text_4": "Furnace Carts will keep themselves powered, pulling fuel from any attached inventories",
"create.ponder.chain_conveyor.header": "Relaying rotational force using Chain Conveyors",
"create.ponder.chain_conveyor.text_1": "Right-click two conveyors with chains to connect them",
"create.ponder.chain_conveyor.text_2": "These relay rotational power to each other very flexibly..",
"create.ponder.chain_conveyor.text_3": "..and connect to shafts above or below them",
"create.ponder.chain_conveyor.text_4": "Right-click holding a wrench to start travelling on the chain",
"create.ponder.chain_conveyor.text_5": "At a junction, face towards a chain to follow it",
"create.ponder.chain_drive.header": "Relaying rotational force with Chain Drives",
"create.ponder.chain_drive.text_1": "Chain Drives relay rotation to each other in a row",
"create.ponder.chain_drive.text_2": "All shafts connected like this will rotate in the same direction",
@ -2124,6 +2130,46 @@
"create.ponder.nixie_tube.text_1": "When powered by Redstone, Nixie Tubes will display the signal strength",
"create.ponder.nixie_tube.text_2": "Using written Clipboards, custom text can be displayed",
"create.ponder.nixie_tube.text_3": "Right-Click with Dye to change their display colour",
"create.ponder.package_frogport.header": "Transporting packages with Frogports",
"create.ponder.package_frogport.text_1": "Right-click a Chain Conveyor and place the Frogport nearby",
"create.ponder.package_frogport.text_10": "Packages find their path to a matching frog on the chain network",
"create.ponder.package_frogport.text_11": "Peter",
"create.ponder.package_frogport.text_12": "→ Peter",
"create.ponder.package_frogport.text_13": "Frogports can directly interface with inventories below them",
"create.ponder.package_frogport.text_14": "This works with packagers, items can be packed and shipped directly",
"create.ponder.package_frogport.text_15": "Albert",
"create.ponder.package_frogport.text_16": "Peter",
"create.ponder.package_frogport.text_17": "Addresses packages to 'Peter'",
"create.ponder.package_frogport.text_18": "Right-click Frogports with a clipboard to collect their address",
"create.ponder.package_frogport.text_19": "Clipboards with collected names can help auto-complete address inputs in other UIs",
"create.ponder.package_frogport.text_2": "They can be given a name in their inventory UI",
"create.ponder.package_frogport.text_3": "If a package is addressed to a different name..",
"create.ponder.package_frogport.text_4": "Albert",
"create.ponder.package_frogport.text_5": "→ Peter",
"create.ponder.package_frogport.text_6": "..the Frogport will place the package on the conveyor",
"create.ponder.package_frogport.text_7": "Packages spin in place if they have no valid destination",
"create.ponder.package_frogport.text_8": "More Frogports can be added anywhere on the chain network",
"create.ponder.package_frogport.text_9": "Peter",
"create.ponder.packager.header": "Creating and unwrapping packages",
"create.ponder.packager.text_1": "Place packagers next to the inventory they should target",
"create.ponder.packager.text_2": "Given redstone power, it will pack items from the inventory into a package",
"create.ponder.packager.text_3": "These can be picked up and transported like any other item",
"create.ponder.packager.text_4": "Packages inserted will be destroyed, unpacking the contents into the inventory",
"create.ponder.packager.text_5": "Full",
"create.ponder.packager.text_6": "Packagers will not accept packages they cannot fully unpack",
"create.ponder.packager_address.header": "Routing packages with an address",
"create.ponder.packager_address.text_1": "Warehouse",
"create.ponder.packager_address.text_10": "For compactness, mechanical saws can unwrap packages straight onto a belt",
"create.ponder.packager_address.text_11": "Aside from those filters, Frogports and Postboxes have package routing capabilities",
"create.ponder.packager_address.text_12": "Inspect them to find out more about their behaviour",
"create.ponder.packager_address.text_2": "When a sign is placed on a packager..",
"create.ponder.packager_address.text_3": "→ Warehouse",
"create.ponder.packager_address.text_4": "Created packages will carry the written line of text as their address",
"create.ponder.packager_address.text_5": "Package filters route packages based on their address",
"create.ponder.packager_address.text_6": "→ Warehouse",
"create.ponder.packager_address.text_7": "Factory",
"create.ponder.packager_address.text_8": "→ Factory",
"create.ponder.packager_address.text_9": "Factory",
"create.ponder.piston_pole.header": "Piston Extension Poles",
"create.ponder.piston_pole.text_1": "Without attached Poles, a Mechanical Piston cannot move",
"create.ponder.piston_pole.text_2": "The Length of pole added at its back determines the Extension Range",
@ -2596,6 +2642,10 @@
"create.schedule.condition.unloaded.status": "Waiting for chunk unload",
"create.schedule.condition_type": "Continue if/after:",
"create.schedule.continued": "Schedule resumed",
"create.schedule.instruction.address_filter_edit_box": "Retrieve Packages with this Address",
"create.schedule.instruction.address_filter_edit_box_1": "Use * as a text wildcard",
"create.schedule.instruction.address_filter_edit_box_2": "Train may navigate anywhere to collect it",
"create.schedule.instruction.address_filter_edit_box_3": "Add another instruction to make it return",
"create.schedule.instruction.destination": "Travel to Station",
"create.schedule.instruction.destination.summary": "Next Stop:",
"create.schedule.instruction.editor": "Instruction Editor",
@ -2606,6 +2656,14 @@
"create.schedule.instruction.name_edit_box": "Schedule Title",
"create.schedule.instruction.name_edit_box_1": "Affects text shown on displays",
"create.schedule.instruction.name_edit_box_2": "Defaults to next destination's name",
"create.schedule.instruction.package_delivery": "Deliver Package",
"create.schedule.instruction.package_delivery.summary": "Deliver first package in cargo",
"create.schedule.instruction.package_delivery.summary_1": "Drives to the station with",
"create.schedule.instruction.package_delivery.summary_2": "the correct postbox",
"create.schedule.instruction.package_retrieval": "Retrieve Package",
"create.schedule.instruction.package_retrieval.summary": "Fetch a package addressed to:",
"create.schedule.instruction.package_retrieval.summary_1": "Drives to a postbox with",
"create.schedule.instruction.package_retrieval.summary_2": "an undelivered package",
"create.schedule.instruction.rename": "Update Schedule Title",
"create.schedule.instruction.rename.summary": "New Title:",
"create.schedule.instruction.throttle": "Limit Max Speed",

View file

@ -44,6 +44,13 @@ public class TrainStatus {
displayInformation("no_match", false, filter);
navigation = true;
}
public void failedPackageNoTarget(String address) {
if (navigation)
return;
displayInformation("no_package_target", false, address);
navigation = true;
}
public void successfulNavigation() {
if (!navigation)

View file

@ -17,7 +17,9 @@ import com.simibubi.create.content.trains.schedule.condition.StationUnloadedCond
import com.simibubi.create.content.trains.schedule.condition.TimeOfDayCondition;
import com.simibubi.create.content.trains.schedule.destination.ChangeThrottleInstruction;
import com.simibubi.create.content.trains.schedule.destination.ChangeTitleInstruction;
import com.simibubi.create.content.trains.schedule.destination.DeliverPackagesInstruction;
import com.simibubi.create.content.trains.schedule.destination.DestinationInstruction;
import com.simibubi.create.content.trains.schedule.destination.FetchPackagesInstruction;
import com.simibubi.create.content.trains.schedule.destination.ScheduleInstruction;
import net.createmod.catnip.utility.NBTHelper;
@ -38,6 +40,8 @@ public class Schedule {
static {
registerInstruction("destination", DestinationInstruction::new);
registerInstruction("package_delivery", DeliverPackagesInstruction::new);
registerInstruction("package_retrieval", FetchPackagesInstruction::new);
registerInstruction("rename", ChangeTitleInstruction::new);
registerInstruction("throttle", ChangeThrottleInstruction::new);
registerCondition("delay", ScheduledDelay::new);

View file

@ -4,17 +4,14 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.regex.PatternSyntaxException;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.trains.display.GlobalTrainDisplayData.TrainDeparturePrediction;
import com.simibubi.create.content.trains.entity.Carriage;
import com.simibubi.create.content.trains.entity.Train;
import com.simibubi.create.content.trains.graph.DiscoveredPath;
import com.simibubi.create.content.trains.graph.EdgePointType;
import com.simibubi.create.content.trains.schedule.condition.ScheduleWaitCondition;
import com.simibubi.create.content.trains.schedule.condition.ScheduledDelay;
import com.simibubi.create.content.trains.schedule.destination.ChangeThrottleInstruction;
import com.simibubi.create.content.trains.schedule.destination.ChangeTitleInstruction;
import com.simibubi.create.content.trains.schedule.destination.DestinationInstruction;
import com.simibubi.create.content.trains.schedule.destination.ScheduleInstruction;
@ -38,30 +35,35 @@ public class ScheduleRuntime {
PRE_TRANSIT, IN_TRANSIT, POST_TRANSIT
}
Train train;
Schedule schedule;
public Train train;
public Schedule schedule;
public boolean isAutoSchedule;
public boolean paused;
public boolean completed;
public int currentEntry;
public State state;
public List<Integer> conditionProgress;
public List<CompoundTag> conditionContext;
public String currentTitle;
static final int INTERVAL = 40;
int cooldown;
List<Integer> conditionProgress;
List<CompoundTag> conditionContext;
String currentTitle;
int ticksInTransit;
List<Integer> predictionTicks;
public int ticksInTransit;
public List<Integer> predictionTicks;
public boolean displayLinkUpdateRequested;
private static final int INTERVAL = 40;
private int cooldown;
public ScheduleRuntime(Train train) {
this.train = train;
reset();
}
public void startCooldown() {
cooldown = INTERVAL;
}
public void destinationReached() {
if (state != State.IN_TRANSIT)
@ -142,7 +144,15 @@ public class ScheduleRuntime {
}
public void tickConditions(Level level) {
List<List<ScheduleWaitCondition>> conditions = schedule.entries.get(currentEntry).conditions;
ScheduleEntry entry = schedule.entries.get(currentEntry);
List<List<ScheduleWaitCondition>> conditions = entry.conditions;
if (!entry.instruction.supportsConditions()) {
state = State.PRE_TRANSIT;
currentEntry++;
return;
}
for (int i = 0; i < conditions.size(); i++) {
List<ScheduleWaitCondition> list = conditions.get(i);
int progress = conditionProgress.get(i);
@ -173,55 +183,7 @@ public class ScheduleRuntime {
public DiscoveredPath startCurrentInstruction() {
ScheduleEntry entry = schedule.entries.get(currentEntry);
ScheduleInstruction instruction = entry.instruction;
if (instruction instanceof DestinationInstruction destination) {
String regex = destination.getFilterForRegex();
boolean anyMatch = false;
ArrayList<GlobalStation> validStations = new ArrayList<>();
if (!train.hasForwardConductor() && !train.hasBackwardConductor()) {
train.status.missingConductor();
cooldown = INTERVAL;
return null;
}
try {
for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) {
if (!globalStation.name.matches(regex))
continue;
anyMatch = true;
validStations.add(globalStation);
}
} catch (PatternSyntaxException ignored) {}
DiscoveredPath best = train.navigation.findPathTo(validStations, Double.MAX_VALUE);
if (best == null) {
if (anyMatch)
train.status.failedNavigation();
else
train.status.failedNavigationNoTarget(destination.getFilter());
cooldown = INTERVAL;
return null;
}
return best;
}
if (instruction instanceof ChangeTitleInstruction title) {
currentTitle = title.getScheduleTitle();
state = State.PRE_TRANSIT;
currentEntry++;
return null;
}
if (instruction instanceof ChangeThrottleInstruction throttle) {
train.throttle = throttle.getThrottle();
state = State.PRE_TRANSIT;
currentEntry++;
return null;
}
return null;
return instruction.start(this);
}
public void setSchedule(Schedule schedule, boolean auto) {

View file

@ -57,6 +57,7 @@ import net.minecraft.network.chat.Component;
import net.minecraft.util.FormattedCharSequence;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.phys.Vec3;
@ -991,8 +992,15 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleMenu> im
for (int i = 0; i < Math.max(1, rendered.slotsTargeted()); i++) {
List<Component> secondLineTooltip = rendered.getSecondLineTooltip(i);
if (secondLineTooltip == null || (hoveredSlot != menu.getSlot(36 + i) || !hoveredSlot.getItem()
.isEmpty()))
if (secondLineTooltip == null)
continue;
Slot slot = menu.getSlot(36 + i);
if (slot == null || !slot.getItem()
.isEmpty())
continue;
if (mouseX < leftPos + slot.x || mouseX > leftPos + slot.x + 18)
continue;
if (mouseY < topPos + slot.y || mouseY > topPos + slot.y + 18)
continue;
renderActionTooltip(graphics, secondLineTooltip, mouseX, mouseY);
}

View file

@ -2,9 +2,14 @@ package com.simibubi.create.content.trains.schedule.destination;
import java.util.List;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.Create;
import com.simibubi.create.content.trains.graph.DiscoveredPath;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State;
import com.simibubi.create.foundation.gui.ModularGuiLineBuilder;
import com.simibubi.create.foundation.utility.CreateLang;
@ -83,4 +88,13 @@ public class ChangeThrottleInstruction extends ScheduleInstruction {
.withStyle(ChatFormatting.GRAY));
}
@Override
@Nullable
public DiscoveredPath start(ScheduleRuntime runtime) {
runtime.train.throttle = getThrottle();
runtime.state = State.PRE_TRANSIT;
runtime.currentEntry++;
return null;
}
}

View file

@ -2,8 +2,13 @@ package com.simibubi.create.content.trains.schedule.destination;
import java.util.List;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.Create;
import com.simibubi.create.content.trains.graph.DiscoveredPath;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State;
import com.simibubi.create.foundation.utility.CreateLang;
import net.createmod.catnip.utility.Pair;
@ -53,4 +58,13 @@ public class ChangeTitleInstruction extends TextScheduleInstruction {
.withStyle(ChatFormatting.DARK_GRAY));
}
@Override
@Nullable
public DiscoveredPath start(ScheduleRuntime runtime) {
runtime.currentTitle = getScheduleTitle();
runtime.state = State.PRE_TRANSIT;
runtime.currentEntry++;
return null;
}
}

View file

@ -0,0 +1,126 @@
package com.simibubi.create.content.trains.schedule.destination;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.box.PackageItem;
import com.simibubi.create.content.trains.entity.Carriage;
import com.simibubi.create.content.trains.entity.Train;
import com.simibubi.create.content.trains.graph.DiscoveredPath;
import com.simibubi.create.content.trains.graph.EdgePointType;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State;
import com.simibubi.create.content.trains.station.GlobalStation;
import com.simibubi.create.content.trains.station.GlobalStation.GlobalPackagePort;
import com.simibubi.create.foundation.utility.CreateLang;
import net.createmod.catnip.utility.Pair;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.items.IItemHandlerModifiable;
public class DeliverPackagesInstruction extends ScheduleInstruction {
@Override
public Pair<ItemStack, Component> getSummary() {
return Pair.of(getSecondLineIcon(), CreateLang.translateDirect("schedule.instruction.package_delivery"));
}
@Override
public ItemStack getSecondLineIcon() {
return AllBlocks.PACKAGE_POSTBOXES.get(DyeColor.WHITE)
.asStack();
}
@Override
public List<Component> getTitleAs(String type) {
return ImmutableList.of(CreateLang.translate("schedule.instruction.package_delivery.summary")
.style(ChatFormatting.GOLD)
.component(),
CreateLang.translateDirect("schedule.instruction.package_delivery.summary_1")
.withStyle(ChatFormatting.GRAY),
CreateLang.translateDirect("schedule.instruction.package_delivery.summary_2")
.withStyle(ChatFormatting.GRAY));
}
@Override
public ResourceLocation getId() {
return Create.asResource("package_delivery");
}
@Override
public boolean supportsConditions() {
return true;
}
@Override
@Nullable
public DiscoveredPath start(ScheduleRuntime runtime) {
boolean anyMatch = false;
String firstPackage = null;
ArrayList<GlobalStation> validStations = new ArrayList<>();
Train train = runtime.train;
if (!train.hasForwardConductor() && !train.hasBackwardConductor()) {
train.status.missingConductor();
runtime.startCooldown();
return null;
}
for (Carriage carriage : train.carriages) {
IItemHandlerModifiable carriageInventory = carriage.storage.getItems();
if (carriageInventory == null)
continue;
// Export to station
for (int slot = 0; slot < carriageInventory.getSlots(); slot++) {
ItemStack stack = carriageInventory.getStackInSlot(slot);
if (!PackageItem.isPackage(stack))
continue;
if (firstPackage == null)
firstPackage = PackageItem.getAddress(stack);
for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) {
for (Entry<BlockPos, GlobalPackagePort> port : globalStation.connectedPorts.entrySet()) {
if (!PackageItem.matchAddress(stack, port.getValue().address))
continue;
anyMatch = true;
validStations.add(globalStation);
break;
}
}
}
}
if (validStations.isEmpty()) {
if (firstPackage != null) {
train.status.failedPackageNoTarget(firstPackage);
runtime.startCooldown();
} else {
runtime.state = State.PRE_TRANSIT;
runtime.currentEntry++;
}
return null;
}
DiscoveredPath best = train.navigation.findPathTo(validStations, Double.MAX_VALUE);
if (best == null) {
if (anyMatch)
train.status.failedNavigation();
runtime.startCooldown();
return null;
}
return best;
}
}

View file

@ -1,12 +1,21 @@
package com.simibubi.create.content.trains.schedule.destination;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.PatternSyntaxException;
import javax.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.Create;
import com.simibubi.create.content.trains.entity.Train;
import com.simibubi.create.content.trains.graph.DiscoveredPath;
import com.simibubi.create.content.trains.graph.EdgePointType;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime;
import com.simibubi.create.content.trains.station.GlobalStation;
import com.simibubi.create.foundation.utility.CreateLang;
import net.createmod.catnip.utility.Pair;
@ -69,4 +78,40 @@ public class DestinationInstruction extends TextScheduleInstruction {
box.setFilter(s -> StringUtils.countMatches(s, '*') <= 3);
}
@Override
@Nullable
public DiscoveredPath start(ScheduleRuntime runtime) {
String regex = getFilterForRegex();
boolean anyMatch = false;
ArrayList<GlobalStation> validStations = new ArrayList<>();
Train train = runtime.train;
if (!train.hasForwardConductor() && !train.hasBackwardConductor()) {
train.status.missingConductor();
runtime.startCooldown();
return null;
}
try {
for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) {
if (!globalStation.name.matches(regex))
continue;
anyMatch = true;
validStations.add(globalStation);
}
} catch (PatternSyntaxException ignored) {}
DiscoveredPath best = train.navigation.findPathTo(validStations, Double.MAX_VALUE);
if (best == null) {
if (anyMatch)
train.status.failedNavigation();
else
train.status.failedNavigationNoTarget(getFilter());
runtime.startCooldown();
return null;
}
return best;
}
}

View file

@ -0,0 +1,170 @@
package com.simibubi.create.content.trains.schedule.destination;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.PatternSyntaxException;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.box.PackageItem;
import com.simibubi.create.content.logistics.box.PackageStyles;
import com.simibubi.create.content.logistics.packagePort.postbox.PostboxBlockEntity;
import com.simibubi.create.content.trains.entity.Carriage;
import com.simibubi.create.content.trains.entity.CarriageContraptionEntity;
import com.simibubi.create.content.trains.entity.Train;
import com.simibubi.create.content.trains.graph.DiscoveredPath;
import com.simibubi.create.content.trains.graph.EdgePointType;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State;
import com.simibubi.create.content.trains.station.GlobalStation;
import com.simibubi.create.content.trains.station.GlobalStation.GlobalPackagePort;
import com.simibubi.create.foundation.utility.CreateLang;
import net.createmod.catnip.utility.Pair;
import net.createmod.catnip.utility.lang.Components;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.items.IItemHandlerModifiable;
public class FetchPackagesInstruction extends TextScheduleInstruction {
@Override
public Pair<ItemStack, Component> getSummary() {
return Pair.of(getSecondLineIcon(), CreateLang.translateDirect("schedule.instruction.package_retrieval"));
}
@Override
public List<Component> getTitleAs(String type) {
return ImmutableList.of(CreateLang.translate("schedule.instruction.package_retrieval.summary")
.style(ChatFormatting.GOLD)
.component(), CreateLang.translateDirect("generic.in_quotes", Components.literal(getLabelText())),
CreateLang.translateDirect("schedule.instruction.package_retrieval.summary_1")
.withStyle(ChatFormatting.GRAY),
CreateLang.translateDirect("schedule.instruction.package_retrieval.summary_2")
.withStyle(ChatFormatting.GRAY));
}
@Override
public ItemStack getSecondLineIcon() {
return PackageStyles.getDefaultBox();
}
public String getFilter() {
return getLabelText();
}
public String getFilterForRegex() {
String filter = getFilter();
if (filter.isBlank())
return filter;
return "\\Q" + filter.replace("*", "\\E.*\\Q") + "\\E";
}
@Override
public List<Component> getSecondLineTooltip(int slot) {
return ImmutableList.of(CreateLang.translateDirect("schedule.instruction.address_filter_edit_box"),
CreateLang.translateDirect("schedule.instruction.address_filter_edit_box_1")
.withStyle(ChatFormatting.GRAY),
CreateLang.translateDirect("schedule.instruction.address_filter_edit_box_2")
.withStyle(ChatFormatting.DARK_GRAY),
CreateLang.translateDirect("schedule.instruction.address_filter_edit_box_3")
.withStyle(ChatFormatting.DARK_GRAY));
}
@Override
@OnlyIn(Dist.CLIENT)
protected void modifyEditBox(EditBox box) {
box.setFilter(s -> StringUtils.countMatches(s, '*') <= 3);
}
@Override
public ResourceLocation getId() {
return Create.asResource("package_retrieval");
}
@Override
public boolean supportsConditions() {
return false;
}
@Override
public DiscoveredPath start(ScheduleRuntime runtime) {
String regex = getFilterForRegex();
boolean anyMatch = false;
ArrayList<GlobalStation> validStations = new ArrayList<>();
Train train = runtime.train;
if (!train.hasForwardConductor() && !train.hasBackwardConductor()) {
train.status.missingConductor();
runtime.startCooldown();
return null;
}
Level level = null;
for (Carriage carriage : train.carriages) {
if (level == null) {
CarriageContraptionEntity entity = carriage.anyAvailableEntity();
if (entity != null && entity.level() instanceof ServerLevel sl)
level = sl;
}
}
for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) {
for (Entry<BlockPos, GlobalPackagePort> entry : globalStation.connectedPorts.entrySet()) {
GlobalPackagePort port = entry.getValue();
BlockPos pos = entry.getKey();
IItemHandlerModifiable postboxInventory = port.offlineBuffer;
if (level != null && level.isLoaded(pos)
&& level.getBlockEntity(pos) instanceof PostboxBlockEntity ppbe) {
postboxInventory = ppbe.inventory;
}
for (int slot = 0; slot < postboxInventory.getSlots(); slot++) {
ItemStack stack = postboxInventory.getStackInSlot(slot);
if (!PackageItem.isPackage(stack))
continue;
if (PackageItem.matchAddress(stack, port.address))
continue;
try {
if (!PackageItem.getAddress(stack)
.matches(regex))
continue;
anyMatch = true;
validStations.add(globalStation);
} catch (PatternSyntaxException ignored) {
}
}
}
}
if (validStations.isEmpty()) {
runtime.startCooldown();
runtime.state = State.PRE_TRANSIT;
runtime.currentEntry++;
return null;
}
DiscoveredPath best = train.navigation.findPathTo(validStations, Double.MAX_VALUE);
if (best == null) {
if (anyMatch)
train.status.failedNavigation();
runtime.startCooldown();
return null;
}
return best;
}
}

View file

@ -2,9 +2,13 @@ package com.simibubi.create.content.trains.schedule.destination;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.simibubi.create.Create;
import com.simibubi.create.content.trains.graph.DiscoveredPath;
import com.simibubi.create.content.trains.schedule.Schedule;
import com.simibubi.create.content.trains.schedule.ScheduleDataEntry;
import com.simibubi.create.content.trains.schedule.ScheduleRuntime;
import net.createmod.catnip.utility.Pair;
import net.minecraft.nbt.CompoundTag;
@ -13,6 +17,9 @@ import net.minecraft.resources.ResourceLocation;
public abstract class ScheduleInstruction extends ScheduleDataEntry {
public abstract boolean supportsConditions();
@Nullable
public abstract DiscoveredPath start(ScheduleRuntime runtime);
public final CompoundTag write() {
CompoundTag tag = new CompoundTag();

View file

@ -790,6 +790,20 @@
"create.schedule.instruction.throttle.summary": "Change Max Speed to %1$s",
"create.schedule.instruction.throttle_edit_box": "Throttle",
"create.schedule.instruction.throttle_edit_box_1": "Affects the top speed of the Train",
"create.schedule.instruction.package_delivery": "Deliver Package",
"create.schedule.instruction.package_delivery.summary": "Deliver first package in cargo",
"create.schedule.instruction.package_delivery.summary_1": "Drives to the station with",
"create.schedule.instruction.package_delivery.summary_2": "the correct postbox",
"create.schedule.instruction.package_retrieval": "Retrieve Package",
"create.schedule.instruction.package_retrieval.summary": "Fetch a package addressed to:",
"create.schedule.instruction.package_retrieval.summary_1": "Drives to a postbox with",
"create.schedule.instruction.package_retrieval.summary_2": "an undelivered package",
"create.schedule.instruction.address_filter_edit_box": "Retrieve Packages with this Address",
"create.schedule.instruction.address_filter_edit_box_1": "Use * as a text wildcard",
"create.schedule.instruction.address_filter_edit_box_2": "Train may navigate anywhere to collect it",
"create.schedule.instruction.address_filter_edit_box_3": "Add another instruction to make it return",
"create.schedule.condition_type": "Continue if/after:",
"create.schedule.condition.editor": "Condition Editor",