Merge branch 'mc1.20.1/feature-dev' into mc1.21.1/dev

# Conflicts:
#	src/main/java/com/simibubi/create/AllPackets.java
#	src/main/java/com/simibubi/create/content/contraptions/MountedStorage.java
#	src/main/java/com/simibubi/create/content/contraptions/MountedStorageManager.java
#	src/main/java/com/simibubi/create/content/logistics/box/PackageItem.java
#	src/main/java/com/simibubi/create/content/logistics/depot/DepotBlockEntity.java
#	src/main/java/com/simibubi/create/content/logistics/packagePort/frogport/FrogportVisual.java
#	src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java
#	src/main/java/com/simibubi/create/foundation/render/AllInstanceTypes.java
This commit is contained in:
IThundxr 2025-01-12 09:53:36 -05:00
commit b6ab33db9c
Failed to generate hash of commit
52 changed files with 1663 additions and 359 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

@ -169,6 +169,7 @@ import com.simibubi.create.content.logistics.crate.CreativeCrateBlock;
import com.simibubi.create.content.logistics.depot.DepotBlock;
import com.simibubi.create.content.logistics.depot.EjectorBlock;
import com.simibubi.create.content.logistics.depot.EjectorItem;
import com.simibubi.create.content.logistics.depot.MountedDepotInteractionBehaviour;
import com.simibubi.create.content.logistics.factoryBoard.FactoryPanelBlock;
import com.simibubi.create.content.logistics.factoryBoard.FactoryPanelBlockItem;
import com.simibubi.create.content.logistics.factoryBoard.FactoryPanelModel;
@ -796,6 +797,7 @@ public class AllBlocks {
.transform(axeOrPickaxe())
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
.onRegister(assignDataBehaviour(new ItemNameDisplaySource(), "combine_item_names"))
.onRegister(interactionBehaviour(new MountedDepotInteractionBehaviour()))
.item()
.transform(customItemModel("_", "block"))
.register();

View file

@ -27,6 +27,7 @@ import com.simibubi.create.content.contraptions.minecart.capability.MinecartCont
import com.simibubi.create.content.contraptions.sync.ClientMotionPacket;
import com.simibubi.create.content.contraptions.sync.ContraptionFluidPacket;
import com.simibubi.create.content.contraptions.sync.ContraptionInteractionPacket;
import com.simibubi.create.content.contraptions.sync.ContraptionItemPacket;
import com.simibubi.create.content.contraptions.sync.ContraptionSeatMappingPacket;
import com.simibubi.create.content.contraptions.sync.LimbSwingUpdatePacket;
import com.simibubi.create.content.contraptions.wrench.RadialWrenchMenuSubmitPacket;
@ -201,6 +202,7 @@ public enum AllPackets implements BasePacketPayload.PacketTypeProvider {
MINECART_CONTROLLER(MinecartControllerUpdatePacket.class, MinecartControllerUpdatePacket.STREAM_CODEC),
FLUID_SPLASH(FluidSplashPacket.class, FluidSplashPacket.STREAM_CODEC),
CONTRAPTION_FLUID(ContraptionFluidPacket.class, ContraptionFluidPacket.STREAM_CODEC),
CONTRAPTION_ITEM(ContraptionItemPacket.class, ContraptionItemPacket.STREAM_CODEC),
GANTRY_UPDATE(GantryContraptionUpdatePacket.class, GantryContraptionUpdatePacket.STREAM_CODEC),
BLOCK_HIGHLIGHT(HighlightPacket.class, HighlightPacket.STREAM_CODEC),
TUNNEL_FLAP(TunnelFlapPacket.class, TunnelFlapPacket.STREAM_CODEC),

View file

@ -1467,6 +1467,10 @@ public abstract class Contraption {
public IFluidHandler getSharedFluidTanks() {
return storage.getFluids();
}
public MountedStorageManager getStorageManager() {
return storage;
}
public RenderedBlocks getRenderedBlocks() {
return new RenderedBlocks(pos -> {
@ -1493,6 +1497,10 @@ public abstract class Contraption {
public void handleContraptionFluidPacket(BlockPos localPos, FluidStack containedFluid) {
storage.updateContainedFluid(localPos, containedFluid);
}
public void handleContraptionItemPacket(BlockPos localPos, List<ItemStack> containedItems) {
storage.updateContainedItem(localPos, containedItems);
}
public static class ContraptionInvWrapper extends CombinedInvWrapper {
protected final boolean isExternal;

View file

@ -1,20 +1,29 @@
package com.simibubi.create.content.contraptions;
import java.util.List;
import com.simibubi.create.AllBlockEntityTypes;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.content.contraptions.sync.ContraptionItemPacket;
import com.simibubi.create.content.equipment.toolbox.ToolboxInventory;
import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack;
import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlockEntity;
import com.simibubi.create.content.logistics.crate.BottomlessItemHandler;
import com.simibubi.create.content.logistics.depot.DepotBehaviour;
import com.simibubi.create.content.logistics.depot.DepotBlockEntity;
import com.simibubi.create.content.logistics.vault.ItemVaultBlockEntity;
import com.simibubi.create.content.processing.recipe.ProcessingInventory;
import net.createmod.catnip.platform.CatnipServices;
import net.createmod.catnip.utility.NBTHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.NonNullList;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BarrelBlockEntity;
@ -22,6 +31,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.ChestBlockEntity;
import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.items.IItemHandler;
import net.neoforged.neoforge.items.IItemHandlerModifiable;
@ -35,7 +45,10 @@ public class MountedStorage {
boolean noFuel;
boolean valid;
private BlockEntity blockEntity;
private int packetCooldown = 0;
private boolean sendPacket = false;
BlockEntity blockEntity;
public static boolean canUseAsStorage(BlockEntity be) {
if (be == null)
@ -52,10 +65,12 @@ public class MountedStorage {
return true;
if (be instanceof ItemVaultBlockEntity)
return true;
if (be instanceof DepotBlockEntity)
return true;
try {
IItemHandler capability = be.getLevel().getCapability(Capabilities.ItemHandler.BLOCK, be.getBlockPos(), null);
if (capability instanceof ItemStackHandler)
net.neoforged.neoforge.items.IItemHandler capability = be.getLevel().getCapability(Capabilities.ItemHandler.BLOCK, be.getBlockPos(), null);
if (capability instanceof net.neoforged.neoforge.items.ItemStackHandler)
return !(capability instanceof ProcessingInventory);
return canUseModdedInventory(be, capability);
} catch (Exception e) {
@ -64,7 +79,7 @@ public class MountedStorage {
}
public static boolean canUseModdedInventory(BlockEntity be, IItemHandler handler) {
if (!(handler instanceof IItemHandlerModifiable))
if (!(handler instanceof net.neoforged.neoforge.items.IItemHandlerModifiable))
return false;
BlockState blockState = be.getBlockState();
if (AllBlockTags.CONTRAPTION_INVENTORY_DENY.matches(blockState))
@ -88,9 +103,17 @@ public class MountedStorage {
Level level = blockEntity.getLevel();
valid = false;
sendPacket = false;
if (blockEntity == null)
return;
if (blockEntity instanceof DepotBlockEntity depot) {
handler = new SyncedMountedItemStackHandler(1);
handler.setStackInSlot(0, depot.getHeldItem());
valid = true;
return;
}
RegistryAccess registryAccess = level.registryAccess();
if (blockEntity instanceof ChestBlockEntity) {
@ -107,7 +130,7 @@ public class MountedStorage {
return;
}
IItemHandler beHandler = level.getCapability(Capabilities.ItemHandler.BLOCK, blockEntity.getBlockPos(), null, blockEntity, null);
net.neoforged.neoforge.items.IItemHandler beHandler = level.getCapability(Capabilities.ItemHandler.BLOCK, blockEntity.getBlockPos(), null, blockEntity, null);
if (beHandler == null || beHandler == dummyHandler)
return;
@ -144,6 +167,13 @@ public class MountedStorage {
if (handler instanceof BottomlessItemHandler)
return;
if (be instanceof DepotBlockEntity depot) {
if (handler.getSlots() > 0)
depot.getBehaviour(DepotBehaviour.TYPE)
.setCenteredHeldItem(new TransportedItemStack(handler.getStackInSlot(0)));
return;
}
if (be instanceof ChestBlockEntity) {
RegistryAccess registryAccess = be.getLevel().registryAccess();
@ -162,14 +192,35 @@ public class MountedStorage {
return;
}
IItemHandler capability = be.getLevel().getCapability(Capabilities.ItemHandler.BLOCK, be.getBlockPos(), null);
if (!(capability instanceof IItemHandlerModifiable inv))
net.neoforged.neoforge.items.IItemHandler capability = be.getLevel().getCapability(Capabilities.ItemHandler.BLOCK, be.getBlockPos(), null);
if (!(capability instanceof net.neoforged.neoforge.items.IItemHandlerModifiable inv))
return;
for (int slot = 0; slot < Math.min(inv.getSlots(), handler.getSlots()); slot++)
inv.setStackInSlot(slot, handler.getStackInSlot(slot));
}
public void tick(Entity entity, BlockPos pos, boolean isRemote) {
if (isRemote)
return;
if (packetCooldown > 0) {
packetCooldown--;
return;
}
if (sendPacket) {
sendPacket = false;
CatnipServices.NETWORK.sendToClientsTrackingEntity(entity, new ContraptionItemPacket(entity.getId(), pos, handler));
packetCooldown = 8;
}
}
public void updateItems(List<ItemStack> containedItems) {
for (int i = 0; i < Math.min(containedItems.size(), handler.getSlots()); i++)
handler.setStackInSlot(i, containedItems.get(i));
if (blockEntity instanceof DepotBlockEntity depot)
depot.setHeldItem(handler.getStackInSlot(0));
}
public IItemHandlerModifiable getItemHandler() {
return handler;
}
@ -183,6 +234,9 @@ public class MountedStorage {
NBTHelper.putMarker(tag, "NoFuel");
if (handler instanceof ToolboxInventory)
NBTHelper.putMarker(tag, "Toolbox");
if (needsSync())
NBTHelper.putMarker(tag, "Synced");
if (!(handler instanceof BottomlessItemHandler))
return tag;
@ -198,6 +252,8 @@ public class MountedStorage {
return storage;
if (nbt.contains("Toolbox"))
storage.handler = new ToolboxInventory(null);
if (nbt.contains("Synced"))
storage.handler = storage.new SyncedMountedItemStackHandler(1);
storage.valid = true;
storage.noFuel = nbt.contains("NoFuel");
@ -220,4 +276,21 @@ public class MountedStorage {
return !noFuel;
}
public boolean needsSync() {
return handler instanceof SyncedMountedItemStackHandler;
}
public class SyncedMountedItemStackHandler extends ItemStackHandler {
public SyncedMountedItemStackHandler(int i) {
super(i);
}
@Override
protected void onContentsChanged(int slot) {
sendPacket = true;
}
}
}

View file

@ -5,12 +5,14 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.simibubi.create.content.contraptions.Contraption.ContraptionInvWrapper;
import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity;
import com.simibubi.create.content.logistics.depot.DepotBlockEntity;
import com.simibubi.create.foundation.fluid.CombinedTankWrapper;
import net.createmod.catnip.utility.NBTHelper;
@ -54,7 +56,9 @@ public class MountedStorageManager {
}
public void entityTick(AbstractContraptionEntity entity) {
fluidStorage.forEach((pos, mfs) -> mfs.tick(entity, pos, entity.level().isClientSide));
boolean isClientSide = entity.level().isClientSide;
storage.forEach((pos, mfs) -> mfs.tick(entity, pos, isClientSide));
fluidStorage.forEach((pos, mfs) -> mfs.tick(entity, pos, isClientSide));
}
public void createHandlers() {
@ -100,7 +104,7 @@ public class MountedStorageManager {
.put(NbtUtils.readBlockPos(c, "Pos").orElseThrow(), MountedFluidStorage.deserialize(c.getCompound("Data"), registries)));
if (clientPacket && presentBlockEntities != null)
bindTanks(presentBlockEntities);
bindTanksAndDepots(presentBlockEntities);
List<IItemHandlerModifiable> handlers = new ArrayList<>();
List<IItemHandlerModifiable> fuelHandlers = new ArrayList<>();
@ -119,33 +123,41 @@ public class MountedStorageManager {
.toList());
}
public void bindTanks(Map<BlockPos, BlockEntity> presentBlockEntities) {
fluidStorage.forEach((pos, mfs) -> {
BlockEntity blockEntity = presentBlockEntities.get(pos);
if (!(blockEntity instanceof FluidTankBlockEntity))
public void bindTanksAndDepots(Map<BlockPos, BlockEntity> presentBlockEntities) {
for (Entry<BlockPos, MountedStorage> entry : storage.entrySet()) {
BlockEntity blockEntity = presentBlockEntities.get(entry.getKey());
if (!(blockEntity instanceof DepotBlockEntity depot))
return;
depot.setHeldItem(entry.getValue().handler.getStackInSlot(0));
entry.getValue().blockEntity = depot;
}
for (Entry<BlockPos, MountedFluidStorage> entry : fluidStorage.entrySet()) {
BlockEntity blockEntity = presentBlockEntities.get(entry.getKey());
if (!(blockEntity instanceof FluidTankBlockEntity tank))
return;
FluidTankBlockEntity tank = (FluidTankBlockEntity) blockEntity;
IFluidTank tankInventory = tank.getTankInventory();
MountedFluidStorage mfs = entry.getValue();
if (tankInventory instanceof FluidTank)
((FluidTank) tankInventory).setFluid(mfs.tank.getFluid());
tank.getFluidLevel()
.startWithValue(tank.getFillState());
mfs.assignBlockEntity(tank);
});
}
}
public void write(CompoundTag nbt, HolderLookup.Provider registries, boolean clientPacket) {
ListTag storageNBT = new ListTag();
if (!clientPacket)
for (BlockPos pos : storage.keySet()) {
CompoundTag c = new CompoundTag();
MountedStorage mountedStorage = storage.get(pos);
if (!mountedStorage.isValid())
continue;
c.put("Pos", NbtUtils.writeBlockPos(pos));
c.put("Data", mountedStorage.serialize(registries));
storageNBT.add(c);
}
for (BlockPos pos : storage.keySet()) {
CompoundTag c = new CompoundTag();
MountedStorage mountedStorage = storage.get(pos);
if (!mountedStorage.isValid())
continue;
if (clientPacket && !mountedStorage.needsSync())
continue;
c.put("Pos", NbtUtils.writeBlockPos(pos));
c.put("Data", mountedStorage.serialize(registries));
storageNBT.add(c);
}
ListTag fluidStorageNBT = new ListTag();
for (BlockPos pos : fluidStorage.keySet()) {
@ -197,6 +209,12 @@ public class MountedStorageManager {
mountedFluidStorage.updateFluid(containedFluid);
}
public void updateContainedItem(BlockPos localPos, List<ItemStack> containedItems) {
MountedStorage mountedStorage = storage.get(localPos);
if (mountedStorage != null)
mountedStorage.updateItems(containedItems);
}
public void attachExternal(IItemHandlerModifiable externalStorage) {
inventory = new ContraptionInvWrapper(externalStorage, inventory);
fuelInventory = new ContraptionInvWrapper(externalStorage, fuelInventory);
@ -214,6 +232,14 @@ public class MountedStorageManager {
return fluidInventory;
}
public Map<BlockPos, MountedStorage> getMountedItemStorage() {
return storage;
}
public Map<BlockPos, MountedFluidStorage> getMountedFluidStorage() {
return fluidStorage;
}
public boolean handlePlayerStorageInteraction(Contraption contraption, Player player, BlockPos localPos) {
if (player.level().isClientSide()) {
BlockEntity localBE = contraption.presentBlockEntities.get(localPos);

View file

@ -0,0 +1,53 @@
package com.simibubi.create.content.contraptions.sync;
import java.util.ArrayList;
import java.util.List;
import com.simibubi.create.AllPackets;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import net.createmod.catnip.codecs.stream.CatnipStreamCodecBuilders;
import net.createmod.catnip.net.base.ClientboundPacketPayload;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.neoforged.neoforge.items.ItemStackHandler;
public record ContraptionItemPacket(int entityId, BlockPos localPos, List<ItemStack> containedItems) implements ClientboundPacketPayload {
public static StreamCodec<RegistryFriendlyByteBuf, ContraptionItemPacket> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.INT, ContraptionItemPacket::entityId,
BlockPos.STREAM_CODEC, ContraptionItemPacket::localPos,
CatnipStreamCodecBuilders.list(ItemStack.STREAM_CODEC), ContraptionItemPacket::containedItems,
ContraptionItemPacket::new
);
public ContraptionItemPacket(int entityId, BlockPos localPos, ItemStackHandler handler) {
this(entityId, localPos, convert(handler));
}
private static List<ItemStack> convert(ItemStackHandler handler) {
List<ItemStack> list = new ArrayList<>(handler.getSlots());
for (int i = 0; i < handler.getSlots(); i++)
list.add(handler.getStackInSlot(i));
return list;
}
@Override
public PacketTypeProvider getTypeProvider() {
return AllPackets.CONTRAPTION_ITEM;
}
@Override
public void handle(LocalPlayer player) {
Entity entityByID = Minecraft.getInstance().level.getEntity(entityId);
if (!(entityByID instanceof AbstractContraptionEntity contraptionEntity))
return;
contraptionEntity.getContraption().handleContraptionItemPacket(localPos, containedItems);
}
}

View file

@ -6,9 +6,9 @@ import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.block.state.BlockState;
public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> extends AbstractBlockEntityVisual<T> {
@ -32,7 +32,7 @@ public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> ext
protected final void updateRotation(RotatingInstance instance, Direction.Axis axis, float speed) {
instance.setRotationAxis(axis)
.setRotationOffset(getRotationOffset(axis))
.setRotationalSpeed(speed)
.setRotationalSpeed(speed * RotatingInstance.SPEED_MULTIPLIER)
.setColor(blockEntity)
.setChanged();
}
@ -51,7 +51,7 @@ public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> ext
protected final RotatingInstance setup(RotatingInstance key, Direction.Axis axis, float speed) {
key.setRotationAxis(axis)
.setRotationalSpeed(speed)
.setRotationalSpeed(speed * RotatingInstance.SPEED_MULTIPLIER)
.setRotationOffset(getRotationOffset(axis))
.setColor(blockEntity)
.setPosition(getVisualPosition())
@ -76,7 +76,7 @@ public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> ext
return shaft(rotationAxis());
}
public static float rotationOffset(BlockState state, Axis axis, BlockPos pos) {
public static float rotationOffset(BlockState state, Axis axis, Vec3i pos) {
if (shouldOffset(axis, pos)) {
return 22.5f;
} else {
@ -84,7 +84,7 @@ public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> ext
}
}
public static boolean shouldOffset(Axis axis, BlockPos pos) {
public static boolean shouldOffset(Axis axis, Vec3i pos) {
// Sum the components of the other 2 axes.
int x = (axis == Axis.X) ? 0 : pos.getX();
int y = (axis == Axis.Y) ? 0 : pos.getY();

View file

@ -1,69 +0,0 @@
package com.simibubi.create.content.kinetics.base;
import org.joml.Vector3f;
import dev.engine_room.flywheel.api.instance.InstanceHandle;
import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.lib.instance.ColoredLitInstance;
import net.createmod.catnip.utility.theme.Color;
import net.minecraft.core.BlockPos;
public class KineticInstance extends ColoredLitInstance {
public float x;
public float y;
public float z;
public float rotationalSpeed;
public float rotationOffset;
protected KineticInstance(InstanceType<? extends KineticInstance> type, InstanceHandle handle) {
super(type, handle);
}
public KineticInstance setPosition(BlockPos pos) {
return setPosition(pos.getX(), pos.getY(), pos.getZ());
}
public KineticInstance setPosition(Vector3f pos) {
return setPosition(pos.x(), pos.y(), pos.z());
}
public KineticInstance setPosition(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
public KineticInstance nudge(float x, float y, float z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public KineticInstance setColor(KineticBlockEntity blockEntity) {
colorRgb(colorFromBE(blockEntity));
return this;
}
public KineticInstance setColor(Color c) {
color(c.getRed(), c.getGreen(), c.getBlue());
return this;
}
public KineticInstance setRotationalSpeed(float rotationalSpeed) {
this.rotationalSpeed = rotationalSpeed;
return this;
}
public KineticInstance setRotationOffset(float rotationOffset) {
this.rotationOffset = rotationOffset;
return this;
}
public static int colorFromBE(KineticBlockEntity be) {
if (be.hasNetwork())
return Color.generateFromLong(be.network).getRGB();
return 0xFFFFFF;
}
}

View file

@ -1,20 +1,48 @@
package com.simibubi.create.content.kinetics.base;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import dev.engine_room.flywheel.api.instance.InstanceHandle;
import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.lib.instance.ColoredLitInstance;
import net.createmod.catnip.utility.theme.Color;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
public class RotatingInstance extends ColoredLitInstance {
public static final float SPEED_MULTIPLIER = 6;
public class RotatingInstance extends KineticInstance {
public byte rotationAxisX;
public byte rotationAxisY;
public byte rotationAxisZ;
public float x;
public float y;
public float z;
/**
* Speed in degrees per second
*/
public float rotationalSpeed;
/**
* Offset in degrees
*/
public float rotationOffset;
public RotatingInstance(InstanceType<? extends KineticInstance> type, InstanceHandle handle) {
/**
* Base rotation of the instance, applied before kinetic rotation
*/
public final Quaternionf rotation = new Quaternionf();
public RotatingInstance(InstanceType<? extends RotatingInstance> type, InstanceHandle handle) {
super(type, handle);
}
public static int colorFromBE(KineticBlockEntity be) {
if (be.hasNetwork())
return Color.generateFromLong(be.network).getRGB();
return 0xFFFFFF;
}
public RotatingInstance setRotationAxis(Direction.Axis axis) {
Direction orientation = Direction.get(Direction.AxisDirection.POSITIVE, axis);
return setRotationAxis(orientation.step());
@ -31,4 +59,45 @@ public class RotatingInstance extends KineticInstance {
return this;
}
public RotatingInstance setPosition(Vec3i pos) {
return setPosition(pos.getX(), pos.getY(), pos.getZ());
}
public RotatingInstance setPosition(Vector3f pos) {
return setPosition(pos.x(), pos.y(), pos.z());
}
public RotatingInstance setPosition(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
public RotatingInstance nudge(float x, float y, float z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public RotatingInstance setColor(KineticBlockEntity blockEntity) {
colorRgb(colorFromBE(blockEntity));
return this;
}
public RotatingInstance setColor(Color c) {
color(c.getRed(), c.getGreen(), c.getBlue());
return this;
}
public RotatingInstance setRotationalSpeed(float rotationalSpeed) {
this.rotationalSpeed = rotationalSpeed;
return this;
}
public RotatingInstance setRotationOffset(float rotationOffset) {
this.rotationOffset = rotationOffset;
return this;
}
}

View file

@ -7,7 +7,6 @@ import org.joml.Quaternionf;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityVisual;
import com.simibubi.create.content.kinetics.base.KineticInstance;
import com.simibubi.create.content.kinetics.base.RotatingInstance;
import com.simibubi.create.content.processing.burner.ScrollInstance;
import com.simibubi.create.foundation.render.AllInstanceTypes;
@ -158,7 +157,7 @@ public class BeltVisual extends KineticBlockEntityVisual<BeltBlockEntity> {
.rotation(q)
.speed(0, speed * MAGIC_SCROLL_MULTIPLIER)
.offset(0, bottom ? SCROLL_OFFSET_BOTTOM : SCROLL_OFFSET_OTHERWISE)
.colorRgb(KineticInstance.colorFromBE(blockEntity))
.colorRgb(RotatingInstance.colorFromBE(blockEntity))
.setChanged();
return key;

View file

@ -1,11 +1,9 @@
package com.simibubi.create.content.kinetics.drill;
import org.joml.Quaternionf;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.contraptions.actors.ActorInstance;
import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.render.ActorVisual;
import com.simibubi.create.content.kinetics.base.RotatingInstance;
import com.simibubi.create.foundation.render.AllInstanceTypes;
import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld;
@ -19,7 +17,7 @@ import net.minecraft.world.level.block.state.BlockState;
public class DrillActorVisual extends ActorVisual {
ActorInstance drillHead;
RotatingInstance drillHead;
private final Direction facing;
public DrillActorVisual(VisualizationContext visualizationContext, VirtualRenderWorld contraption, MovementContext context) {
@ -38,21 +36,22 @@ public class DrillActorVisual extends ActorVisual {
else
eulerY = facing.toYRot() + ((axis == Direction.Axis.X) ? 180 : 0);
drillHead = instancerProvider.instancer(AllInstanceTypes.ACTOR, Models.partial(AllPartialModels.DRILL_HEAD))
drillHead = instancerProvider.instancer(AllInstanceTypes.ROTATING, Models.partial(AllPartialModels.DRILL_HEAD))
.createInstance();
drillHead.rotation.rotationXYZ(eulerX * Mth.DEG_TO_RAD, eulerY * Mth.DEG_TO_RAD, 0);
drillHead.setPosition(context.localPos)
.setBlockLight(localBlockLight())
.setRotationOffset(0)
.setRotationAxis(0, 0, 1)
.setLocalRotation(new Quaternionf().rotationXYZ(eulerX * Mth.DEG_TO_RAD, eulerY * Mth.DEG_TO_RAD, 0))
.setSpeed(getSpeed(facing))
.setChanged();
.setRotationOffset(0)
.setRotationAxis(0, 0, 1)
.setRotationalSpeed(getSpeed(facing))
.light(localBlockLight(), 0)
.setChanged();
}
@Override
public void beginFrame() {
drillHead.setSpeed(getSpeed(facing))
drillHead.setRotationalSpeed(getSpeed(facing))
.setChanged();
}

View file

@ -45,7 +45,7 @@ public class GearboxVisual extends KineticBlockEntityVisual<GearboxBlockEntity>
.createInstance();
key.setRotationAxis(axis)
.setRotationalSpeed(getSpeed(direction))
.setRotationalSpeed(getSpeed(direction) * RotatingInstance.SPEED_MULTIPLIER)
.setRotationOffset(getRotationOffset(axis)).setColor(blockEntity)
.setPosition(getVisualPosition())
.light(blockLight, skyLight)

View file

@ -60,7 +60,7 @@ public class MixerVisual extends EncasedCogVisual implements SimpleDynamicVisual
mixerHead.setPosition(getVisualPosition())
.nudge(0, -renderedHeadOffset, 0)
.setRotationalSpeed(speed * 2)
.setRotationalSpeed(speed * 2 * RotatingInstance.SPEED_MULTIPLIER)
.setChanged();
}

View file

@ -14,6 +14,7 @@ import com.simibubi.create.content.logistics.chute.ChuteBlock;
import net.createmod.catnip.platform.CatnipServices;
import net.createmod.catnip.utility.VecHelper;
import net.createmod.catnip.utility.math.AngleHelper;
import net.createmod.ponder.api.level.PonderLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@ -164,6 +165,13 @@ public class PackageEntity extends LivingEntity implements IEntityWithComplexSpa
verifyInitialEntity();
originalEntity = null;
}
if (level() instanceof PonderLevel) {
setDeltaMovement(getDeltaMovement().add(0, -0.06, 0));
if (position().y < 0.125)
discard();
}
insertionDelay = Math.min(insertionDelay + 1, 30);
super.tick();

View file

@ -188,7 +188,7 @@ public class PackageItem extends Item {
super.appendHoverText(stack, tooltipContext, tooltipComponents, tooltipFlag);
if (stack.has(AllDataComponents.PACKAGE_ADDRESS))
tooltipComponents.add(Components.literal("-> " + stack.get(AllDataComponents.PACKAGE_ADDRESS))
tooltipComponents.add(Components.literal("\u2192 " + stack.get(AllDataComponents.PACKAGE_ADDRESS))
.withStyle(ChatFormatting.GOLD));
/*

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.depot;
import java.util.List;
import com.simibubi.create.AllBlockEntityTypes;
import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
@ -38,4 +39,12 @@ public class DepotBlockEntity extends SmartBlockEntity {
public ItemStack getHeldItem() {
return depotBehaviour.getHeldItemStack();
}
public void setHeldItem(ItemStack item) {
TransportedItemStack newStack = new TransportedItemStack(item);
if (depotBehaviour.heldItem != null)
newStack.angle = depotBehaviour.heldItem.angle;
depotBehaviour.setHeldItem(newStack);
}
}

View file

@ -0,0 +1,52 @@
package com.simibubi.create.content.logistics.depot;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.MountedStorage;
import com.simibubi.create.content.contraptions.MountedStorageManager;
import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.items.IItemHandlerModifiable;
public class MountedDepotInteractionBehaviour extends MovingInteractionBehaviour {
@Override
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
AbstractContraptionEntity contraptionEntity) {
ItemStack itemInHand = player.getItemInHand(activeHand);
if (activeHand == InteractionHand.OFF_HAND)
return false;
if (player.level().isClientSide)
return true;
MountedStorageManager storageManager = contraptionEntity.getContraption()
.getStorageManager();
if (storageManager == null)
return false;
MountedStorage mountedStorage = storageManager.getMountedItemStorage()
.get(localPos);
if (mountedStorage == null)
return false;
IItemHandlerModifiable itemHandler = mountedStorage.getItemHandler();
ItemStack itemOnDepot = itemHandler.getStackInSlot(0);
if (itemOnDepot.isEmpty() && itemInHand.isEmpty())
return true;
itemHandler.setStackInSlot(0, itemInHand.copy());
player.setItemInHand(activeHand, itemOnDepot.copy());
AllSoundEvents.DEPOT_PLOP.playOnServer(player.level(),
BlockPos.containing(contraptionEntity.toGlobalVector(Vec3.atCenterOf(localPos), 0)));
return true;
}
}

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.packagePort.frogport;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import com.simibubi.create.AllPartialModels;
@ -26,6 +27,12 @@ public class FrogportVisual extends AbstractBlockEntityVisual<FrogportBlockEntit
private final TransformedInstance rig;
private final TransformedInstance box;
private final Matrix4f basePose = new Matrix4f();
private float lastYaw = Float.NaN;
private float lastHeadPitch = Float.NaN;
private float lastTonguePitch = Float.NaN;
private float lastTongueLength = Float.NaN;
public FrogportVisual(VisualizationContext ctx, FrogportBlockEntity blockEntity, float partialTick) {
super(ctx, blockEntity, partialTick);
@ -112,40 +119,55 @@ public class FrogportVisual extends AbstractBlockEntityVisual<FrogportBlockEntit
float anticipation = blockEntity.anticipationProgress.getValue(partialTicks);
headPitchModifier =
anticipation > 0 ? (float) Math.max(0, 1 - Math.pow((anticipation * 1.25) * 2 - 1, 4)) : 0;
rig.handle()
.setVisible(false);
box.handle()
.setVisible(false);
}
headPitch *= headPitchModifier;
headPitch = Math.max(headPitch, blockEntity.manualOpenAnimationProgress.getValue(partialTicks) * 60);
tongueLength = Math.max(tongueLength, blockEntity.manualOpenAnimationProgress.getValue(partialTicks) * 0.25f);
if (yaw != lastYaw) {
body.setIdentityTransform()
.translate(getVisualPosition())
.center()
.rotateYDegrees(yaw)
.uncenter()
.setChanged();
body.setIdentityTransform()
.translate(getVisualPosition())
.center()
.rotateYDegrees(yaw)
.uncenter()
.setChanged();
// Save the base pose to avoid recalculating it twice every frame
basePose.set(body.pose)
.translate(8 / 16f, 10 / 16f, 11 / 16f);
head.setIdentityTransform()
.translate(getVisualPosition())
.center()
.rotateYDegrees(yaw)
.uncenter()
.translate(8 / 16f, 10 / 16f, 11 / 16f)
.rotateXDegrees(headPitch)
.translateBack(8 / 16f, 10 / 16f, 11 / 16f)
.setChanged();
// I'm not entirely sure that yaw ever changes
lastYaw = yaw;
tongue.setIdentityTransform()
.translate(getVisualPosition())
.center()
.rotateYDegrees(yaw)
.uncenter()
.translate(8 / 16f, 10 / 16f, 11 / 16f)
.rotateXDegrees(tonguePitch)
.scale(1f, 1f, tongueLength / (7 / 16f))
.translateBack(8 / 16f, 10 / 16f, 11 / 16f)
.setChanged();
// Force the head and tongue to update
lastTonguePitch = Float.NaN;
lastHeadPitch = Float.NaN;
}
if (headPitch != lastHeadPitch) {
head.setTransform(basePose)
.rotateXDegrees(headPitch)
.translateBack(8 / 16f, 10 / 16f, 11 / 16f)
.setChanged();
lastHeadPitch = headPitch;
}
if (tonguePitch != lastTonguePitch || tongueLength != lastTongueLength) {
tongue.setTransform(basePose)
.rotateXDegrees(tonguePitch)
.scale(1f, 1f, tongueLength / (7 / 16f))
.translateBack(8 / 16f, 10 / 16f, 11 / 16f)
.setChanged();
lastTonguePitch = tonguePitch;
lastTongueLength = tongueLength;
}
}
private void renderPackage(Vec3 diff, float scale, float itemDistance) {

View file

@ -334,6 +334,11 @@ public class CarriageContraption extends Contraption {
public void handleContraptionFluidPacket(BlockPos localPos, FluidStack containedFluid) {
storage.updateContainedFluid(localPos, containedFluid);
}
@Override
public MountedStorageManager getStorageManager() {
return storageProxy;
}
@Override
public void tickStorage(AbstractContraptionEntity entity) {

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;
@ -49,6 +51,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,7 +4,6 @@ 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.AllDataComponents;
import com.simibubi.create.AllItems;
@ -12,10 +11,8 @@ import com.simibubi.create.content.trains.display.GlobalTrainDisplayData.TrainDe
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;
@ -40,30 +37,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)
@ -144,7 +146,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);
@ -175,55 +185,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

@ -58,6 +58,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;
@ -989,8 +990,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,127 @@
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.neoforged.neoforge.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,171 @@
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.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import net.neoforged.neoforge.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

@ -3,8 +3,11 @@ package com.simibubi.create.content.trains.schedule.destination;
import java.util.function.Supplier;
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 com.simibubi.create.infrastructure.codec.CreateStreamCodecs;
import net.createmod.catnip.utility.Pair;
@ -14,6 +17,8 @@ import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nullable;
public abstract class ScheduleInstruction extends ScheduleDataEntry {
public static final StreamCodec<RegistryFriendlyByteBuf, ScheduleInstruction> STREAM_CODEC = CreateStreamCodecs.ofLegacyNbtWithRegistries(
ScheduleInstruction::write, ScheduleInstruction::fromTag
@ -21,6 +26,9 @@ public abstract class ScheduleInstruction extends ScheduleDataEntry {
public abstract boolean supportsConditions();
@Nullable
public abstract DiscoveredPath start(ScheduleRuntime runtime);
public final CompoundTag write(HolderLookup.Provider registries) {
CompoundTag tag = new CompoundTag();
CompoundTag dataCopy = data.copy();

View file

@ -187,6 +187,37 @@ public class GlobalStation extends SingleBlockEntityEdgePoint {
if (carriageInventory == null)
continue;
// Import from station
for (Entry<BlockPos, GlobalPackagePort> entry : connectedPorts.entrySet()) {
GlobalPackagePort port = entry.getValue();
BlockPos pos = entry.getKey();
PostboxBlockEntity box = null;
IItemHandlerModifiable postboxInventory = port.offlineBuffer;
if (level != null && level.isLoaded(pos)
&& level.getBlockEntity(pos) instanceof PostboxBlockEntity ppbe) {
postboxInventory = ppbe.inventory;
box = ppbe;
}
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;
ItemStack result = ItemHandlerHelper.insertItemStacked(carriageInventory, stack, false);
if (!result.isEmpty())
continue;
postboxInventory.setStackInSlot(slot, ItemStack.EMPTY);
Create.RAILWAYS.markTracksDirty();
if (box != null)
box.spawnParticles();
}
}
// Export to station
for (int slot = 0; slot < carriageInventory.getSlots(); slot++) {
ItemStack stack = carriageInventory.getStackInSlot(slot);
@ -221,37 +252,6 @@ public class GlobalStation extends SingleBlockEntityEdgePoint {
}
}
// Import from station
for (Entry<BlockPos, GlobalPackagePort> entry : connectedPorts.entrySet()) {
GlobalPackagePort port = entry.getValue();
BlockPos pos = entry.getKey();
PostboxBlockEntity box = null;
IItemHandlerModifiable postboxInventory = port.offlineBuffer;
if (level != null && level.isLoaded(pos)
&& level.getBlockEntity(pos) instanceof PostboxBlockEntity ppbe) {
postboxInventory = ppbe.inventory;
box = ppbe;
}
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;
ItemStack result = ItemHandlerHelper.insertItemStacked(carriageInventory, stack, false);
if (!result.isEmpty())
continue;
postboxInventory.setStackInSlot(slot, ItemStack.EMPTY);
Create.RAILWAYS.markTracksDirty();
if (box != null)
box.spawnParticles();
}
}
}
}

View file

@ -2,7 +2,6 @@ package com.simibubi.create.foundation.blockEntity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@ -19,6 +18,7 @@ import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour
import com.simibubi.create.foundation.utility.IInteractionChecker;
import com.simibubi.create.api.schematic.nbt.IPartialSafeNBT;
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
import net.createmod.ponder.api.VirtualBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
@ -32,7 +32,7 @@ import net.neoforged.neoforge.common.NeoForge;
public abstract class SmartBlockEntity extends CachedRenderBBBlockEntity
implements IPartialSafeNBT, IInteractionChecker, ISpecialBlockEntityItemRequirement, VirtualBlockEntity {
private final Map<BehaviourType<?>, BlockEntityBehaviour> behaviours = new HashMap<>();
private final Map<BehaviourType<?>, BlockEntityBehaviour> behaviours = new Reference2ObjectArrayMap<>();
private boolean initialized = false;
private boolean firstNbtRead = true;
protected int lazyTickRate;

View file

@ -7,7 +7,6 @@ import net.neoforged.api.distmarker.OnlyIn;
import org.lwjgl.system.MemoryUtil;
import com.simibubi.create.content.contraptions.actors.ActorInstance;
import com.simibubi.create.content.kinetics.base.RotatingInstance;
import com.simibubi.create.content.processing.burner.ScrollInstance;
@ -27,6 +26,7 @@ public class AllInstanceTypes {
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
.vector("light", IntegerRepr.SHORT, 2)
.vector("overlay", IntegerRepr.SHORT, 2)
.vector("rotation", FloatRepr.FLOAT, 4)
.vector("pos", FloatRepr.FLOAT, 3)
.scalar("speed", FloatRepr.FLOAT)
.scalar("offset", FloatRepr.FLOAT)
@ -39,14 +39,15 @@ public class AllInstanceTypes {
MemoryUtil.memPutByte(ptr + 3, instance.alpha);
ExtraMemoryOps.put2x16(ptr + 4, instance.light);
ExtraMemoryOps.put2x16(ptr + 8, instance.overlay);
MemoryUtil.memPutFloat(ptr + 12, instance.x);
MemoryUtil.memPutFloat(ptr + 16, instance.y);
MemoryUtil.memPutFloat(ptr + 20, instance.z);
MemoryUtil.memPutFloat(ptr + 24, instance.rotationalSpeed);
MemoryUtil.memPutFloat(ptr + 28, instance.rotationOffset);
MemoryUtil.memPutByte(ptr + 32, instance.rotationAxisX);
MemoryUtil.memPutByte(ptr + 33, instance.rotationAxisY);
MemoryUtil.memPutByte(ptr + 34, instance.rotationAxisZ);
ExtraMemoryOps.putQuaternionf(ptr + 12, instance.rotation);
MemoryUtil.memPutFloat(ptr + 28, instance.x);
MemoryUtil.memPutFloat(ptr + 32, instance.y);
MemoryUtil.memPutFloat(ptr + 36, instance.z);
MemoryUtil.memPutFloat(ptr + 40, instance.rotationalSpeed);
MemoryUtil.memPutFloat(ptr + 44, instance.rotationOffset);
MemoryUtil.memPutByte(ptr + 48, instance.rotationAxisX);
MemoryUtil.memPutByte(ptr + 49, instance.rotationAxisY);
MemoryUtil.memPutByte(ptr + 50, instance.rotationAxisZ);
})
.build();
@ -86,36 +87,6 @@ public class AllInstanceTypes {
})
.build();
public static final InstanceType<ActorInstance> ACTOR = SimpleInstanceType.builder(ActorInstance::new)
.cullShader(asResource("instance/cull/actor.glsl"))
.vertexShader(asResource("instance/actor.vert"))
.layout(LayoutBuilder.create()
.vector("pos", FloatRepr.FLOAT, 3)
.vector("light", IntegerRepr.SHORT, 2)
.scalar("offset", FloatRepr.FLOAT)
.vector("axis", FloatRepr.NORMALIZED_BYTE, 3)
.vector("rotation", FloatRepr.FLOAT, 4)
.vector("rotationCenter", FloatRepr.NORMALIZED_BYTE, 3)
.scalar("speed", FloatRepr.FLOAT)
.build())
.writer((ptr, instance) -> {
MemoryUtil.memPutFloat(ptr, instance.x);
MemoryUtil.memPutFloat(ptr + 4, instance.y);
MemoryUtil.memPutFloat(ptr + 8, instance.z);
MemoryUtil.memPutShort(ptr + 12, instance.blockLight);
MemoryUtil.memPutShort(ptr + 14, instance.skyLight);
MemoryUtil.memPutFloat(ptr + 16, instance.rotationOffset);
MemoryUtil.memPutByte(ptr + 20, instance.rotationAxisX);
MemoryUtil.memPutByte(ptr + 21, instance.rotationAxisY);
MemoryUtil.memPutByte(ptr + 22, instance.rotationAxisZ);
ExtraMemoryOps.putQuaternionf(ptr + 24, instance.rotation);
MemoryUtil.memPutByte(ptr + 40, instance.rotationCenterX);
MemoryUtil.memPutByte(ptr + 41, instance.rotationCenterY);
MemoryUtil.memPutByte(ptr + 42, instance.rotationCenterZ);
MemoryUtil.memPutFloat(ptr + 44, instance.speed);
})
.build();
public static void init() {
// noop
}

View file

@ -19,7 +19,6 @@ import com.simibubi.create.infrastructure.ponder.scenes.DisplayScenes;
import com.simibubi.create.infrastructure.ponder.scenes.EjectorScenes;
import com.simibubi.create.infrastructure.ponder.scenes.ElevatorScenes;
import com.simibubi.create.infrastructure.ponder.scenes.FanScenes;
import com.simibubi.create.infrastructure.ponder.scenes.FrogAndConveyorScenes;
import com.simibubi.create.infrastructure.ponder.scenes.FunnelScenes;
import com.simibubi.create.infrastructure.ponder.scenes.GantryScenes;
import com.simibubi.create.infrastructure.ponder.scenes.ItemVaultScenes;
@ -42,6 +41,8 @@ import com.simibubi.create.infrastructure.ponder.scenes.fluid.HosePulleyScenes;
import com.simibubi.create.infrastructure.ponder.scenes.fluid.PipeScenes;
import com.simibubi.create.infrastructure.ponder.scenes.fluid.PumpScenes;
import com.simibubi.create.infrastructure.ponder.scenes.fluid.SpoutScenes;
import com.simibubi.create.infrastructure.ponder.scenes.highLogistics.FrogAndConveyorScenes;
import com.simibubi.create.infrastructure.ponder.scenes.highLogistics.PackagerScenes;
import com.simibubi.create.infrastructure.ponder.scenes.trains.TrackObserverScenes;
import com.simibubi.create.infrastructure.ponder.scenes.trains.TrackScenes;
import com.simibubi.create.infrastructure.ponder.scenes.trains.TrainScenes;
@ -351,10 +352,13 @@ public class AllCreatePonderScenes {
// Hilo
HELPER.forComponents(AllBlocks.CHAIN_CONVEYOR)
.addStoryBoard("chain_conveyor", FrogAndConveyorScenes::conveyor);
.addStoryBoard("high_logistics/chain_conveyor", FrogAndConveyorScenes::conveyor);
HELPER.forComponents(AllBlocks.PACKAGE_FROGPORT)
.addStoryBoard("package_frogport", FrogAndConveyorScenes::frogPort);
.addStoryBoard("high_logistics/package_frogport", FrogAndConveyorScenes::frogPort);
HELPER.forComponents(AllBlocks.PACKAGER)
.addStoryBoard("high_logistics/packager", PackagerScenes::packager)
.addStoryBoard("high_logistics/packager_address", PackagerScenes::packagerAddress);
// Trains
HELPER.forComponents(TrackMaterial.allBlocks()
.stream()

View file

@ -1,4 +1,4 @@
package com.simibubi.create.infrastructure.ponder.scenes;
package com.simibubi.create.infrastructure.ponder.scenes.highLogistics;
import java.util.Iterator;
import java.util.function.Supplier;
@ -564,10 +564,19 @@ public class FrogAndConveyorScenes {
scene.world()
.multiplyKineticSpeed(util.select()
.fromTo(9, 0, 1, 5, 1, 0), 1 / 32f);
scene.idle(5);
scene.overlay()
.showText(75)
.showText(60)
.attachKeyFrame()
.text("If a package is addressed to a different name..")
.pointAt(util.vector()
.topOf(5, 0, 3))
.placeNearTarget();
scene.idle(70);
scene.overlay()
.showText(40)
.colored(PonderPalette.BLUE)
.text("Albert")
.pointAt(util.vector()
@ -575,24 +584,15 @@ public class FrogAndConveyorScenes {
.placeNearTarget();
scene.idle(5);
scene.overlay()
.showText(70)
.showText(40)
.colored(PonderPalette.OUTPUT)
.text("Peter")
.text("\u2192 Peter")
.pointAt(util.vector()
.centerOf(util.grid()
.at(5, 2, 0)))
.placeNearTarget();
scene.idle(30);
scene.overlay()
.showText(80)
.attachKeyFrame()
.text("If a package is addressed to a different name..")
.pointAt(util.vector()
.topOf(5, 0, 3))
.placeNearTarget();
scene.idle(60);
scene.idle(50);
scene.world()
.multiplyKineticSpeed(util.select()
@ -712,7 +712,7 @@ public class FrogAndConveyorScenes {
scene.overlay()
.showText(55)
.colored(PonderPalette.OUTPUT)
.text("Peter")
.text("\u2192 Peter")
.pointAt(util.vector()
.centerOf(util.grid()
.at(0, 2, 5)))
@ -775,7 +775,7 @@ public class FrogAndConveyorScenes {
scene.world()
.showIndependentSection(fromPackager, Direction.WEST);
ElementLink<WorldSectionElement> toPackagerE = scene.world()
.showIndependentSection(toPackager, Direction.WEST);
.showIndependentSection(toPackager, Direction.EAST);
scene.world()
.moveSection(toPackagerE, util.vector()
.of(0, 0, 1), 0);
@ -849,14 +849,8 @@ public class FrogAndConveyorScenes {
.fromTo(5, 1, 2, 6, 1, 1));
scene.idle(5);
scene.world()
.modifyBlockEntity(util.grid()
.at(5, 1, 2), PackagerBlockEntity.class, be -> {
be.animationTicks = PackagerBlockEntity.CYCLE;
be.animationInward = false;
be.heldBox = box;
});
PonderHilo.packagerCreate(scene, util.grid()
.at(5, 1, 2), box);
scene.idle(30);
scene.world()
@ -873,15 +867,10 @@ public class FrogAndConveyorScenes {
.modifyBlockEntity(conv2, ChainConveyorBlockEntity.class, be -> boxTransfer(conv1, conv2, be));
scene.idle(50);
scene.world()
.modifyBlockEntity(util.grid()
.at(2, 1, 4), PackagerBlockEntity.class, be -> {
be.animationTicks = PackagerBlockEntity.CYCLE;
be.animationInward = true;
be.previouslyUnwrapped = box;
});
PonderHilo.packagerUnpack(scene, util.grid()
.at(2, 1, 4), box);
scene.idle(20);
scene.overlay()
.showControls(util.vector()
.blockSurface(util.grid()

View file

@ -0,0 +1,569 @@
package com.simibubi.create.infrastructure.ponder.scenes.highLogistics;
import java.util.List;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.logistics.box.PackageItem;
import com.simibubi.create.content.logistics.box.PackageStyles;
import com.simibubi.create.foundation.ponder.CreateSceneBuilder;
import net.createmod.catnip.utility.Pointing;
import net.createmod.ponder.api.PonderPalette;
import net.createmod.ponder.api.element.ElementLink;
import net.createmod.ponder.api.element.WorldSectionElement;
import net.createmod.ponder.api.scene.SceneBuilder;
import net.createmod.ponder.api.scene.SceneBuildingUtil;
import net.createmod.ponder.api.scene.Selection;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
public class PackagerScenes {
public static void packager(SceneBuilder builder, SceneBuildingUtil util) {
CreateSceneBuilder scene = new CreateSceneBuilder(builder);
scene.title("packager", "Creating and unwrapping packages");
scene.configureBasePlate(0, 0, 7);
scene.showBasePlate();
Selection chest1 = util.select()
.fromTo(5, 2, 3, 5, 2, 4);
BlockPos funnel1 = util.grid()
.at(4, 2, 2);
BlockPos funnel2 = util.grid()
.at(1, 2, 2);
Selection funnel1S = util.select()
.position(funnel1);
Selection funnel2S = util.select()
.position(funnel2);
BlockPos packager1 = util.grid()
.at(5, 2, 2);
BlockPos packager2 = util.grid()
.at(1, 2, 3);
Selection packager1S = util.select()
.position(packager1);
Selection packager2S = util.select()
.position(packager2);
Selection largeCog = util.select()
.position(7, 0, 3);
Selection cogNBelt = util.select()
.fromTo(6, 1, 2, 0, 1, 2)
.add(util.select()
.position(6, 1, 3));
BlockPos lever = util.grid()
.at(5, 3, 2);
Selection scaff1 = util.select()
.fromTo(5, 1, 3, 5, 1, 4);
Selection scaff2 = util.select()
.fromTo(1, 1, 3, 1, 1, 4);
scene.idle(5);
ElementLink<WorldSectionElement> chestL = scene.world()
.showIndependentSection(chest1, Direction.DOWN);
scene.world()
.moveSection(chestL, util.vector()
.of(-2, -1, 0), 0);
scene.idle(10);
ElementLink<WorldSectionElement> packagerL = scene.world()
.showIndependentSection(packager1S, Direction.SOUTH);
scene.world()
.moveSection(packagerL, util.vector()
.of(-2, -1, 0), 0);
scene.idle(20);
ItemStack dirt = new ItemStack(Items.DIRT);
scene.overlay()
.showControls(util.vector()
.of(2.5, 3, 2.5), Pointing.DOWN, 40)
.withItem(dirt);
scene.idle(20);
scene.overlay()
.showText(80)
.text("Place packagers next to the inventory they should target")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector()
.of(2, 2.5, 2.5));
scene.idle(60);
ElementLink<WorldSectionElement> leverL = scene.world()
.showIndependentSection(util.select()
.position(lever), Direction.DOWN);
scene.world()
.moveSection(leverL, util.vector()
.of(-2, -1, 0), 0);
scene.idle(30);
scene.world()
.toggleRedstonePower(util.select()
.fromTo(lever, packager1));
scene.effects()
.indicateRedstone(lever.west(2)
.below());
scene.idle(10);
ItemStack box = PackageStyles.getDefaultBox()
.copy();
PackageItem.addAddress(box, "Warehouse");
PonderHilo.packagerCreate(scene, packager1, box);
scene.idle(30);
scene.overlay()
.showText(80)
.text("Given redstone power, it will pack items from the inventory into a package")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(3, 1, 2), Direction.UP));
scene.idle(30);
scene.idle(80);
scene.world()
.moveSection(leverL, util.vector()
.of(2, 1, 0), 10);
scene.world()
.moveSection(packagerL, util.vector()
.of(2, 1, 0), 10);
scene.world()
.moveSection(chestL, util.vector()
.of(2, 1, 0), 10);
scene.world()
.showSection(scaff1, Direction.UP);
scene.idle(10);
scene.world()
.showSection(largeCog, Direction.UP);
scene.world()
.showSection(cogNBelt, Direction.SOUTH);
scene.idle(10);
scene.world()
.showSection(funnel1S, Direction.DOWN);
scene.idle(15);
scene.world()
.createItemOnBelt(util.grid()
.at(4, 1, 2), Direction.EAST, box);
PonderHilo.packagerClear(scene, packager1);
scene.idle(20);
scene.world()
.toggleRedstonePower(util.select()
.fromTo(5, 2, 2, 5, 3, 2));
scene.idle(10);
scene.world()
.multiplyKineticSpeed(util.select()
.everywhere(), 1 / 16f);
scene.overlay()
.showText(70)
.text("These can be picked up and transported like any other item")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(3, 2, 2), Direction.EAST));
scene.idle(80);
scene.world()
.multiplyKineticSpeed(util.select()
.everywhere(), 16f);
scene.idle(10);
scene.world()
.showSection(scaff2, Direction.DOWN);
scene.idle(5);
scene.world()
.showSection(packager2S, Direction.DOWN);
scene.world()
.showSection(util.select()
.position(1, 2, 4), Direction.DOWN);
scene.idle(10);
scene.world()
.showSection(funnel2S, Direction.SOUTH);
scene.rotateCameraY(-15);
scene.idle(40);
scene.world()
.removeItemsFromBelt(util.grid()
.at(1, 1, 2));
scene.world()
.flapFunnel(util.grid()
.at(1, 2, 2), false);
PonderHilo.packagerUnpack(scene, packager2, box);
scene.idle(20);
scene.overlay()
.showControls(util.vector()
.topOf(util.grid()
.at(1, 2, 4)),
Pointing.DOWN, 40)
.withItem(dirt);
scene.idle(20);
scene.overlay()
.showText(90)
.text("Packages inserted will be destroyed, unpacking the contents into the inventory")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(1, 2, 3), Direction.WEST));
scene.idle(100);
scene.world()
.toggleRedstonePower(util.select()
.fromTo(5, 2, 2, 5, 3, 2));
scene.effects()
.indicateRedstone(util.grid()
.at(5, 3, 2));
PonderHilo.packagerCreate(scene, packager1, box);
scene.idle(25);
scene.world()
.createItemOnBelt(util.grid()
.at(4, 1, 2), Direction.EAST, box);
PonderHilo.packagerClear(scene, packager1);
scene.idle(30);
scene.overlay()
.showText(60)
.text("Full")
.colored(PonderPalette.RED)
.placeNearTarget()
.pointAt(util.vector()
.topOf(util.grid()
.at(1, 2, 4)));
scene.idle(80);
scene.overlay()
.showOutlineWithText(util.select()
.fromTo(1, 2, 3, 1, 2, 4), 90)
.text("Packagers will not accept packages they cannot fully unpack")
.colored(PonderPalette.RED)
.placeNearTarget()
.attachKeyFrame()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(1, 2, 3), Direction.WEST));
scene.idle(40);
PonderHilo.packageHopsOffBelt(scene, util.grid()
.at(0, 1, 2), Direction.WEST);
scene.idle(40);
}
public static void packagerAddress(SceneBuilder builder, SceneBuildingUtil util) {
CreateSceneBuilder scene = new CreateSceneBuilder(builder);
scene.title("packager_address", "Routing packages with an address");
scene.configureBasePlate(0, 0, 9);
scene.scaleSceneView(.875f);
scene.showBasePlate();
Selection frogport = util.select()
.position(7, 1, 1);
Selection postbox = util.select()
.fromTo(6, 1, 2, 6, 2, 2);
Selection northBelt = util.select()
.fromTo(3, 1, 3, 4, 1, 0);
Selection initialKinetics = util.select()
.fromTo(3, 1, 5, 3, 1, 9);
Selection largeCog = util.select()
.position(2, 0, 9);
Selection saw = util.select()
.fromTo(2, 1, 5, 0, 1, 4);
Selection eastBelt = util.select()
.fromTo(3, 1, 4, 8, 1, 4);
Selection tunnelS = util.select()
.position(4, 2, 4);
Selection chest = util.select()
.fromTo(7, 2, 8, 7, 2, 7);
Selection scaffold = util.select()
.fromTo(7, 1, 8, 7, 1, 7);
BlockPos packager = util.grid()
.at(7, 2, 6);
Selection packagerAndLever = util.select()
.fromTo(7, 2, 6, 7, 3, 6);
Selection packagerBelt = util.select()
.fromTo(7, 1, 6, 4, 1, 6);
BlockPos funnel = util.grid()
.at(6, 2, 6);
Selection signS = util.select()
.position(7, 2, 5);
scene.idle(10);
ElementLink<WorldSectionElement> chestL = scene.world()
.showIndependentSection(chest, Direction.DOWN);
scene.world()
.moveSection(chestL, util.vector()
.of(-2, -1, -2), 0);
scene.idle(5);
scene.world()
.showSectionAndMerge(packagerAndLever, Direction.SOUTH, chestL);
scene.idle(20);
scene.world()
.showSectionAndMerge(signS, Direction.SOUTH, chestL);
scene.idle(15);
scene.overlay()
.showText(40)
.text("Warehouse")
.colored(PonderPalette.OUTPUT)
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(5, 1, 4), Direction.NORTH)
.add(-0.5, 0, 0));
scene.idle(50);
scene.overlay()
.showText(60)
.text("When a sign is placed on a packager..")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(5, 1, 4), Direction.NORTH)
.add(-0.5, 0, 0));
scene.idle(50);
scene.world()
.toggleRedstonePower(packagerAndLever);
scene.effects()
.indicateRedstone(util.grid()
.at(5, 1, 4));
ItemStack box = PackageStyles.getDefaultBox()
.copy();
PonderHilo.packagerCreate(scene, packager, box);
scene.idle(20);
scene.world()
.moveSection(chestL, util.vector()
.of(0, 1, 0), 10);
scene.idle(10);
scene.world()
.showSectionAndMerge(scaffold, Direction.NORTH, chestL);
scene.world()
.showSection(largeCog, Direction.UP);
scene.world()
.showSection(initialKinetics, Direction.NORTH);
scene.world()
.showSectionAndMerge(packagerBelt, Direction.SOUTH, chestL);
scene.idle(5);
scene.world()
.showSectionAndMerge(util.select()
.position(funnel), Direction.DOWN, chestL);
scene.idle(15);
PonderHilo.packagerClear(scene, packager);
scene.world()
.createItemOnBelt(util.grid()
.at(6, 1, 6), Direction.EAST, box);
scene.idle(20);
scene.world()
.multiplyKineticSpeed(util.select()
.everywhere(), 1 / 32f);
scene.overlay()
.showText(40)
.text("\u2192 Warehouse")
.colored(PonderPalette.OUTPUT)
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(3, 2, 4), Direction.NORTH));
scene.idle(50);
scene.overlay()
.showText(100)
.text("Created packages will carry the written line of text as their address")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(3, 2, 4), Direction.NORTH)
.add(-0.5, 0, 0));
scene.idle(120);
scene.world()
.hideIndependentSection(chestL, Direction.NORTH);
scene.idle(15);
scene.world()
.removeItemsFromBelt(util.grid()
.at(5, 1, 6));
scene.world()
.removeItemsFromBelt(util.grid()
.at(4, 1, 6));
scene.idle(15);
scene.world()
.showSection(eastBelt, Direction.WEST);
scene.idle(5);
scene.world()
.showSection(tunnelS, Direction.DOWN);
scene.idle(5);
scene.world()
.showSection(saw, Direction.EAST);
scene.idle(5);
scene.world()
.showSection(northBelt, Direction.SOUTH);
scene.rotateCameraY(-15);
scene.idle(15);
scene.overlay()
.showControls(util.vector()
.of(4, 2.825, 4.5), Pointing.DOWN, 60)
.withItem(AllItems.PACKAGE_FILTER.asStack());
scene.idle(10);
scene.overlay()
.showFilterSlotInput(util.vector()
.of(4.1, 2.825, 4.5), 50);
scene.idle(30);
scene.overlay()
.showText(70)
.text("Package filters route packages based on their address")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector()
.of(4, 2.825, 4.5));
scene.idle(70);
ItemStack warehouseBox = PackageStyles.getDefaultBox()
.copy();
ItemStack factoryBox = PackageItem.containing(List.of(new ItemStack(Items.IRON_INGOT)));
PackageItem.addAddress(warehouseBox, "Warehouse");
PackageItem.addAddress(factoryBox, "Factory");
scene.world()
.createItemOnBelt(util.grid()
.at(6, 1, 4), Direction.EAST, warehouseBox);
scene.idle(10);
scene.overlay()
.showText(50)
.text("\u2192 Warehouse")
.colored(PonderPalette.OUTPUT)
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(7, 2, 4), Direction.WEST));
scene.overlay()
.showText(50)
.colored(PonderPalette.BLUE)
.text("Factory")
.placeNearTarget()
.pointAt(util.vector()
.of(4, 2.825, 4.5));
scene.idle(60);
scene.world()
.multiplyKineticSpeed(util.select()
.everywhere(), 32f);
scene.idle(60);
scene.world()
.createItemOnBelt(util.grid()
.at(6, 1, 4), Direction.EAST, factoryBox);
scene.world()
.multiplyKineticSpeed(util.select()
.everywhere(), 1 / 32f);
scene.idle(10);
scene.overlay()
.showText(50)
.text("\u2192 Factory")
.colored(PonderPalette.OUTPUT)
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(7, 2, 4), Direction.WEST));
scene.overlay()
.showText(50)
.colored(PonderPalette.BLUE)
.text("Factory")
.placeNearTarget()
.pointAt(util.vector()
.of(4, 2.825, 4.5));
scene.idle(60);
scene.world()
.multiplyKineticSpeed(util.select()
.everywhere(), 32f);
scene.idle(40);
PonderHilo.packageHopsOffBelt(scene, util.grid()
.at(4, 1, 0), Direction.NORTH);
scene.idle(40);
scene.world()
.multiplyKineticSpeed(util.select()
.everywhere(), 1 / 32f);
scene.overlay()
.showText(100)
.text("For compactness, mechanical saws can unwrap packages straight onto a belt")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector()
.topOf(util.grid()
.at(2, 1, 4)));
scene.idle(110);
scene.world()
.multiplyKineticSpeed(util.select()
.everywhere(), 32f);
scene.idle(20);
scene.world()
.hideSection(eastBelt, Direction.EAST);
scene.idle(5);
scene.world()
.hideSection(tunnelS, Direction.UP);
scene.idle(5);
scene.world()
.hideSection(saw, Direction.WEST);
scene.idle(5);
scene.world()
.hideSection(initialKinetics, Direction.UP);
scene.world()
.hideSection(largeCog, Direction.DOWN);
scene.world()
.hideSection(northBelt, Direction.NORTH);
scene.rotateCameraY(15);
scene.idle(15);
ElementLink<WorldSectionElement> extrasL = scene.world()
.showIndependentSection(postbox, Direction.DOWN);
scene.world()
.moveSection(extrasL, util.vector()
.of(-3, 0, 2), 0);
scene.idle(5);
scene.world()
.showSectionAndMerge(frogport, Direction.DOWN, extrasL);
scene.idle(20);
scene.overlay()
.showText(100)
.text("Aside from those filters, Frogports and Postboxes have package routing capabilities")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(3, 2, 4), Direction.NORTH));
scene.idle(110);
scene.overlay()
.showText(80)
.text("Inspect them to find out more about their behaviour")
.placeNearTarget()
.pointAt(util.vector()
.blockSurface(util.grid()
.at(3, 2, 4), Direction.NORTH));
scene.idle(90);
}
}

View file

@ -0,0 +1,54 @@
package com.simibubi.create.infrastructure.ponder.scenes.highLogistics;
import com.simibubi.create.content.logistics.box.PackageEntity;
import com.simibubi.create.content.logistics.box.PackageStyles;
import com.simibubi.create.content.logistics.packager.PackagerBlockEntity;
import com.simibubi.create.foundation.ponder.CreateSceneBuilder;
import net.createmod.ponder.api.element.ElementLink;
import net.createmod.ponder.api.element.EntityElement;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
public class PonderHilo {
public static void packagerCreate(CreateSceneBuilder scene, BlockPos pos, ItemStack box) {
scene.world()
.modifyBlockEntity(pos, PackagerBlockEntity.class, be -> {
be.animationTicks = PackagerBlockEntity.CYCLE;
be.animationInward = false;
be.heldBox = box;
});
}
public static void packagerUnpack(CreateSceneBuilder scene, BlockPos pos, ItemStack box) {
scene.world()
.modifyBlockEntity(pos, PackagerBlockEntity.class, be -> {
be.animationTicks = PackagerBlockEntity.CYCLE;
be.animationInward = true;
be.previouslyUnwrapped = box;
});
}
public static void packagerClear(CreateSceneBuilder scene, BlockPos pos) {
scene.world()
.modifyBlockEntity(pos, PackagerBlockEntity.class, be -> be.heldBox = ItemStack.EMPTY);
}
public static ElementLink<EntityElement> packageHopsOffBelt(CreateSceneBuilder scene, BlockPos beltPos,
Direction side) {
scene.world()
.removeItemsFromBelt(beltPos);
return scene.world()
.createEntity(l -> {
PackageEntity packageEntity = new PackageEntity(l, beltPos.getX() + 0.5 + side.getStepX() * 0.25,
beltPos.getY() + 0.875, beltPos.getZ() + 0.5 + side.getStepZ() * 0.25);
packageEntity.setDeltaMovement(new Vec3(side.getStepX(), 0.5f, side.getStepZ()).scale(0.25f));
packageEntity.box = PackageStyles.getDefaultBox();
return packageEntity;
});
}
}

View file

@ -1,13 +0,0 @@
#include "flywheel:util/matrix.glsl"
#include "flywheel:util/quaternion.glsl"
void flw_instanceVertex(in FlwInstance instance) {
float degrees = instance.offset + flw_renderSeconds * instance.speed;
vec4 kineticRot = quaternionDegrees(instance.axis, degrees);
vec3 rotated = rotateByQuaternion(flw_vertexPos.xyz - instance.rotationCenter, kineticRot) + instance.rotationCenter;
flw_vertexPos.xyz = rotateByQuaternion(rotated - .5, instance.rotation) + instance.pos + .5;
flw_vertexNormal = rotateByQuaternion(rotateByQuaternion(flw_vertexNormal, kineticRot), instance.rotation);
flw_vertexLight = max(vec2(instance.light) / 256., flw_vertexLight);
}

View file

@ -1,8 +0,0 @@
void flw_transformBoundingSphere(in FlwInstance instance, inout vec3 center, inout float radius) {
// The instance will spin about the rotation center, so we need to expand the radius to account for that
float extraForKinetic = length(center - instance.rotationCenter);
float extraForModel = length(center - 0.5);
radius += extraForKinetic + extraForModel;
center += instance.pos;
}

View file

@ -1,5 +1,5 @@
void flw_transformBoundingSphere(in FlwInstance instance, inout vec3 center, inout float radius) {
// The instance will spin about (0.5, 0.5, 0.5), so we need to expand the radius to account for that
// The instance will spin about the rotation center, so we need to expand the radius to account for that
radius += length(center - 0.5);
center += instance.pos;
}

View file

@ -1,21 +1,15 @@
#include "flywheel:util/matrix.glsl"
const float uTime = 0.;
mat3 kineticRotation(float offset, float speed, vec3 axis) {
float degrees = offset + flw_renderTicks * speed * 3./10.;
return rotationDegrees(axis, degrees);
}
#include "flywheel:util/quaternion.glsl"
void flw_instanceVertex(in FlwInstance instance) {
mat3 spin = kineticRotation(instance.offset, instance.speed, instance.axis);
float degrees = instance.offset + flw_renderSeconds * instance.speed;
vec3 worldPos = spin * (flw_vertexPos.xyz - .5);
flw_vertexPos.xyz = worldPos.xyz + instance.pos + .5;
vec4 kineticRot = quaternionDegrees(instance.axis, degrees);
vec3 rotated = rotateByQuaternion(flw_vertexPos.xyz - .5, instance.rotation);
flw_vertexNormal = spin * flw_vertexNormal;
flw_vertexOverlay = instance.overlay;
flw_vertexPos.xyz = rotateByQuaternion(rotated, kineticRot) + instance.pos + .5;
flw_vertexNormal = rotateByQuaternion(rotateByQuaternion(flw_vertexNormal, instance.rotation), kineticRot);
flw_vertexLight = max(vec2(instance.light) / 256., flw_vertexLight);
flw_vertexOverlay = instance.overlay;
#if defined(DEBUG_RAINBOW)
flw_vertexColor = instance.color;

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",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,003 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 952 B

View file

@ -24,10 +24,6 @@
"type": "single",
"resource": "create:entity/blueprint_small"
},
{
"type": "single",
"resource": "create:entity/display_cloth"
},
{
"type": "single",
"resource": "create:entity/coupling"