Squashed commit of the following:

commit 053dd09df6c426ab5e570f42a1edb5df3d0fbd01
Merge: 6d1e1c71d ecc645eba
Author: simibubi <31564874+simibubi@users.noreply.github.com>
Date:   Tue May 9 18:22:42 2023 +0200

    Merge branch '1.18/api' of https://github.com/Layers-of-Railways/Create into pr/4692

commit ecc645eba7
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Tue May 9 11:24:11 2023 +0100

    Implemented support for creating and removing individual blockstate models

commit 6d1e1c71de7ce20f6fd9fc8ed4ed9bdd1072829a
Author: simibubi <31564874+simibubi@users.noreply.github.com>
Date:   Tue May 9 12:16:54 2023 +0200

    Less error logging when migrating old worlds

commit 205e47352e
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 8 21:02:19 2023 -0700

    Fix up ItemOutline

commit 6cf204f6af
Merge: fe049bc77 2e3c906ce
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 8 20:28:56 2023 -0700

    Merge remote-tracking branch 'upstream/mc1.18/dev' into 1.18/api

    # Conflicts:
    #	src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java

commit fe049bc771
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 8 20:26:16 2023 -0700

    Revert "Revert "Rewrite outline buffering""

    This reverts commit 726bfaf0

commit 435b4c1c16
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 8 20:20:23 2023 -0700

    Clean up last bits of upside down rendering

commit 662da6bab1
Merge: 122fe77af d83285e8a
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 8 20:16:32 2023 -0700

    Merge remote-tracking branch 'origin/1.18/api' into 1.18/api

    # Conflicts:
    #	src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java

commit 122fe77afa
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 8 20:15:46 2023 -0700

    Fix up upside down rendering

commit d83285e8a4
Merge: 00e953a58 cdb0ad210
Author: techno-sam <77073745+techno-sam@users.noreply.github.com>
Date:   Sun May 7 07:02:18 2023 -0700

    Merge pull request #3 from Layers-of-Railways/1.18/bogey-api

    Cleanup cycle groups and unused imports

commit cdb0ad210b
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun May 7 10:15:47 2023 +0100

    Fixed merge artifact

commit 457d5f33ed
Merge: 4e4e227a3 00e953a58
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun May 7 10:14:07 2023 +0100

    Merge remote-tracking branch 'origin/1.18/api' into 1.18/api

commit 00e953a585
Merge: 1e4d5504e a7a25896c
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com>
Date:   Sun May 7 10:13:49 2023 +0100

    Merge pull request #2 from Rabbitminers/mc1.18/dev

    Added Return Values and Small Cleanup

commit a7a25896c1
Merge: 7622128be 1e4d5504e
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com>
Date:   Sun May 7 10:13:40 2023 +0100

    Merge branch '1.18/api' into mc1.18/dev

commit 4e4e227a35
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun May 7 10:10:30 2023 +0100

    Cleanup to cycle groups

commit aa94fc97d1
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun May 7 09:50:50 2023 +0100

    Removed unused import of Railways

commit 7622128bec
Merge: 81eeadb85 d52065808
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com>
Date:   Sun May 7 09:11:59 2023 +0100

    Merge branch 'Layers-of-Railways:mc1.18/dev' into mc1.18/dev

commit 1e4d5504ee
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sat May 6 18:03:39 2023 -0700

    Don't revert non-buggy changes

commit b306cf2124
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sat May 6 18:00:59 2023 -0700

    Take materials into consideration when trains pathfind

commit fca02ae4bf
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sat May 6 10:25:51 2023 -0700

    Add materials to track graph

commit 726bfaf0b5
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Fri May 5 21:16:49 2023 -0700

    Revert "Rewrite outline buffering"

    This reverts commit d4106d545b.

commit 171897bed2
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Fri May 5 20:55:25 2023 -0700

    Fix up style cycling

commit cbd0cf20da
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Fri May 5 07:32:06 2023 -0700

    clean up nether portal carriage handling

commit d556f08876
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Fri May 5 07:06:02 2023 -0700

    upside down bogeys work in nether portals
    fixed coupling anchor offsets

commit da26c0ccbf
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Thu May 4 09:32:53 2023 -0700

    working on upside down bogeys in nether portals

commit 81eeadb853
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon May 1 16:15:28 2023 +0100

    Small cleanup

commit c7e9df973c
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon May 1 16:13:51 2023 +0100

    Fixed issue raised in #1

commit 2f285b6eb7
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 1 08:13:27 2023 -0700

    add data gen

commit 206de01311
Merge: e91753a33 6564f4fa7
Author: techno-sam <77073745+techno-sam@users.noreply.github.com>
Date:   Mon May 1 06:49:21 2023 -0700

    Merge pull request #1 from Rabbitminers/mc1.18/dev

    Bogey API

commit 6564f4fa73
Merge: e5d759582 e91753a33
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com>
Date:   Mon May 1 10:40:32 2023 +0100

    Merge branch '1.18/api' into mc1.18/dev

commit e5d7595822
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon May 1 10:09:03 2023 +0100

    Connected Custom Bogey Particle Types To CarriageParticles

commit e91753a33c
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sun Apr 30 19:51:26 2023 -0700

    Fix up some problems

commit 9815f1490f
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 21:12:43 2023 +0100

    Implemented default data when shifting styles

commit da30e78815
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 21:12:14 2023 +0100

    Added Particles To Bogey Style (And Respective Builder)

commit 08c000b8ba
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 21:01:19 2023 +0100

    Added Backup Rendering If A Size Is Not Present

commit 2b76e8d7b3
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 21:00:40 2023 +0100

    Added Common Renderer To Remove Function

commit 411ec36f57
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:59:50 2023 +0100

    Added Display Name To Standard Bogey Style

commit 112306d5d4
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:59:30 2023 +0100

    Displayed new style name when changing betweeen them

commit 5634670b27
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:06:00 2023 +0100

    General Cleanup

commit 0f7a8b7b24
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:05:50 2023 +0100

    Implemented Changes To Remaining Classes

commit 8aedc00f96
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:02:06 2023 +0100

    Removed Bogey Style Handling From Registrate

commit edf8079abf
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:01:40 2023 +0100

    Removed Unused Registry Handling

commit 6a185c4e72
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:01:16 2023 +0100

    Refactored Bogey Sizes

commit e10d07ddc3
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:01:00 2023 +0100

    Overhauled Bogey Style

commit 74d98a2ad5
Merge: e629d02f5 4ebcf8201
Author: techno-sam <77073745+techno-sam@users.noreply.github.com>
Date:   Sun Apr 23 07:16:33 2023 -0700

    Merge branch 'Creators-of-Create:mc1.18/dev' into 1.18/api

commit e629d02f50
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sun Apr 9 07:18:22 2023 -0700

    Track API

    Clean up code a bit

commit d9ce6ce995
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sun Apr 9 07:14:46 2023 -0700

    Track API?

    Fix placement

commit 7fbf08ba54
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sat Apr 8 11:11:24 2023 -0700

    Track API?

    Fix up some placement issues

commit 35644f1434
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sat Apr 8 08:11:13 2023 -0700

    Track API maybe?

    Datagen
    Seems to be working

commit f7c56b867a
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Thu Apr 6 21:24:31 2023 -0700

    Track API maybe?

    Fix build - broken generic
    Not yet tested, but it is progress

commit 2a59fd7e8a
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Thu Apr 6 21:13:54 2023 -0700

    Track API maybe?

    Not yet tested, but it is progress

commit 5ba30d6a85
Merge: e4e5ac1c4 c2977bbff
Author: techno-sam <77073745+techno-sam@users.noreply.github.com>
Date:   Thu Apr 6 17:10:39 2023 -0700

    Merge branch 'Creators-of-Create:mc1.18/dev' into 1.18/api

commit d52065808c
Merge: e4e5ac1c4 c2977bbff
Author: techno-sam <77073745+techno-sam@users.noreply.github.com>
Date:   Thu Apr 6 17:10:26 2023 -0700

    Merge branch 'Creators-of-Create:mc1.18/dev' into mc1.18/dev

commit 53240bd42f
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 21:42:29 2023 +0100

    Corrected Bogey InteractionResult To Pass

commit 69326e361a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 21:30:28 2023 +0100

    Fixed Default Values When Used Styles Are Removed

commit 4f176979de
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 19:33:17 2023 +0100

    Fixed Carriage Sounds (Again)

commit 1e80af3303
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 19:27:58 2023 +0100

    Refactored Bogey Sizes To Seperate Class

commit 129be61fee
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 17:20:17 2023 +0100

    Fixed Bogey Sound Loading

commit 2543185a55
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 09:45:23 2023 +0100

    Added Bogey Sound Customisation

commit 1ad5ae9514
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 00:44:53 2023 +0100

    Added Size Transforms If Size Is Not Available For New Style

commit 96566b1614
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 2 23:02:02 2023 +0100

    Moved Bogey Style Inside Of Bogey Data And Implemented Bogey Data Communication

commit eedd984738
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 2 16:53:55 2023 +0100

    Fixed Large Bogey Size

commit 68ca0974c6
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 2 16:47:58 2023 +0100

    Implemented Style Cycling & Default Values

commit a55ba4267a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 2 16:46:15 2023 +0100

    Implemented renderer instance creator

commit 43523302c2
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 2 16:45:33 2023 +0100

    Removed Unused Standard Bogey Instance

commit 773e084422
Merge: 0c0b5a1ed d1e1f7ec5
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sat Apr 1 18:50:15 2023 +0100

    Merge remote-tracking branch 'origin/mc1.18/dev' into mc1.18/dev

    # Conflicts:
    #	src/main/java/com/simibubi/create/AllBogeyStyles.java
    #	src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java
    #	src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java
    #	src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java
    #	src/main/java/com/simibubi/create/content/logistics/trains/entity/StandardBogeyInstance.java
    #	src/main/java/com/simibubi/create/foundation/data/BogeyStyleBuilder.java

commit 0c0b5a1ed6
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sat Apr 1 18:39:58 2023 +0100

    Linked Style Registry To Bogey Blocks

commit 71f839ee51
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sat Apr 1 18:39:03 2023 +0100

    Replaced size boolean with direct use of size enum

commit 50ff081704
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 30 18:47:13 2023 +0100

    Added Resource Location To NBT helper methods

commit d1e1f7ec5a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 30 18:47:13 2023 +0100

    Re-worked BogeyStyles

commit da593fccb1
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 30 18:46:02 2023 +0100

    Refactored IBogeyBlock to AbstractBogeyBlock and extracted relevant StandardBogeyBlock implementations

commit 17432c9113
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sat Mar 25 10:20:50 2023 +0000

    Fixed Incorrect Registry Loading

commit c7d899369a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:44:03 2023 +0000

    Registered Registers

commit 6d862290d7
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:43:23 2023 +0000

    Added BogeyStyleBuilder To Registrate

commit 3dfb9e3b3b
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:43:08 2023 +0000

    Implemented AllBogeyStyles

commit c9e71b462d
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:42:56 2023 +0000

    Created BogeyStyleBuilder

commit a90977d642
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:42:25 2023 +0000

    Created AllRegistries and BogeyStyle Registry

commit 154d455f3f
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:41:56 2023 +0000

    Added BogeyStyle Wrapper

commit dfb7640bfc
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:50:41 2023 +0000

    Removed left over logging statement

commit 9920536cc3
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:50:18 2023 +0000

    Implemented Secondary Shaft To Large Renderer

commit 6cd40cc6f9
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:49:56 2023 +0000

    Prevented Overwrite When Using Two BlockStates Of The Same Type With Different Properties

commit 06fb901144
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:39:11 2023 +0000

    Implemented Common Rendering For StandardBogeyRenderer

commit 435b0f8266
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:38:40 2023 +0000

    Added Common Renderer

commit 96a0623dab
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:38:29 2023 +0000

    Implemented BlockState Models For Rendering

commit 469d9d592b
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:42:28 2023 +0000

    Added Standard Bogey Instance (Might be redundant)

commit 2661d260d8
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:42:06 2023 +0000

    Refactored Changes To Existing Methods

commit 9ded16fbab
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:41:15 2023 +0000

    Integrated BogeyRenderer To BogeyInstance (Also Corrected Rendering In Contraption)

commit 4a82fcbca1
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:40:13 2023 +0000

    Implemented Changes To StandardBogeyBlock

commit 7238fb93f3
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:39:51 2023 +0000

    Added Renderer To IBogeyBlock

commit ded4c1f613
Merge: 91727cc84 3c02fe6ec
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Wed Mar 22 17:03:37 2023 +0000

    Merge remote-tracking branch 'origin/mc1.18/dev' into mc1.18/dev

commit 91727cc84a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Wed Mar 22 17:03:28 2023 +0000

    Implemented Model Data Initializer to StandardBogeyRenderer

commit 6d98a1f469
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Wed Mar 22 17:03:00 2023 +0000

    Added Contraption Model Instance Initializer

commit 3c02fe6ecc
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com>
Date:   Tue Mar 21 22:45:34 2023 +0000

    Added missing render type check

commit 6672c49649
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Tue Mar 21 22:37:36 2023 +0000

    Re-created standard bogey with test api

commit a8a9491fa0
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Tue Mar 21 22:34:54 2023 +0000

    Implemented Proof Of Concept Generic Bogey Renderer

commit e4e5ac1c40
Author: SpottyTheTurtle <69260662+SpottyTheTurtle@users.noreply.github.com>
Date:   Sat Mar 11 21:34:59 2023 +0000

    init
This commit is contained in:
simibubi 2023-05-09 18:23:47 +02:00
parent 2e3c906ce0
commit e5c6ca157c
77 changed files with 2357 additions and 711 deletions

3
.gitignore vendored
View file

@ -42,4 +42,5 @@ local.properties
# PDT-specific # PDT-specific
.buildpath .buildpath
.DS_Store .DS_Store
/libs/

View file

@ -135,6 +135,9 @@ repositories {
includeGroup "maven.modrinth" includeGroup "maven.modrinth"
} }
} }
flatDir {
dirs 'libs'
}
} }
dependencies { dependencies {
@ -169,6 +172,7 @@ dependencies {
// runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.5-1.6.115") // runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.5-1.6.115")
// runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252") // runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252")
// runtimeOnly fg.deobf("maven.modrinth:rubidium:0.5.3") // runtimeOnly fg.deobf("maven.modrinth:rubidium:0.5.3")
// implementation fg.deobf("com.railwayteam.railways:railways-1.18.2-1.1.1:all") { transitive = false }
// https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497 // https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497
// Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings // Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings

View file

@ -559,7 +559,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
f85edc574ee6de0de7693ffb031266643db6724a assets/create/lang/en_ud.json f85edc574ee6de0de7693ffb031266643db6724a assets/create/lang/en_ud.json
eb624aafc91b284143c3a0cc7d9bbb8de66e8950 assets/create/lang/en_us.json c0b485449804a49390ef01491350a2878b2b57bd assets/create/lang/en_us.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
@ -5611,6 +5611,7 @@ ac265a674626e0e832330086fd18fe0be37fc327 data/create/recipes/weathered_copper_ti
2a2700b43614f86d3294726595cb28ed7dca4387 data/create/tags/blocks/brittle.json 2a2700b43614f86d3294726595cb28ed7dca4387 data/create/tags/blocks/brittle.json
d99d5c67bdffff60789a19bd51a5c5267c75e0a4 data/create/tags/blocks/casing.json d99d5c67bdffff60789a19bd51a5c5267c75e0a4 data/create/tags/blocks/casing.json
2b4c93e5a752ebf54217594766f30d8d60cb4343 data/create/tags/blocks/fan_transparent.json 2b4c93e5a752ebf54217594766f30d8d60cb4343 data/create/tags/blocks/fan_transparent.json
ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/girdable_tracks.json
ee6d2b53d81f2bed492662b6c06f46c4f2b9ef9b data/create/tags/blocks/movable_empty_collider.json ee6d2b53d81f2bed492662b6c06f46c4f2b9ef9b data/create/tags/blocks/movable_empty_collider.json
6e5d3b2123fbb00e7f439c091623619502551bca data/create/tags/blocks/non_movable.json 6e5d3b2123fbb00e7f439c091623619502551bca data/create/tags/blocks/non_movable.json
10781e8cfcbb3486327aace3aa00e437fb44b331 data/create/tags/blocks/ore_override_stone.json 10781e8cfcbb3486327aace3aa00e437fb44b331 data/create/tags/blocks/ore_override_stone.json
@ -5618,6 +5619,7 @@ ee6d2b53d81f2bed492662b6c06f46c4f2b9ef9b data/create/tags/blocks/movable_empty_c
23eb7cf8abff36f85320c35c69b98fdb775c8ec9 data/create/tags/blocks/safe_nbt.json 23eb7cf8abff36f85320c35c69b98fdb775c8ec9 data/create/tags/blocks/safe_nbt.json
6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json 6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json
d063e12c9ef75f39518c6d129ea35d833464d547 data/create/tags/blocks/toolboxes.json d063e12c9ef75f39518c6d129ea35d833464d547 data/create/tags/blocks/toolboxes.json
ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/tracks.json
9460e92c8e483446318b849abe7e6f52dcd4a269 data/create/tags/blocks/tree_attachments.json 9460e92c8e483446318b849abe7e6f52dcd4a269 data/create/tags/blocks/tree_attachments.json
50936b211d94167a35ec78c89954082a336b6269 data/create/tags/blocks/valve_handles.json 50936b211d94167a35ec78c89954082a336b6269 data/create/tags/blocks/valve_handles.json
eac71740fb12bdb38b5dfaa2268613d7ba82b809 data/create/tags/blocks/windmill_sails.json eac71740fb12bdb38b5dfaa2268613d7ba82b809 data/create/tags/blocks/windmill_sails.json

View file

@ -1754,6 +1754,12 @@
"enchantment.create.capacity.desc": "Increases Backtank air capacity.", "enchantment.create.capacity.desc": "Increases Backtank air capacity.",
"enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.", "enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.",
"create.bogey.style.updated_style": "Updated style",
"create.bogey.style.updated_style_and_size": "Updated style and size",
"create.bogey.style.no_other_sizes": "No other sizes",
"create.bogey.style.invalid": "Unnamed style",
"create.bogey.style.standard": "Standard",
"_": "->------------------------] Subtitles [------------------------<-", "_": "->------------------------] Subtitles [------------------------<-",

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"create:track"
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"create:track"
]
}

View file

@ -207,6 +207,9 @@ import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock;
import com.simibubi.create.content.logistics.block.vault.ItemVaultCTBehaviour; import com.simibubi.create.content.logistics.block.vault.ItemVaultCTBehaviour;
import com.simibubi.create.content.logistics.block.vault.ItemVaultItem; import com.simibubi.create.content.logistics.block.vault.ItemVaultItem;
import com.simibubi.create.content.logistics.item.LecternControllerBlock; import com.simibubi.create.content.logistics.item.LecternControllerBlock;
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
import com.simibubi.create.content.logistics.trains.BogeySizes;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayBlock; import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayBlock;
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem;
@ -667,7 +670,7 @@ public class AllBlocks {
.onRegister(movementBehaviour(new BlazeBurnerMovementBehaviour())) .onRegister(movementBehaviour(new BlazeBurnerMovementBehaviour()))
.onRegister(interactionBehaviour(new BlazeBurnerInteractionBehaviour())) .onRegister(interactionBehaviour(new BlazeBurnerInteractionBehaviour()))
.item(BlazeBurnerBlockItem::withBlaze) .item(BlazeBurnerBlockItem::withBlaze)
.model(AssetLookup.<BlazeBurnerBlockItem>customBlockItemModel("blaze_burner", "block_with_blaze")) .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze"))
.build() .build()
.register(); .register();
@ -926,7 +929,7 @@ public class AllBlocks {
.onRegister(assignDataBehaviour(new BoilerDisplaySource(), "boiler_status")) .onRegister(assignDataBehaviour(new BoilerDisplaySource(), "boiler_status"))
.addLayer(() -> RenderType::cutoutMipped) .addLayer(() -> RenderType::cutoutMipped)
.item(FluidTankItem::new) .item(FluidTankItem::new)
.model(AssetLookup.<FluidTankItem>customBlockItemModel("_", "block_single_window")) .model(AssetLookup.customBlockItemModel("_", "block_single_window"))
.build() .build()
.register(); .register();
@ -1500,7 +1503,7 @@ public class AllBlocks {
.transform(customItemModel()) .transform(customItemModel())
.register(); .register();
public static final BlockEntry<TrackBlock> TRACK = REGISTRATE.block("track", TrackBlock::new) public static final BlockEntry<TrackBlock> TRACK = REGISTRATE.block("track", TrackMaterial.ANDESITE::createBlock)
.initialProperties(Material.STONE) .initialProperties(Material.STONE)
.properties(p -> p.color(MaterialColor.METAL) .properties(p -> p.color(MaterialColor.METAL)
.strength(0.8F) .strength(0.8F)
@ -1510,6 +1513,8 @@ public class AllBlocks {
.transform(pickaxeOnly()) .transform(pickaxeOnly())
.blockstate(new TrackBlockStateGenerator()::generate) .blockstate(new TrackBlockStateGenerator()::generate)
.tag(AllBlockTags.RELOCATION_NOT_SUPPORTED.tag) .tag(AllBlockTags.RELOCATION_NOT_SUPPORTED.tag)
.tag(AllBlockTags.TRACKS.tag)
.tag(AllBlockTags.GIRDABLE_TRACKS.tag)
.lang("Train Track") .lang("Train Track")
.item(TrackBlockItem::new) .item(TrackBlockItem::new)
.model((c, p) -> p.generated(c, Create.asResource("item/" + c.getName()))) .model((c, p) -> p.generated(c, Create.asResource("item/" + c.getName())))
@ -1578,13 +1583,13 @@ public class AllBlocks {
.register(); .register();
public static final BlockEntry<StandardBogeyBlock> SMALL_BOGEY = public static final BlockEntry<StandardBogeyBlock> SMALL_BOGEY =
REGISTRATE.block("small_bogey", p -> new StandardBogeyBlock(p, false)) REGISTRATE.block("small_bogey", p -> new StandardBogeyBlock(p, BogeySizes.SMALL))
.properties(p -> p.color(MaterialColor.PODZOL)) .properties(p -> p.color(MaterialColor.PODZOL))
.transform(BuilderTransformers.bogey()) .transform(BuilderTransformers.bogey())
.register(); .register();
public static final BlockEntry<StandardBogeyBlock> LARGE_BOGEY = public static final BlockEntry<StandardBogeyBlock> LARGE_BOGEY =
REGISTRATE.block("large_bogey", p -> new StandardBogeyBlock(p, true)) REGISTRATE.block("large_bogey", p -> new StandardBogeyBlock(p, BogeySizes.LARGE))
.properties(p -> p.color(MaterialColor.PODZOL)) .properties(p -> p.color(MaterialColor.PODZOL))
.transform(BuilderTransformers.bogey()) .transform(BuilderTransformers.bogey())
.register(); .register();

View file

@ -0,0 +1,122 @@
package com.simibubi.create;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import com.google.common.collect.ImmutableMap;
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
import com.simibubi.create.content.logistics.trains.BogeyRenderer.CommonRenderer;
import com.simibubi.create.content.logistics.trains.BogeySizes;
import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.CommonStandardBogeyRenderer;
import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.LargeStandardBogeyRenderer;
import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.SmallStandardBogeyRenderer;
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import com.tterrag.registrate.util.entry.BlockEntry;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
public class AllBogeyStyles {
public static final Map<ResourceLocation, BogeyStyle> BOGEY_STYLES = new HashMap<>();
public static final Map<ResourceLocation, Map<ResourceLocation, BogeyStyle>> CYCLE_GROUPS = new HashMap<>();
private static final Map<ResourceLocation, BogeyStyle> EMPTY_GROUP = ImmutableMap.of();
public static Map<ResourceLocation, BogeyStyle> getCycleGroup(ResourceLocation cycleGroup) {
return CYCLE_GROUPS.getOrDefault(cycleGroup, EMPTY_GROUP);
}
public static final String STANDARD_CYCLE_GROUP = "standard";
public static final BogeyStyle STANDARD =
create("standard", STANDARD_CYCLE_GROUP).commonRenderer(CommonStandardBogeyRenderer::new)
.displayName(Components.translatable("create.bogey.style.standard"))
.size(BogeySizes.SMALL, SmallStandardBogeyRenderer::new, AllBlocks.SMALL_BOGEY)
.size(BogeySizes.LARGE, LargeStandardBogeyRenderer::new, AllBlocks.LARGE_BOGEY)
.build();
private static BogeyStyleBuilder create(String name, String cycleGroup) {
return create(Create.asResource(name), Create.asResource(cycleGroup));
}
public static BogeyStyleBuilder create(ResourceLocation name, ResourceLocation cycleGroup) {
return new BogeyStyleBuilder(name, cycleGroup);
}
public static void register() {}
public static class BogeyStyleBuilder {
protected final Map<BogeySizes.BogeySize, BogeyStyle.SizeData> sizes = new HashMap<>();
protected final ResourceLocation name;
protected final ResourceLocation cycleGroup;
protected Component displayName = Lang.translateDirect("bogey.style.invalid");
protected ResourceLocation soundType = AllSoundEvents.TRAIN2.getId();
protected CompoundTag defaultData = new CompoundTag();
protected ParticleOptions contactParticle = ParticleTypes.CRIT;
protected ParticleOptions smokeParticle = ParticleTypes.POOF;
protected Optional<Supplier<? extends CommonRenderer>> commonRenderer = Optional.empty();
public BogeyStyleBuilder(ResourceLocation name, ResourceLocation cycleGroup) {
this.name = name;
this.cycleGroup = cycleGroup;
}
public BogeyStyleBuilder displayName(Component displayName) {
this.displayName = displayName;
return this;
}
public BogeyStyleBuilder soundType(ResourceLocation soundType) {
this.soundType = soundType;
return this;
}
public BogeyStyleBuilder defaultData(CompoundTag defaultData) {
this.defaultData = defaultData;
return this;
}
public BogeyStyleBuilder size(BogeySizes.BogeySize size, Supplier<? extends BogeyRenderer> renderer,
BlockEntry<? extends AbstractBogeyBlock<?>> blockEntry) {
this.size(size, renderer, blockEntry.getId());
return this;
}
public BogeyStyleBuilder size(BogeySizes.BogeySize size, Supplier<? extends BogeyRenderer> renderer,
ResourceLocation location) {
this.sizes.put(size, new BogeyStyle.SizeData(location, renderer, renderer.get()));
return this;
}
public BogeyStyleBuilder contactParticle(ParticleOptions contactParticle) {
this.contactParticle = contactParticle;
return this;
}
public BogeyStyleBuilder smokeParticle(ParticleOptions smokeParticle) {
this.smokeParticle = smokeParticle;
return this;
}
public BogeyStyleBuilder commonRenderer(Supplier<? extends CommonRenderer> commonRenderer) {
this.commonRenderer = Optional.of(commonRenderer);
return this;
}
public BogeyStyle build() {
BogeyStyle entry =
new BogeyStyle(name, cycleGroup, displayName, soundType, contactParticle, smokeParticle, defaultData, sizes, commonRenderer);
BOGEY_STYLES.put(name, entry);
CYCLE_GROUPS.computeIfAbsent(cycleGroup, l -> new HashMap<>()).put(name, entry);
return entry;
}
}
}

View file

@ -107,6 +107,8 @@ public class AllTags {
SAFE_NBT, SAFE_NBT,
SEATS, SEATS,
TOOLBOXES, TOOLBOXES,
TRACKS,
GIRDABLE_TRACKS,
TREE_ATTACHMENTS, TREE_ATTACHMENTS,
VALVE_HANDLES, VALVE_HANDLES,
WINDMILL_SAILS, WINDMILL_SAILS,
@ -155,6 +157,10 @@ public class AllTags {
.is(tag); .is(tag);
} }
public boolean matches(ItemStack stack) {
return stack != null && stack.getItem() instanceof BlockItem blockItem && matches(blockItem.getBlock());
}
public boolean matches(BlockState state) { public boolean matches(BlockState state) {
return state.is(tag); return state.is(tag);
} }

View file

@ -182,6 +182,7 @@ import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity;
import com.simibubi.create.content.logistics.item.LecternControllerRenderer; import com.simibubi.create.content.logistics.item.LecternControllerRenderer;
import com.simibubi.create.content.logistics.item.LecternControllerTileEntity; import com.simibubi.create.content.logistics.item.LecternControllerTileEntity;
import com.simibubi.create.content.logistics.trains.BogeyTileEntityRenderer; import com.simibubi.create.content.logistics.trains.BogeyTileEntityRenderer;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayRenderer; import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayRenderer;
import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity;
import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserverRenderer; import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserverRenderer;
@ -191,7 +192,9 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationRenderer; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationRenderer;
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity;
import com.simibubi.create.content.logistics.trains.track.FakeTrackTileEntity; import com.simibubi.create.content.logistics.trains.track.FakeTrackTileEntity;
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity;
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
import com.simibubi.create.content.logistics.trains.track.TrackInstance; import com.simibubi.create.content.logistics.trains.track.TrackInstance;
import com.simibubi.create.content.logistics.trains.track.TrackRenderer; import com.simibubi.create.content.logistics.trains.track.TrackRenderer;
import com.simibubi.create.content.logistics.trains.track.TrackTileEntity; import com.simibubi.create.content.logistics.trains.track.TrackTileEntity;
@ -202,6 +205,8 @@ import com.simibubi.create.content.schematics.block.SchematicannonTileEntity;
import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer;
import com.tterrag.registrate.util.entry.BlockEntityEntry; import com.tterrag.registrate.util.entry.BlockEntityEntry;
import com.tterrag.registrate.util.nullness.NonNullSupplier;
public class AllTileEntities { public class AllTileEntities {
// Schematics // Schematics
@ -656,7 +661,7 @@ public class AllTileEntities {
.validBlocks(AllBlocks.ANALOG_LEVER) .validBlocks(AllBlocks.ANALOG_LEVER)
.renderer(() -> AnalogLeverRenderer::new) .renderer(() -> AnalogLeverRenderer::new)
.register(); .register();
public static final BlockEntityEntry<PlacardTileEntity> PLACARD = REGISTRATE public static final BlockEntityEntry<PlacardTileEntity> PLACARD = REGISTRATE
.tileEntity("placard", PlacardTileEntity::new) .tileEntity("placard", PlacardTileEntity::new)
.validBlocks(AllBlocks.PLACARD) .validBlocks(AllBlocks.PLACARD)
@ -781,9 +786,9 @@ public class AllTileEntities {
.tileEntity("track", TrackTileEntity::new) .tileEntity("track", TrackTileEntity::new)
.instance(() -> TrackInstance::new) .instance(() -> TrackInstance::new)
.renderer(() -> TrackRenderer::new) .renderer(() -> TrackRenderer::new)
.validBlocks(AllBlocks.TRACK) .validBlocks((NonNullSupplier<? extends TrackBlock>[]) TrackMaterial.allBlocks().toArray(new NonNullSupplier[0]))
.register(); .register();
public static final BlockEntityEntry<FakeTrackTileEntity> FAKE_TRACK = REGISTRATE public static final BlockEntityEntry<FakeTrackTileEntity> FAKE_TRACK = REGISTRATE
.tileEntity("fake_track", FakeTrackTileEntity::new) .tileEntity("fake_track", FakeTrackTileEntity::new)
.validBlocks(AllBlocks.FAKE_TRACK) .validBlocks(AllBlocks.FAKE_TRACK)
@ -800,7 +805,7 @@ public class AllTileEntities {
.renderer(() -> StationRenderer::new) .renderer(() -> StationRenderer::new)
.validBlocks(AllBlocks.TRACK_STATION) .validBlocks(AllBlocks.TRACK_STATION)
.register(); .register();
public static final BlockEntityEntry<SlidingDoorTileEntity> SLIDING_DOOR = REGISTRATE public static final BlockEntityEntry<SlidingDoorTileEntity> SLIDING_DOOR = REGISTRATE
.tileEntity("sliding_door", SlidingDoorTileEntity::new) .tileEntity("sliding_door", SlidingDoorTileEntity::new)
.renderer(() -> SlidingDoorRenderer::new) .renderer(() -> SlidingDoorRenderer::new)

View file

@ -2,6 +2,8 @@ package com.simibubi.create;
import java.util.Random; import java.util.Random;
import com.simibubi.create.content.logistics.trains.BogeySizes;
import org.slf4j.Logger; import org.slf4j.Logger;
import com.google.gson.Gson; import com.google.gson.Gson;
@ -121,6 +123,8 @@ public class Create {
AllFeatures.register(modEventBus); AllFeatures.register(modEventBus);
AllPlacementModifiers.register(modEventBus); AllPlacementModifiers.register(modEventBus);
BuiltinRegistration.register(modEventBus); BuiltinRegistration.register(modEventBus);
BogeySizes.init();
AllBogeyStyles.register();
AllConfigs.register(modLoadingContext); AllConfigs.register(modLoadingContext);

View file

@ -4,7 +4,7 @@ import javax.annotation.Nullable;
import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTags;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices;
@ -61,7 +61,7 @@ public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour {
@Override @Override
public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) { public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) {
return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos) return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos)
.isEmpty() && !AllBlocks.TRACK.has(state); .isEmpty() && !AllTags.AllBlockTags.TRACKS.matches(state);
} }
} }

View file

@ -3,8 +3,8 @@ package com.simibubi.create.content.contraptions.components.press;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.AllTags;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCraftingRecipe; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCraftingRecipe;
import com.simibubi.create.content.contraptions.components.press.PressingBehaviour.Mode; import com.simibubi.create.content.contraptions.components.press.PressingBehaviour.Mode;
@ -69,7 +69,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity implemen
public void onItemPressed(ItemStack result) { public void onItemPressed(ItemStack result) {
award(AllAdvancements.PRESS); award(AllAdvancements.PRESS);
if (AllBlocks.TRACK.isIn(result)) if (AllTags.AllBlockTags.TRACKS.matches(result))
tracksCreated += result.getCount(); tracksCreated += result.getCount();
if (tracksCreated >= 1000) { if (tracksCreated >= 1000) {
award(AllAdvancements.TRACK_CRAFTING); award(AllAdvancements.TRACK_CRAFTING);

View file

@ -30,7 +30,7 @@ import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock;
import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock;
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock; import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock;
import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock; import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock;
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlock; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlock;
import com.simibubi.create.foundation.config.ContraptionMovementSetting; import com.simibubi.create.foundation.config.ContraptionMovementSetting;
@ -337,7 +337,7 @@ public class BlockMovementChecks {
return direction == state.getValue(StickerBlock.FACING) return direction == state.getValue(StickerBlock.FACING)
&& !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite()); && !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite());
} }
if (block instanceof IBogeyBlock bogey) if (block instanceof AbstractBogeyBlock bogey)
return bogey.getStickySurfaces(world, pos, state) return bogey.getStickySurfaces(world, pos, state)
.contains(direction); .contains(direction);
if (block instanceof WhistleBlock) if (block instanceof WhistleBlock)

View file

@ -63,7 +63,7 @@ import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock;
import com.simibubi.create.content.logistics.block.inventories.CreativeCrateTileEntity; import com.simibubi.create.content.logistics.block.inventories.CreativeCrateTileEntity;
import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock; import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock;
import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity; import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; import com.simibubi.create.foundation.tileEntity.IMultiTileContainer;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
@ -342,7 +342,7 @@ public abstract class Contraption {
} }
// Bogeys tend to have sticky sides // Bogeys tend to have sticky sides
if (state.getBlock()instanceof IBogeyBlock bogey) if (state.getBlock()instanceof AbstractBogeyBlock<?> bogey)
for (Direction d : bogey.getStickySurfaces(world, pos, state)) for (Direction d : bogey.getStickySurfaces(world, pos, state))
if (!visited.contains(pos.relative(d))) if (!visited.contains(pos.relative(d)))
frontier.add(pos.relative(d)); frontier.add(pos.relative(d));
@ -1006,7 +1006,7 @@ public abstract class Contraption {
if (disassembled) if (disassembled)
return; return;
disassembled = true; disassembled = true;
for (boolean nonBrittles : Iterate.trueAndFalse) { for (boolean nonBrittles : Iterate.trueAndFalse) {
for (StructureBlockInfo block : blocks.values()) { for (StructureBlockInfo block : blocks.values()) {
if (nonBrittles == BlockMovementChecks.isBrittle(block.state)) if (nonBrittles == BlockMovementChecks.isBrittle(block.state))

View file

@ -8,6 +8,7 @@ import java.util.Random;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllShapes; import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTags;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlock; import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlock;
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
@ -224,7 +225,7 @@ public class GirderBlock extends Block implements SimpleWaterloggedBlock, IWrenc
for (Direction d2 : Iterate.directionsInAxis(axis == Axis.X ? Axis.Z : Axis.X)) { for (Direction d2 : Iterate.directionsInAxis(axis == Axis.X ? Axis.Z : Axis.X)) {
BlockState above = level.getBlockState(pos.above() BlockState above = level.getBlockState(pos.above()
.relative(d2)); .relative(d2));
if (AllBlocks.TRACK.has(above)) { if (AllTags.AllBlockTags.GIRDABLE_TRACKS.matches(above)) {
TrackShape shape = above.getValue(TrackBlock.SHAPE); TrackShape shape = above.getValue(TrackBlock.SHAPE);
if (shape == (axis == Axis.X ? TrackShape.XO : TrackShape.ZO)) if (shape == (axis == Axis.X ? TrackShape.XO : TrackShape.ZO))
state = state.setValue(updateProperty, true); state = state.setValue(updateProperty, true);

View file

@ -9,7 +9,6 @@ import java.util.Optional;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintCraftingInventory; import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintCraftingInventory;
import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection;
@ -106,7 +105,7 @@ public class BlueprintOverlayRenderer {
int tracks = info.requiredTracks; int tracks = info.requiredTracks;
while (tracks > 0) { while (tracks > 0) {
ingredients.add(Pair.of(AllBlocks.TRACK.asStack(Math.min(64, tracks)), info.hasRequiredTracks)); ingredients.add(Pair.of(new ItemStack(info.trackMaterial.getTrackBlock().get(), Math.min(64, tracks)), info.hasRequiredTracks));
tracks -= 64; tracks -= 64;
} }

View file

@ -0,0 +1,361 @@
package com.simibubi.create.content.logistics.trains;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Vector3f;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.content.logistics.trains.entity.Carriage;
import com.simibubi.create.content.logistics.trains.entity.CarriageBogey;
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint;
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.RegisteredObjects;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.NotNull;
public abstract class AbstractBogeyBlock<T extends AbstractBogeyTileEntity> extends Block implements ITE<T>, ProperWaterloggedBlock, ISpecialBlockItemRequirement, IWrenchable {
public static final EnumProperty<Direction.Axis> AXIS = BlockStateProperties.HORIZONTAL_AXIS;
static final List<ResourceLocation> BOGEYS = new ArrayList<>();
public BogeySizes.BogeySize size;
public AbstractBogeyBlock(Properties pProperties, BogeySizes.BogeySize size) {
super(pProperties);
registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false));
this.size = size;
}
public boolean isOnIncompatibleTrack(Carriage carriage, boolean leading) {
TravellingPoint point = leading ? carriage.getLeadingPoint() : carriage.getTrailingPoint();
CarriageBogey bogey = leading ? carriage.leadingBogey() : carriage.trailingBogey();
return point.edge.getTrackMaterial().trackType != getTrackType(bogey.getStyle());
}
public Set<TrackMaterial.TrackType> getValidPathfindingTypes(BogeyStyle style) {
return ImmutableSet.of(getTrackType(style));
}
public abstract TrackMaterial.TrackType getTrackType(BogeyStyle style);
/**
* Only for internal Create use. If you have your own style set, do not call this method
*/
@Deprecated
public static void registerStandardBogey(ResourceLocation block) {
BOGEYS.add(block);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(AXIS, WATERLOGGED);
super.createBlockStateDefinition(builder);
}
@Override
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
updateWater(pLevel, pState, pCurrentPos);
return pState;
}
@Override
public FluidState getFluidState(BlockState pState) {
return fluidState(pState);
}
static final EnumSet<Direction> STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST);
static final EnumSet<Direction> STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH);
public EnumSet<Direction> getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state) {
return state.getValue(BlockStateProperties.HORIZONTAL_AXIS) == Direction.Axis.X ? STICKY_X : STICKY_Z;
}
public abstract double getWheelPointSpacing();
public abstract double getWheelRadius();
public Vec3 getConnectorAnchorOffset(boolean upsideDown) {
return getConnectorAnchorOffset();
}
/**
* This should be implemented, but not called directly
*/
protected abstract Vec3 getConnectorAnchorOffset();
public boolean allowsSingleBogeyCarriage() {
return true;
}
public abstract BogeyStyle getDefaultStyle();
/**
* Legacy system doesn't capture bogey tile entities when constructing a train
*/
public boolean captureTileEntityForTrain() {
return false;
}
@OnlyIn(Dist.CLIENT)
public void render(@Nullable BlockState state, float wheelAngle, PoseStack ms, float partialTicks,
MultiBufferSource buffers, int light, int overlay, BogeyStyle style, CompoundTag bogeyData) {
if (style == null)
style = getDefaultStyle();
final Optional<BogeyRenderer.CommonRenderer> commonRenderer
= style.getInWorldCommonRenderInstance();
final BogeyRenderer renderer = style.getInWorldRenderInstance(this.getSize());
if (state != null) {
ms.translate(.5f, .5f, .5f);
if (state.getValue(AXIS) == Direction.Axis.X)
ms.mulPose(Vector3f.YP.rotationDegrees(90));
}
ms.translate(0, -1.5 - 1 / 128f, 0);
VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped());
if (bogeyData == null)
bogeyData = new CompoundTag();
renderer.render(bogeyData, wheelAngle, ms, light, vb, state == null);
CompoundTag finalBogeyData = bogeyData;
commonRenderer.ifPresent(common ->
common.render(finalBogeyData, wheelAngle, ms, light, vb, state == null));
}
public BogeySizes.BogeySize getSize() {
return this.size;
}
public Direction getBogeyUpDirection() {
return Direction.UP;
}
public boolean isTrackAxisAlongFirstCoordinate(BlockState state) {
return state.getValue(AXIS) == Direction.Axis.X;
}
@Nullable
public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst) {
if (upDirection != Direction.UP)
return null;
return defaultBlockState().setValue(AXIS, axisAlongFirst ? Direction.Axis.X : Direction.Axis.Z);
}
@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand,
BlockHitResult hit) {
if (level.isClientSide)
return InteractionResult.PASS;
ItemStack stack = player.getItemInHand(hand);
if (!player.isShiftKeyDown() && stack.is(AllItems.WRENCH.get()) && !player.getCooldowns().isOnCooldown(stack.getItem())
&& AllBogeyStyles.BOGEY_STYLES.size() > 1) {
BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof AbstractBogeyTileEntity sbte))
return InteractionResult.FAIL;
player.getCooldowns().addCooldown(stack.getItem(), 20);
BogeyStyle currentStyle = sbte.getStyle();
BogeySizes.BogeySize size = getSize();
BogeyStyle style = this.getNextStyle(currentStyle);
if (style == currentStyle)
return InteractionResult.PASS;
Set<BogeySizes.BogeySize> validSizes = style.validSizes();
for (int i = 0; i < BogeySizes.count(); i++) {
if (validSizes.contains(size)) break;
size = size.increment();
}
sbte.setBogeyStyle(style);
CompoundTag defaultData = style.defaultData;
sbte.setBogeyData(sbte.getBogeyData().merge(defaultData));
if (size == getSize()) {
player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style")
.append(": ").append(style.displayName), true);
} else {
CompoundTag oldData = sbte.getBogeyData();
level.setBlock(pos, this.getStateOfSize(sbte, size), 3);
BlockEntity newBlockEntity = level.getBlockEntity(pos);
if (!(newBlockEntity instanceof AbstractBogeyTileEntity newTileEntity))
return InteractionResult.FAIL;
newTileEntity.setBogeyData(oldData);
player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style_and_size")
.append(": ").append(style.displayName), true);
}
return InteractionResult.CONSUME;
}
return InteractionResult.PASS;
}
/**
* If, instead of using the style-based cycling system you prefer to use separate blocks, return them from this method
*/
protected List<ResourceLocation> getBogeyBlockCycle() {
return BOGEYS;
}
@Override
public BlockState getRotatedBlockState(BlockState state, Direction targetedFace) {
Block block = state.getBlock();
List<ResourceLocation> bogeyCycle = getBogeyBlockCycle();
int indexOf = bogeyCycle.indexOf(RegisteredObjects.getKeyOrThrow(block));
if (indexOf == -1)
return state;
int index = (indexOf + 1) % bogeyCycle.size();
Direction bogeyUpDirection = getBogeyUpDirection();
boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state);
while (index != indexOf) {
ResourceLocation id = bogeyCycle.get(index);
Block newBlock = ForgeRegistries.BLOCKS.getValue(id);
if (newBlock instanceof AbstractBogeyBlock<?> bogey) {
BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate);
if (matchingBogey != null)
return copyProperties(state, matchingBogey);
}
index = (index + 1) % bogeyCycle.size();
}
return state;
}
public BlockState getNextSize(Level level, BlockPos pos) {
BlockEntity te = level.getBlockEntity(pos);
if (te instanceof AbstractBogeyTileEntity sbte)
return this.getNextSize(sbte);
return level.getBlockState(pos);
}
/**
* List of BlockState Properties to copy between sizes
*/
public List<Property<?>> propertiesToCopy() {
return ImmutableList.of(WATERLOGGED, AXIS);
}
// generic method needed to satisfy Property and BlockState's generic requirements
private <V extends Comparable<V>> BlockState copyProperty(BlockState source, BlockState target, Property<V> property) {
if (source.hasProperty(property) && target.hasProperty(property)) {
return target.setValue(property, source.getValue(property));
}
return target;
}
private BlockState copyProperties(BlockState source, BlockState target) {
for (Property<?> property : propertiesToCopy())
target = copyProperty(source, target, property);
return target;
}
public BlockState getNextSize(AbstractBogeyTileEntity sbte) {
BogeySizes.BogeySize size = this.getSize();
BogeyStyle style = sbte.getStyle();
BlockState nextBlock = style.getNextBlock(size).defaultBlockState();
nextBlock = copyProperties(sbte.getBlockState(), nextBlock);
return nextBlock;
}
public BlockState getStateOfSize(AbstractBogeyTileEntity sbte, BogeySizes.BogeySize size) {
BogeyStyle style = sbte.getStyle();
BlockState state = style.getBlockOfSize(size).defaultBlockState();
return copyProperties(sbte.getBlockState(), state);
}
public BogeyStyle getNextStyle(Level level, BlockPos pos) {
BlockEntity te = level.getBlockEntity(pos);
if (te instanceof AbstractBogeyTileEntity sbte)
return this.getNextStyle(sbte.getStyle());
return getDefaultStyle();
}
public BogeyStyle getNextStyle(BogeyStyle style) {
Collection<BogeyStyle> allStyles = style.getCycleGroup().values();
if (allStyles.size() <= 1)
return style;
List<BogeyStyle> list = new ArrayList<>(allStyles);
return Iterate.cycleValue(list, style);
}
@Override
public @NotNull BlockState rotate(@NotNull BlockState pState, Rotation pRotation) {
return switch (pRotation) {
case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> pState.cycle(AXIS);
default -> pState;
};
}
@Override
public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) {
return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack());
}
public boolean canBeUpsideDown() {
return false;
}
public boolean isUpsideDown(BlockState state) {
return false;
}
public BlockState getVersion(BlockState base, boolean upsideDown) {
return base;
}
}

View file

@ -24,6 +24,7 @@ import net.minecraft.util.Mth;
import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
@ -39,6 +40,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
public Couple<Vec3> normals; public Couple<Vec3> normals;
public boolean primary; public boolean primary;
public boolean hasGirder; public boolean hasGirder;
protected TrackMaterial trackMaterial;
// runtime // runtime
@ -55,19 +57,37 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
private AABB bounds; private AABB bounds;
public BezierConnection(Couple<BlockPos> positions, Couple<Vec3> starts, Couple<Vec3> axes, Couple<Vec3> normals, public BezierConnection(Couple<BlockPos> positions, Couple<Vec3> starts, Couple<Vec3> axes, Couple<Vec3> normals,
boolean primary, boolean girder) { boolean primary, boolean girder, TrackMaterial material) {
tePositions = positions; tePositions = positions;
this.starts = starts; this.starts = starts;
this.axes = axes; this.axes = axes;
this.normals = normals; this.normals = normals;
this.primary = primary; this.primary = primary;
this.hasGirder = girder; this.hasGirder = girder;
this.trackMaterial = material;
resolved = false; resolved = false;
} }
public BezierConnection secondary() { public BezierConnection secondary() {
return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), !primary, return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), !primary,
hasGirder); hasGirder, trackMaterial);
}
private static boolean coupleEquals(Couple<?> a, Couple<?> b) {
return (a.getFirst().equals(b.getFirst()) && a.getSecond().equals(b.getSecond()))
|| (a.getFirst() instanceof Vec3 aFirst && a.getSecond() instanceof Vec3 aSecond
&& b.getFirst() instanceof Vec3 bFirst && b.getSecond() instanceof Vec3 bSecond
&& aFirst.closerThan(bFirst, 1e-6) && aSecond.closerThan(bSecond, 1e-6));
}
public boolean equalsSansMaterial(BezierConnection other) {
return equalsSansMaterialInner(other) || equalsSansMaterialInner(other.secondary());
}
private boolean equalsSansMaterialInner(BezierConnection other) {
return this == other || (other != null && coupleEquals(this.tePositions, other.tePositions) && coupleEquals(this.starts, other.starts)
&& coupleEquals(this.axes, other.axes) && coupleEquals(this.normals, other.normals)
&& this.hasGirder == other.hasGirder);
} }
public BezierConnection(CompoundTag compound, BlockPos localTo) { public BezierConnection(CompoundTag compound, BlockPos localTo) {
@ -77,7 +97,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
.map(v -> v.add(Vec3.atLowerCornerOf(localTo))), .map(v -> v.add(Vec3.atLowerCornerOf(localTo))),
Couple.deserializeEach(compound.getList("Axes", Tag.TAG_COMPOUND), VecHelper::readNBTCompound), Couple.deserializeEach(compound.getList("Axes", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
Couple.deserializeEach(compound.getList("Normals", Tag.TAG_COMPOUND), VecHelper::readNBTCompound), Couple.deserializeEach(compound.getList("Normals", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
compound.getBoolean("Primary"), compound.getBoolean("Girder")); compound.getBoolean("Primary"), compound.getBoolean("Girder"), TrackMaterial.deserialize(compound.getString("Material")));
} }
public CompoundTag write(BlockPos localTo) { public CompoundTag write(BlockPos localTo) {
@ -91,13 +111,14 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
compound.put("Starts", starts.serializeEach(VecHelper::writeNBTCompound)); compound.put("Starts", starts.serializeEach(VecHelper::writeNBTCompound));
compound.put("Axes", axes.serializeEach(VecHelper::writeNBTCompound)); compound.put("Axes", axes.serializeEach(VecHelper::writeNBTCompound));
compound.put("Normals", normals.serializeEach(VecHelper::writeNBTCompound)); compound.put("Normals", normals.serializeEach(VecHelper::writeNBTCompound));
compound.putString("Material", getMaterial().id.toString());
return compound; return compound;
} }
public BezierConnection(FriendlyByteBuf buffer) { public BezierConnection(FriendlyByteBuf buffer) {
this(Couple.create(buffer::readBlockPos), Couple.create(() -> VecHelper.read(buffer)), this(Couple.create(buffer::readBlockPos), Couple.create(() -> VecHelper.read(buffer)),
Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)),
buffer.readBoolean(), buffer.readBoolean()); buffer.readBoolean(), buffer.readBoolean(), TrackMaterial.deserialize(buffer.readUtf()));
} }
public void write(FriendlyByteBuf buffer) { public void write(FriendlyByteBuf buffer) {
@ -107,6 +128,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
normals.forEach(v -> VecHelper.write(v, buffer)); normals.forEach(v -> VecHelper.write(v, buffer));
buffer.writeBoolean(primary); buffer.writeBoolean(primary);
buffer.writeBoolean(hasGirder); buffer.writeBoolean(hasGirder);
buffer.writeUtf(getMaterial().id.toString());
} }
public BlockPos getKey() { public BlockPos getKey() {
@ -300,7 +322,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
Inventory inv = player.getInventory(); Inventory inv = player.getInventory();
int tracks = getTrackItemCost(); int tracks = getTrackItemCost();
while (tracks > 0) { while (tracks > 0) {
inv.placeItemBackInInventory(AllBlocks.TRACK.asStack(Math.min(64, tracks))); inv.placeItemBackInInventory(new ItemStack(getMaterial().getTrackBlock().get(), Math.min(64, tracks)));
tracks -= 64; tracks -= 64;
} }
int girders = getGirderItemCost(); int girders = getGirderItemCost();
@ -328,7 +350,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
continue; continue;
Vec3 v = VecHelper.offsetRandomly(segment.position, level.random, .125f) Vec3 v = VecHelper.offsetRandomly(segment.position, level.random, .125f)
.add(origin); .add(origin);
ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, AllBlocks.TRACK.asStack()); ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, new ItemStack(getMaterial().getTrackBlock().get()));
entity.setDefaultPickUpDelay(); entity.setDefaultPickUpDelay();
level.addFreshEntity(entity); level.addFreshEntity(entity);
if (!hasGirder) if (!hasGirder)
@ -342,7 +364,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
} }
public void spawnDestroyParticles(Level level) { public void spawnDestroyParticles(Level level) {
BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.TRACK.getDefaultState()); BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, getMaterial().getTrackBlock().get().defaultBlockState());
BlockParticleOption girderData = BlockParticleOption girderData =
new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.METAL_GIRDER.getDefaultState()); new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.METAL_GIRDER.getDefaultState());
if (!(level instanceof ServerLevel slevel)) if (!(level instanceof ServerLevel slevel))
@ -360,6 +382,14 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
} }
} }
public TrackMaterial getMaterial() {
return trackMaterial;
}
public void setMaterial(TrackMaterial material) {
trackMaterial = material;
}
public static class Segment { public static class Segment {
public int index; public int index;

View file

@ -0,0 +1,309 @@
package com.simibubi.create.content.logistics.trains;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.util.transform.Transform;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public abstract class BogeyRenderer {
Map<String, ModelData[]> contraptionModelData = new HashMap<>();
/**
* A common interface for getting transform data for both in-world and in-contraption model data safely from a
* partial model
*
* @param model The key for the model data to instantiate or retrieve
* @param ms The posestack used for contraption model data
* @param inInstancedContraption The type of model needed
* @param size The amount of models needed
* @return A generic transform which can be used for both in-world and in-contraption models
*/
public Transform<?>[] getTransformsFromPartial(PartialModel model, PoseStack ms, boolean inInstancedContraption, int size) {
return (inInstancedContraption) ? transformContraptionModelData(keyFromModel(model), ms) : createModelData(model, size);
}
/**
* A common interface for getting transform data for both in-world and in-contraption model data safely from a
* blockstate
*
* @param state The key for the model data to instantiate or retrieve
* @param ms The posestack used for contraption model data
* @param inContraption The type of model needed
* @param size The amount of models needed
* @return A generic transform which can be used for both in-world and in-contraption models
*/
public Transform<?>[] getTransformsFromBlockState(BlockState state, PoseStack ms, boolean inContraption, int size) {
return inContraption ? transformContraptionModelData(keyFromModel(state), ms) : createModelData(state, size);
}
/**
* Used for calling both in-world and in-contraption rendering
*
* @param bogeyData Custom data stored on the bogey able to be used for rendering
* @param wheelAngle The angle of the wheel
* @param ms The posestack to render to
* @param light (Optional) Light used for in-world rendering
* @param vb (Optional) Vertex Consumer used for in-world rendering
*/
@OnlyIn(Dist.CLIENT)
public abstract void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption);
/**
* Used for calling in-contraption rendering ensuring that falsey data is handled correctly
*
* @param bogeyData Custom data stored on the bogey able to be used for rendering
* @param wheelAngle The angle of the wheel
* @param ms The posestack to render to
*/
@OnlyIn(Dist.CLIENT)
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms) {
this.render(bogeyData, wheelAngle, ms, 0, null, true);
}
public abstract BogeySizes.BogeySize getSize();
/**
* Used to collect Contraption Model Data for in-contraption rendering, should not be utilised directly when
* rendering to prevent render type mismatch
*
* @param key The key used to access the model
* @param ms Posestack of the contraption to bind the model data to
* @return A generic transform which can be used for both in-world and in-contraption models
*/
private Transform<?>[] transformContraptionModelData(String key, PoseStack ms) {
ModelData[] modelData = contraptionModelData.get(key);
Arrays.stream(modelData).forEach(modelDataElement -> modelDataElement.setTransform(ms));
return modelData;
}
/**
* Used for in world rendering, creates a set count of model data to be rendered, allowing for a generic response
* when rendering multiple models both in-world and in-contraption for example, with wheels
*
* @param model The partial model of the model data ot be made
* @param size The Amount of models needed
* @return A generic transform which can be used for both in-world and in-contraption models
*/
private Transform<?>[] createModelData(PartialModel model, int size) {
BlockState air = Blocks.AIR.defaultBlockState();
SuperByteBuffer[] data = { CachedBufferer.partial(model, air) };
return expandArrayToLength(data, size);
}
/**
* Used for in world rendering, creates a set count of model data to be rendered, allowing for a generic response
* when rendering multiple models both in-world and in-contraption for example, with wheels
*
* @param state The state of the model data to be made
* @param size Amount of models needed
* @return A generic transform which can be used for both in-world and in-contraption models
*/
private Transform<?>[] createModelData(BlockState state, int size) {
SuperByteBuffer[] data = { CachedBufferer.block(state) };
return expandArrayToLength(data, size);
}
/**
* Utility function to clone in-world models to a set size to allow for common handling of rendering with multiple
* instances of the same model for example with wheels
*
* @param data An in-world model to be replicated
* @param size Amount of models needed
* @return A generic transform which can be used for both in-world and in-contraption models
*/
private Transform<?>[] expandArrayToLength(SuperByteBuffer[] data, int size) {
return Arrays.stream(Collections.nCopies(size, data).toArray())
.flatMap(inner -> Arrays.stream((SuperByteBuffer[]) inner))
.toArray(SuperByteBuffer[]::new);
}
/**
* Helper function to collect or create a single model from a partial model used for both in-world and
* in-contraption rendering
*
* @param model The key of the model to be collected or instantiated
* @param ms Posestack to bind the model to if it is within a contraption
* @param inInstancedContraption Type of rendering required
* @return A generic transform which can be used for both in-world and in-contraption models
*/
public Transform<?> getTransformFromPartial(PartialModel model, PoseStack ms, boolean inInstancedContraption) {
BlockState air = Blocks.AIR.defaultBlockState();
return inInstancedContraption ? contraptionModelData.get(keyFromModel(model))[0].setTransform(ms)
: CachedBufferer.partial(model, air);
}
/**
* A common interface for getting transform data for blockstates, for a single model
*
* @param state The state of the model to be collected or instantiated
* @param ms Posestack to bind the model to if it is within a contraption
* @param inContraption Type of model required
* @return A generic transform which can be used for both in-world and in-contraption models
*/
public Transform<?> getTransformFromBlockState(BlockState state, PoseStack ms, boolean inContraption) {
return (inContraption) ? contraptionModelData.get(keyFromModel(state))[0].setTransform(ms)
: CachedBufferer.block(state);
}
/**
* Provides render implementations a point in setup to instantiate all model data to be needed
*
* @param materialManager The material manager
*/
@OnlyIn(Dist.CLIENT)
public abstract void initialiseContraptionModelData(MaterialManager materialManager);
/**
* Creates instances of models for in-world rendering to a set length from a provided partial model
*
* @param materialManager The material manager
* @param model Partial model to be instanced
* @param count Amount of models neeeded
*/
public void createModelInstances(MaterialManager materialManager, PartialModel model, int count) {
ModelData[] modelData = new ModelData[count];
materialManager.defaultSolid().material(Materials.TRANSFORMED)
.getModel(model).createInstances(modelData);
contraptionModelData.put(keyFromModel(model), modelData);
}
/**
* Creates instances of models for in-contraption rendering to a set length from a provided blockstate
*
* @param materialManager The material manager
* @param state Blockstate of the model to be created
* @param count Amount of models needed
*/
public void createModelInstances(MaterialManager materialManager, BlockState state, int count) {
ModelData[] modelData = new ModelData[count];
materialManager.defaultSolid().material(Materials.TRANSFORMED)
.getModel(state).createInstances(modelData);
contraptionModelData.put(keyFromModel(state), modelData);
}
/**
* Creates a single instance of models for in-contraption rendering from a provided blockstate
*
* @param materialManager The material manager
* @param state Blockstate of the model to be created
*/
public void createModelInstance(MaterialManager materialManager, BlockState state) {
this.createModelInstances(materialManager, state, 1);
}
/**
* Helper function to create a single model instance for in-contraption rendering
*
* @param materialManager The material manager
* @param models The type of model to create instances of
*/
public void createModelInstances(MaterialManager materialManager, PartialModel... models) {
for (PartialModel model : models)
createModelInstances(materialManager, model, 1);
}
/**
* Handles scale for all model data and renders non contraption model data
*
* @param b The model data itself
* @param ms Pose stack to render to
* @param light light level of the scene
* @param vb Vertex Consumber to render to
* @param <B> Generic alias for both contraption and in-world model data
*/
public static <B extends Transform<?>> void finalize(B b, PoseStack ms, int light, @Nullable VertexConsumer vb) {
b.scale(1 - 1/512f);
if (b instanceof SuperByteBuffer byteBuf && vb != null)
byteBuf.light(light).renderInto(ms, vb);
}
/**
* Automatic handling for setting empty transforms for all model data
*
*/
public void emptyTransforms() {
for (ModelData[] data : contraptionModelData.values())
for (ModelData model : data)
model.setEmptyTransform();
}
/**
* Automatic handling for updating all model data's light
*
* @param blockLight the blocklight to be applied
* @param skyLight the skylight to be applied
*/
public void updateLight(int blockLight, int skyLight) {
for (ModelData[] data : contraptionModelData.values())
for (ModelData model : data)
model.setBlockLight(blockLight).setSkyLight(skyLight);
}
/**
* Automatic handling for clearing all model data of a contraption
*
*/
public void remove() {
for (ModelData[] data : contraptionModelData.values())
for (ModelData model : data)
model.delete();
contraptionModelData.clear();
}
/**
* Create a model key from a partial model, so it can be easily accessed
*
* @param partialModel the model we want a unique key for
* @return Key of the model
*/
private String keyFromModel(PartialModel partialModel) {
return partialModel.getLocation().toString();
}
/**
* Create a model key from a blockstate, so it can be easily accessed
*
* @param state Blockstate of the model
* @return Key of the model
*/
private String keyFromModel(BlockState state) {
return state.toString();
}
public static abstract class CommonRenderer extends BogeyRenderer {
@Override
public BogeySizes.BogeySize getSize() {
return null;
}
}
}

View file

@ -0,0 +1,70 @@
package com.simibubi.create.content.logistics.trains;
import com.simibubi.create.Create;
import net.minecraft.resources.ResourceLocation;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
public class BogeySizes {
private static final Collection<BogeySize> BOGEY_SIZES = new HashSet<>();
public static final BogeySize SMALL = new BogeySize(Create.ID, "small", 6.5f / 16f);
public static final BogeySize LARGE = new BogeySize(Create.ID, "large", 12.5f / 16f);
static {
BOGEY_SIZES.add(SMALL);
BOGEY_SIZES.add(LARGE);
}
public static BogeySize addSize(String modId, String name, float size) {
ResourceLocation location = new ResourceLocation(modId, name);
return addSize(location, size);
}
public static BogeySize addSize(ResourceLocation location, float size) {
BogeySize customSize = new BogeySize(location, size);
BOGEY_SIZES.add(customSize);
return customSize;
}
public static List<BogeySize> getAllSizesSmallToLarge() {
return BOGEY_SIZES.stream()
.sorted(Comparator.comparing(BogeySize::wheelRadius))
.collect(Collectors.toList());
}
public static List<BogeySize> getAllSizesLargeToSmall() {
List<BogeySize> sizes = getAllSizesSmallToLarge();
Collections.reverse(sizes);
return sizes;
}
public static int count() {
return BOGEY_SIZES.size();
}
public record BogeySize(ResourceLocation location, Float wheelRadius) {
public BogeySize(String modId, String name, float wheelRadius) {
this(new ResourceLocation(modId, name), wheelRadius);
}
public BogeySize increment() {
List<BogeySize> values = getAllSizesSmallToLarge();
int ordinal = values.indexOf(this);
return values.get((ordinal + 1) % values.size());
}
public boolean is(BogeySize size) {
return size.location == this.location;
}
}
public static void init() {
}
}

View file

@ -1,7 +1,7 @@
package com.simibubi.create.content.logistics.trains; package com.simibubi.create.content.logistics.trains;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
@ -17,11 +17,11 @@ public class BogeyTileEntityRenderer<T extends BlockEntity> extends SafeTileEnti
protected void renderSafe(T te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, protected void renderSafe(T te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light,
int overlay) { int overlay) {
BlockState blockState = te.getBlockState(); BlockState blockState = te.getBlockState();
float angle = 0; if (te instanceof AbstractBogeyTileEntity sbte) {
if (te instanceof StandardBogeyTileEntity sbte) float angle = sbte.getVirtualAngle(partialTicks);
angle = sbte.getVirtualAngle(partialTicks); if (blockState.getBlock() instanceof AbstractBogeyBlock<?> bogey)
if (blockState.getBlock()instanceof IBogeyBlock bogey) bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay, sbte.getStyle(), sbte.getBogeyData());
bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay); }
} }
} }

View file

@ -265,13 +265,17 @@ public class GlobalRailwayManager {
public void clientTick() { public void clientTick() {
if (isTrackGraphDebugActive()) if (isTrackGraphDebugActive())
for (TrackGraph trackGraph : trackNetworks.values()) for (TrackGraph trackGraph : trackNetworks.values())
TrackGraphVisualizer.debugViewGraph(trackGraph); TrackGraphVisualizer.debugViewGraph(trackGraph, isTrackGraphDebugExtended());
} }
private static boolean isTrackGraphDebugActive() { private static boolean isTrackGraphDebugActive() {
return KineticDebugger.isF3DebugModeActive() && AllConfigs.CLIENT.showTrackGraphOnF3.get(); return KineticDebugger.isF3DebugModeActive() && AllConfigs.CLIENT.showTrackGraphOnF3.get();
} }
private static boolean isTrackGraphDebugExtended() {
return AllConfigs.CLIENT.showExtendedTrackGraphOnF3.get();
}
public GlobalRailwayManager sided(LevelAccessor level) { public GlobalRailwayManager sided(LevelAccessor level) {
if (level != null && !level.isClientSide()) if (level != null && !level.isClientSide())
return this; return this;

View file

@ -1,91 +0,0 @@
package com.simibubi.create.content.logistics.trains;
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.api.MaterialManager;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.content.logistics.trains.entity.BogeyInstance;
import com.simibubi.create.content.logistics.trains.entity.CarriageBogey;
import com.simibubi.create.foundation.utility.RegisteredObjects;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.registries.ForgeRegistries;
public interface IBogeyBlock extends IWrenchable {
static final List<ResourceLocation> BOGEYS = new ArrayList<>();
public static void register(ResourceLocation block) {
BOGEYS.add(block);
}
public EnumSet<Direction> getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state);
public double getWheelPointSpacing();
public double getWheelRadius();
public boolean allowsSingleBogeyCarriage();
public Vec3 getConnectorAnchorOffset();
@OnlyIn(Dist.CLIENT)
public void render(@Nullable BlockState state, float wheelAngle, PoseStack ms, float partialTicks,
MultiBufferSource buffers, int light, int overlay);
@OnlyIn(Dist.CLIENT)
public BogeyInstance createInstance(MaterialManager materialManager, CarriageBogey bogey);
public default Direction getBogeyUpDirection() {
return Direction.UP;
}
public boolean isTrackAxisAlongFirstCoordinate(BlockState state);
@Nullable
public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst);
@Override
default BlockState getRotatedBlockState(BlockState state, Direction targetedFace) {
Block block = state.getBlock();
int indexOf = BOGEYS.indexOf(RegisteredObjects.getKeyOrThrow(block));
if (indexOf == -1)
return state;
int index = (indexOf + 1) % BOGEYS.size();
Direction bogeyUpDirection = getBogeyUpDirection();
boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state);
while (index != indexOf) {
ResourceLocation id = BOGEYS.get(index);
Block newBlock = ForgeRegistries.BLOCKS.getValue(id);
if (newBlock instanceof IBogeyBlock bogey) {
BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate);
if (matchingBogey != null)
return matchingBogey.hasProperty(WATERLOGGED)
? matchingBogey.setValue(WATERLOGGED, state.getValue(WATERLOGGED))
: matchingBogey;
}
index = (index + 1) % BOGEYS.size();
}
return state;
}
}

View file

@ -25,6 +25,7 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
@ -74,22 +75,42 @@ public interface ITrackBlock {
getTrackAxes(world, pos, state).forEach(axis -> { getTrackAxes(world, pos, state).forEach(axis -> {
addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d) addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d)
.add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, .add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD,
axis, null); axis, null, (b, v) -> getMaterialSimple(world, v));
}); });
return list; return list;
} }
public static TrackMaterial getMaterialSimple(BlockGetter world, Vec3 pos) {
return getMaterialSimple(world, pos, TrackMaterial.ANDESITE);
}
public static TrackMaterial getMaterialSimple(BlockGetter world, Vec3 pos, TrackMaterial defaultMaterial) {
if (defaultMaterial == null)
defaultMaterial = TrackMaterial.ANDESITE;
if (world != null) {
Block block = world.getBlockState(new BlockPos(pos)).getBlock();
if (block instanceof ITrackBlock track) {
return track.getMaterial();
}
}
return defaultMaterial;
}
public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection<DiscoveredLocation> list, public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection<DiscoveredLocation> list,
BiFunction<Double, Boolean, Vec3> offsetFactory, Function<Boolean, Vec3> normalFactory, BiFunction<Double, Boolean, Vec3> offsetFactory, Function<Boolean, Vec3> normalFactory,
Function<Boolean, ResourceKey<Level>> dimensionFactory, Vec3 axis, BezierConnection viaTurn) { Function<Boolean, ResourceKey<Level>> dimensionFactory, Vec3 axis, BezierConnection viaTurn, BiFunction<Boolean, Vec3, TrackMaterial> materialFactory) {
DiscoveredLocation firstLocation = DiscoveredLocation firstLocation =
new DiscoveredLocation(dimensionFactory.apply(true), offsetFactory.apply(0.5d, true)).viaTurn(viaTurn) new DiscoveredLocation(dimensionFactory.apply(true), offsetFactory.apply(0.5d, true)).viaTurn(viaTurn)
.materialA(materialFactory.apply(true, offsetFactory.apply(0.0d, true)))
.materialB(materialFactory.apply(true, offsetFactory.apply(1.0d, true)))
.withNormal(normalFactory.apply(true)) .withNormal(normalFactory.apply(true))
.withDirection(axis); .withDirection(axis);
DiscoveredLocation secondLocation = DiscoveredLocation secondLocation =
new DiscoveredLocation(dimensionFactory.apply(false), offsetFactory.apply(0.5d, false)).viaTurn(viaTurn) new DiscoveredLocation(dimensionFactory.apply(false), offsetFactory.apply(0.5d, false)).viaTurn(viaTurn)
.materialA(materialFactory.apply(false, offsetFactory.apply(0.0d, false)))
.materialB(materialFactory.apply(false, offsetFactory.apply(1.0d, false)))
.withNormal(normalFactory.apply(false)) .withNormal(normalFactory.apply(false))
.withDirection(axis); .withDirection(axis);
@ -97,7 +118,7 @@ public interface ITrackBlock {
firstLocation.forceNode(); firstLocation.forceNode();
secondLocation.forceNode(); secondLocation.forceNode();
} }
boolean skipFirst = false; boolean skipFirst = false;
boolean skipSecond = false; boolean skipSecond = false;
@ -152,4 +173,6 @@ public interface ITrackBlock {
.normalize()) < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE); .normalize()) < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE);
} }
TrackMaterial getMaterial();
} }

View file

@ -0,0 +1,137 @@
package com.simibubi.create.content.logistics.trains;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.util.transform.Transform;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.Nullable;
import static com.simibubi.create.AllBlockPartials.LARGE_BOGEY_WHEELS;
import static com.simibubi.create.AllBlockPartials.BOGEY_PIN;
import static com.simibubi.create.AllBlockPartials.BOGEY_DRIVE;
import static com.simibubi.create.AllBlockPartials.BOGEY_PISTON;
import static com.simibubi.create.AllBlockPartials.SMALL_BOGEY_WHEELS;
import static com.simibubi.create.AllBlockPartials.BOGEY_FRAME;
public class StandardBogeyRenderer {
public static class CommonStandardBogeyRenderer extends BogeyRenderer.CommonRenderer {
@Override
public void initialiseContraptionModelData(MaterialManager materialManager) {
createModelInstances(materialManager, AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Direction.Axis.Z), 2);
}
@Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
boolean inInstancedContraption = vb == null;
Transform<?>[] shafts = getTransformsFromBlockState(AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Direction.Axis.Z), ms, inInstancedContraption, 2);
for (int i : Iterate.zeroAndOne) {
shafts[i].translate(-.5f, .25f, i * -1)
.centre()
.rotateZ(wheelAngle)
.unCentre();
finalize(shafts[i], ms, light, vb);
}
}
}
public static class SmallStandardBogeyRenderer extends BogeyRenderer {
@Override
public void initialiseContraptionModelData(MaterialManager materialManager) {
createModelInstances(materialManager, SMALL_BOGEY_WHEELS, 2);
createModelInstances(materialManager, BOGEY_FRAME);
}
@Override
public BogeySizes.BogeySize getSize() {
return BogeySizes.SMALL;
}
@Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
boolean inInstancedContraption = vb == null;
Transform<?> transform = getTransformFromPartial(BOGEY_FRAME, ms, inInstancedContraption);
finalize(transform, ms, light, vb);
Transform<?>[] wheels = getTransformsFromPartial(SMALL_BOGEY_WHEELS, ms, inInstancedContraption, 2);
for (int side : Iterate.positiveAndNegative) {
if (!inInstancedContraption)
ms.pushPose();
Transform<?> wheel = wheels[(side + 1)/2];
wheel.translate(0, 12 / 16f, side)
.rotateX(wheelAngle);
finalize(wheel, ms, light, vb);
if (!inInstancedContraption)
ms.popPose();
}
}
}
public static class LargeStandardBogeyRenderer extends BogeyRenderer {
@Override
public void initialiseContraptionModelData(MaterialManager materialManager) {
createModelInstances(materialManager, LARGE_BOGEY_WHEELS, BOGEY_DRIVE, BOGEY_PISTON, BOGEY_PIN);
createModelInstances(materialManager, AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Direction.Axis.X), 2);
}
@Override
public BogeySizes.BogeySize getSize() {
return BogeySizes.LARGE;
}
@Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
boolean inInstancedContraption = vb == null;
Transform<?>[] secondaryShafts = getTransformsFromBlockState(AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Direction.Axis.X), ms, inInstancedContraption, 2);
for (int i : Iterate.zeroAndOne) {
Transform<?> secondShaft = secondaryShafts[i];
secondShaft.translate(-.5f, .25f, .5f + i * -2)
.centre()
.rotateX(wheelAngle)
.unCentre();
finalize(secondShaft, ms, light, vb);
}
Transform<?> bogeyDrive = getTransformFromPartial(BOGEY_DRIVE, ms, inInstancedContraption);
finalize(bogeyDrive, ms, light, vb);
Transform<?> bogeyPiston = getTransformFromPartial(BOGEY_PISTON, ms, inInstancedContraption)
.translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle)));
finalize(bogeyPiston, ms, light, vb);
if (!inInstancedContraption)
ms.pushPose();
Transform<?> bogeyWheels = getTransformFromPartial(LARGE_BOGEY_WHEELS, ms, inInstancedContraption)
.translate(0, 1, 0)
.rotateX(wheelAngle);
finalize(bogeyWheels, ms, light, vb);
Transform<?> bogeyPin = getTransformFromPartial(BOGEY_PIN, ms, inInstancedContraption)
.translate(0, 1, 0)
.rotateX(wheelAngle)
.translate(0, 1 / 4f, 0)
.rotateX(-wheelAngle);
finalize(bogeyPin, ms, light, vb);
if (!inInstancedContraption)
ms.popPose();
}
}
}

View file

@ -22,13 +22,19 @@ public class TrackEdge {
BezierConnection turn; BezierConnection turn;
EdgeData edgeData; EdgeData edgeData;
boolean interDimensional; boolean interDimensional;
TrackMaterial trackMaterial;
public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn) { public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn, TrackMaterial trackMaterial) {
this.interDimensional = !node1.location.dimension.equals(node2.location.dimension); this.interDimensional = !node1.location.dimension.equals(node2.location.dimension);
this.edgeData = new EdgeData(this); this.edgeData = new EdgeData(this);
this.node1 = node1; this.node1 = node1;
this.node2 = node2; this.node2 = node2;
this.turn = turn; this.turn = turn;
this.trackMaterial = trackMaterial;
}
public TrackMaterial getTrackMaterial() {
return trackMaterial;
} }
public boolean isTurn() { public boolean isTurn() {
@ -181,13 +187,15 @@ public class TrackEdge {
public CompoundTag write(DimensionPalette dimensions) { public CompoundTag write(DimensionPalette dimensions) {
CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag(); CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag();
baseCompound.put("Signals", edgeData.write(dimensions)); baseCompound.put("Signals", edgeData.write(dimensions));
baseCompound.putString("Material", getTrackMaterial().id.toString());
return baseCompound; return baseCompound;
} }
public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph, public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph,
DimensionPalette dimensions) { DimensionPalette dimensions) {
TrackEdge trackEdge = TrackEdge trackEdge =
new TrackEdge(node1, node2, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null); new TrackEdge(node1, node2, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null,
TrackMaterial.deserialize(tag.getString("Material")));
trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph, dimensions); trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph, dimensions);
return trackEdge; return trackEdge;
} }

View file

@ -393,14 +393,15 @@ public class TrackGraph {
return connectionsFrom.get(nodes.getSecond()); return connectionsFrom.get(nodes.getSecond());
} }
public void connectNodes(LevelAccessor reader, TrackNodeLocation location, TrackNodeLocation location2, public void connectNodes(LevelAccessor reader, DiscoveredLocation location, DiscoveredLocation location2,
@Nullable BezierConnection turn) { @Nullable BezierConnection turn) {
TrackNode node1 = nodes.get(location); TrackNode node1 = nodes.get(location);
TrackNode node2 = nodes.get(location2); TrackNode node2 = nodes.get(location2);
boolean bezier = turn != null; boolean bezier = turn != null;
TrackEdge edge = new TrackEdge(node1, node2, turn); TrackMaterial material = bezier ? turn.getMaterial() : location2.materialA;
TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null); TrackEdge edge = new TrackEdge(node1, node2, turn, material);
TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null, material);
for (TrackGraph graph : Create.RAILWAYS.trackNetworks.values()) { for (TrackGraph graph : Create.RAILWAYS.trackNetworks.values()) {
for (TrackNode otherNode1 : graph.nodes.values()) { for (TrackNode otherNode1 : graph.nodes.values()) {

View file

@ -60,7 +60,7 @@ public class TrackGraphSync {
public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) { public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) {
flushGraphPacket(graph); flushGraphPacket(graph);
currentGraphSyncPacket.addedEdges currentGraphSyncPacket.addedEdges
.add(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge.getTurn())); .add(Pair.of(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge.getTrackMaterial()), edge.getTurn()));
currentPayload++; currentPayload++;
} }
@ -82,7 +82,7 @@ public class TrackGraphSync {
if (currentGraphSyncPacket.addedNodes.remove(nodeId) == null) if (currentGraphSyncPacket.addedNodes.remove(nodeId) == null)
currentGraphSyncPacket.removedNodes.add(nodeId); currentGraphSyncPacket.removedNodes.add(nodeId);
currentGraphSyncPacket.addedEdges.removeIf(pair -> { currentGraphSyncPacket.addedEdges.removeIf(pair -> {
Couple<Integer> ids = pair.getFirst(); Couple<Integer> ids = pair.getFirst().getFirst();
return ids.getFirst() return ids.getFirst()
.intValue() == nodeId .intValue() == nodeId
|| ids.getSecond() || ids.getSecond()
@ -156,7 +156,7 @@ public class TrackGraphSync {
graph.connectionsByNode.get(node) graph.connectionsByNode.get(node)
.forEach((node2, edge) -> { .forEach((node2, edge) -> {
Couple<Integer> key = Couple.create(node.getNetId(), node2.getNetId()); Couple<Integer> key = Couple.create(node.getNetId(), node2.getNetId());
currentPacket.addedEdges.add(Pair.of(key, edge.getTurn())); currentPacket.addedEdges.add(Pair.of(Pair.of(key, edge.getTrackMaterial()), edge.getTurn()));
currentPacket.syncEdgeData(node, node2, edge); currentPacket.syncEdgeData(node, node2, edge);
}); });

View file

@ -22,7 +22,7 @@ import net.minecraft.world.phys.Vec3;
public class TrackGraphSyncPacket extends TrackGraphPacket { public class TrackGraphSyncPacket extends TrackGraphPacket {
Map<Integer, Pair<TrackNodeLocation, Vec3>> addedNodes; Map<Integer, Pair<TrackNodeLocation, Vec3>> addedNodes;
List<Pair<Couple<Integer>, BezierConnection>> addedEdges; List<Pair<Pair<Couple<Integer>, TrackMaterial>, BezierConnection>> addedEdges;
List<Integer> removedNodes; List<Integer> removedNodes;
List<TrackEdgePoint> addedEdgePoints; List<TrackEdgePoint> addedEdgePoints;
List<UUID> removedEdgePoints; List<UUID> removedEdgePoints;
@ -79,7 +79,7 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
size = buffer.readVarInt(); size = buffer.readVarInt();
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
addedEdges.add( addedEdges.add(
Pair.of(Couple.create(buffer::readVarInt), buffer.readBoolean() ? new BezierConnection(buffer) : null)); Pair.of(Pair.of(Couple.create(buffer::readVarInt), TrackMaterial.deserialize(buffer.readUtf())), buffer.readBoolean() ? new BezierConnection(buffer) : null));
size = buffer.readVarInt(); size = buffer.readVarInt();
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
@ -134,8 +134,9 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
buffer.writeVarInt(addedEdges.size()); buffer.writeVarInt(addedEdges.size());
addedEdges.forEach(pair -> { addedEdges.forEach(pair -> {
pair.getFirst() pair.getFirst().getFirst()
.forEach(buffer::writeVarInt); .forEach(buffer::writeVarInt);
buffer.writeUtf(pair.getFirst().getSecond().id.toString());
BezierConnection turn = pair.getSecond(); BezierConnection turn = pair.getSecond();
buffer.writeBoolean(turn != null); buffer.writeBoolean(turn != null);
if (turn != null) if (turn != null)
@ -192,13 +193,13 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond()); graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond());
} }
for (Pair<Couple<Integer>, BezierConnection> pair : addedEdges) { for (Pair<Pair<Couple<Integer>, TrackMaterial>, BezierConnection> pair : addedEdges) {
Couple<TrackNode> nodes = pair.getFirst() Couple<TrackNode> nodes = pair.getFirst().getFirst()
.map(graph::getNode); .map(graph::getNode);
TrackNode node1 = nodes.getFirst(); TrackNode node1 = nodes.getFirst();
TrackNode node2 = nodes.getSecond(); TrackNode node2 = nodes.getSecond();
if (node1 != null && node2 != null) if (node1 != null && node2 != null)
graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond())); graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond(), pair.getFirst().getSecond()));
} }
for (TrackEdgePoint edgePoint : addedEdgePoints) for (TrackEdgePoint edgePoint : addedEdgePoints)
@ -268,4 +269,4 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
updatedEdgeData.put(key, Pair.of(groupType, list)); updatedEdgeData.put(key, Pair.of(groupType, list));
} }
} }

View file

@ -5,6 +5,15 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.UUID; import java.util.UUID;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import com.simibubi.create.AllKeys; import com.simibubi.create.AllKeys;
@ -209,7 +218,7 @@ public class TrackGraphVisualizer {
} }
} }
public static void debugViewGraph(TrackGraph graph) { public static void debugViewGraph(TrackGraph graph, boolean extended) {
Minecraft mc = Minecraft.getInstance(); Minecraft mc = Minecraft.getInstance();
Entity cameraEntity = mc.cameraEntity; Entity cameraEntity = mc.cameraEntity;
if (cameraEntity == null) if (cameraEntity == null)
@ -262,6 +271,13 @@ public class TrackGraphVisualizer {
yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0); yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
if (!edge.isTurn()) { if (!edge.isTurn()) {
if (extended) {
Vec3 materialPos = edge.getPosition(0.5).add(0, 1, 0);
CreateClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos,
new ItemStack(edge.getTrackMaterial().trackBlock.get().get()));
CreateClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, 1, 1, 1))
.colored(graph.color);
}
CreateClient.OUTLINER.showLine(edge, edge.getPosition(0) CreateClient.OUTLINER.showLine(edge, edge.getPosition(0)
.add(yOffset), .add(yOffset),
edge.getPosition(1) edge.getPosition(1)
@ -273,6 +289,13 @@ public class TrackGraphVisualizer {
Vec3 previous = null; Vec3 previous = null;
BezierConnection turn = edge.getTurn(); BezierConnection turn = edge.getTurn();
if (extended) {
Vec3 materialPos = edge.getPosition(0.5).add(0, 1, 0);
CreateClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos,
new ItemStack(edge.getTrackMaterial().trackBlock.get().get()));
CreateClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, 1, 1, 1))
.colored(graph.color);
}
for (int i = 0; i <= turn.getSegmentCount(); i++) { for (int i = 0; i <= turn.getSegmentCount(); i++) {
Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount()); Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount());
if (previous != null) if (previous != null)

View file

@ -0,0 +1,144 @@
package com.simibubi.create.content.logistics.trains;
import static com.simibubi.create.content.logistics.trains.TrackMaterialFactory.make;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import com.jozufozu.flywheel.core.PartialModel;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
import com.tterrag.registrate.util.nullness.NonNullSupplier;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor;
public class TrackMaterial {
public static final Map<ResourceLocation, TrackMaterial> ALL = new HashMap<>();
public static final TrackMaterial ANDESITE = make(Create.asResource("andesite"))
.lang("Andesite")
.block(NonNullSupplier.lazy(() -> AllBlocks.TRACK))
.particle(Create.asResource("block/palettes/stone_types/polished/andesite_cut_polished"))
.defaultModels()
.build();
public final ResourceLocation id;
public final String langName;
public final NonNullSupplier<NonNullSupplier<? extends TrackBlock>> trackBlock;
public final Ingredient sleeperIngredient;
public final Ingredient railsIngredient;
public final ResourceLocation particle;
public final TrackType trackType;
@OnlyIn(Dist.CLIENT)
protected TrackModelHolder modelHolder;
@OnlyIn(Dist.CLIENT)
public TrackModelHolder getModelHolder() {
return modelHolder;
}
public TrackMaterial(ResourceLocation id, String langName, NonNullSupplier<NonNullSupplier<? extends TrackBlock>> trackBlock,
ResourceLocation particle, Ingredient sleeperIngredient, Ingredient railsIngredient,
TrackType trackType, Supplier<Supplier<TrackModelHolder>> modelHolder) {
this.id = id;
this.langName = langName;
this.trackBlock = trackBlock;
this.sleeperIngredient = sleeperIngredient;
this.railsIngredient = railsIngredient;
this.particle = particle;
this.trackType = trackType;
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.modelHolder = modelHolder.get().get());
ALL.put(this.id, this);
}
public NonNullSupplier<? extends TrackBlock> getTrackBlock() {
return this.trackBlock.get();
}
public TrackBlock createBlock(BlockBehaviour.Properties properties) {
return this.trackType.factory.create(properties, this);
}
public boolean isCustom(String modId) {
return this.id.getNamespace().equals(modId);
}
public static TrackMaterial[] allCustom(String modid) {
return ALL.values().stream().filter(tm -> tm.isCustom(modid)).toArray(TrackMaterial[]::new);
}
public static List<NonNullSupplier<? extends TrackBlock>> allCustomBlocks(String modid) {
List<NonNullSupplier<? extends TrackBlock>> list = new ArrayList<>();
for (TrackMaterial material : allCustom(modid)) {
list.add(material.getTrackBlock());
}
return list;
}
public static List<NonNullSupplier<? extends TrackBlock>> allBlocks() {
List<NonNullSupplier<? extends TrackBlock>> list = new ArrayList<>();
for (TrackMaterial material : ALL.values()) {
list.add(material.getTrackBlock());
}
return list;
}
public String resourceName() {
return this.id.getPath();
}
public static TrackMaterial deserialize(String serializedName) {
if (serializedName.isBlank()) // Data migrating from 0.5
return ANDESITE;
ResourceLocation id = ResourceLocation.tryParse(serializedName);
if (id != null)
for (TrackMaterial material : ALL.values())
if (material.id.equals(id))
return material;
Create.LOGGER.error("Failed to locate serialized track material: " + serializedName);
return ANDESITE;
}
public static class TrackType {
@FunctionalInterface
protected interface TrackBlockFactory {
TrackBlock create(BlockBehaviour.Properties properties, TrackMaterial material);
}
public static final TrackType STANDARD = new TrackType(Create.asResource("standard"), TrackBlock::new);
public final ResourceLocation id;
protected final TrackBlockFactory factory;
public TrackType(ResourceLocation id, TrackBlockFactory factory) {
this.id = id;
this.factory = factory;
}
}
public static TrackMaterial fromItem(Item item) {
if (item instanceof BlockItem blockItem && blockItem.getBlock() instanceof ITrackBlock trackBlock)
return trackBlock.getMaterial();
return TrackMaterial.ANDESITE;
}
@OnlyIn(Dist.CLIENT)
public record TrackModelHolder(PartialModel tie, PartialModel segment_left, PartialModel segment_right) {
static final TrackModelHolder DEFAULT = new TrackModelHolder(AllBlockPartials.TRACK_TIE, AllBlockPartials.TRACK_SEGMENT_LEFT, AllBlockPartials.TRACK_SEGMENT_RIGHT);
}
}

View file

@ -0,0 +1,133 @@
package com.simibubi.create.content.logistics.trains;
import com.jozufozu.flywheel.core.PartialModel;
import com.simibubi.create.AllTags;
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
import com.tterrag.registrate.util.nullness.NonNullSupplier;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.ItemLike;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TrackMaterialFactory {
private final ResourceLocation id;
private String langName;
private NonNullSupplier<NonNullSupplier<? extends TrackBlock>> trackBlock;
private Ingredient sleeperIngredient = Ingredient.EMPTY;
private Ingredient railsIngredient = Ingredient.fromValues(Stream.of(new Ingredient.TagValue(AllTags.forgeItemTag("nuggets/iron")), new Ingredient.TagValue(AllTags.forgeItemTag("nuggets/zinc"))));
private ResourceLocation particle;
private TrackMaterial.TrackType trackType = TrackMaterial.TrackType.STANDARD;
@OnlyIn(Dist.CLIENT)
private TrackMaterial.TrackModelHolder modelHolder;
@OnlyIn(Dist.CLIENT)
private PartialModel tieModel;
@OnlyIn(Dist.CLIENT)
private PartialModel leftSegmentModel;
@OnlyIn(Dist.CLIENT)
private PartialModel rightSegmentModel;
public TrackMaterialFactory(ResourceLocation id) {
this.id = id;
}
public static TrackMaterialFactory make(ResourceLocation id) { // Convenience function for static import
return new TrackMaterialFactory(id);
}
public TrackMaterialFactory lang(String langName) {
this.langName = langName;
return this;
}
public TrackMaterialFactory block(NonNullSupplier<NonNullSupplier<? extends TrackBlock>> trackBlock) {
this.trackBlock = trackBlock;
return this;
}
public TrackMaterialFactory defaultModels() { // was setBuiltin
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.modelHolder = TrackMaterial.TrackModelHolder.DEFAULT);
return this;
}
public TrackMaterialFactory sleeper(Ingredient sleeperIngredient) {
this.sleeperIngredient = sleeperIngredient;
return this;
}
public TrackMaterialFactory sleeper(ItemLike... items) {
this.sleeperIngredient = Ingredient.of(items);
return this;
}
public TrackMaterialFactory rails(Ingredient railsIngredient) {
this.railsIngredient = railsIngredient;
return this;
}
public TrackMaterialFactory rails(ItemLike... items) {
this.railsIngredient = Ingredient.of(items);
return this;
}
public TrackMaterialFactory noRecipeGen() {
this.railsIngredient = Ingredient.EMPTY;
this.sleeperIngredient = Ingredient.EMPTY;
return this;
}
public TrackMaterialFactory particle(ResourceLocation particle) {
this.particle = particle;
return this;
}
public TrackMaterialFactory trackType(TrackMaterial.TrackType trackType) {
this.trackType = trackType;
return this;
}
public TrackMaterialFactory standardModels() { // was defaultModels
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
String namespace = id.getNamespace();
String prefix = "block/track/" + id.getPath() + "/";
tieModel = new PartialModel(new ResourceLocation(namespace, prefix + "tie"));
leftSegmentModel = new PartialModel(new ResourceLocation(namespace, prefix + "segment_left"));
rightSegmentModel = new PartialModel(new ResourceLocation(namespace, prefix + "segment_right"));
});
return this;
}
public TrackMaterialFactory customModels(Supplier<Supplier<PartialModel>> tieModel, Supplier<Supplier<PartialModel>> leftSegmentModel, Supplier<Supplier<PartialModel>> rightSegmentModel) {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
this.tieModel = tieModel.get().get();
this.leftSegmentModel = leftSegmentModel.get().get();
this.rightSegmentModel = rightSegmentModel.get().get();
});
return this;
}
public TrackMaterial build() {
assert trackBlock != null;
assert langName != null;
assert particle != null;
assert trackType != null;
assert sleeperIngredient != null;
assert railsIngredient != null;
assert id != null;
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
assert modelHolder != null;
if (tieModel != null || leftSegmentModel != null || rightSegmentModel != null) {
assert tieModel != null && leftSegmentModel != null && rightSegmentModel != null;
modelHolder = new TrackMaterial.TrackModelHolder(tieModel, leftSegmentModel, rightSegmentModel);
}
});
return new TrackMaterial(id, langName, trackBlock, particle, sleeperIngredient, railsIngredient, trackType, () -> () -> modelHolder);
}
}

View file

@ -24,8 +24,8 @@ public class TrackNodeLocation extends Vec3i {
this(vec.x, vec.y, vec.z); this(vec.x, vec.y, vec.z);
} }
public TrackNodeLocation(double p_121865_, double p_121866_, double p_121867_) { public TrackNodeLocation(double x, double y, double z) {
super(Math.round(p_121865_ * 2), Math.floor(p_121866_ * 2), Math.round(p_121867_ * 2)); super(Math.round(x * 2), Math.floor(y * 2), Math.round(z * 2));
} }
public TrackNodeLocation in(Level level) { public TrackNodeLocation in(Level level) {
@ -116,9 +116,11 @@ public class TrackNodeLocation extends Vec3i {
boolean forceNode = false; boolean forceNode = false;
Vec3 direction; Vec3 direction;
Vec3 normal; Vec3 normal;
TrackMaterial materialA;
TrackMaterial materialB;
public DiscoveredLocation(Level level, double p_121865_, double p_121866_, double p_121867_) { public DiscoveredLocation(Level level, double x, double y, double z) {
super(p_121865_, p_121866_, p_121867_); super(x, y, z);
in(level); in(level);
} }
@ -131,6 +133,22 @@ public class TrackNodeLocation extends Vec3i {
this(level.dimension(), vec); this(level.dimension(), vec);
} }
public DiscoveredLocation materialA(TrackMaterial material) {
this.materialA = material;
return this;
}
public DiscoveredLocation materialB(TrackMaterial material) {
this.materialB = material;
return this;
}
public DiscoveredLocation materials(TrackMaterial materialA, TrackMaterial materialB) {
this.materialA = materialA;
this.materialB = materialB;
return this;
}
public DiscoveredLocation viaTurn(BezierConnection turn) { public DiscoveredLocation viaTurn(BezierConnection turn) {
this.turn = turn; this.turn = turn;
if (turn != null) if (turn != null)
@ -165,6 +183,10 @@ public class TrackNodeLocation extends Vec3i {
return forceNode; return forceNode;
} }
public boolean differentMaterials() {
return materialA != materialB;
}
public boolean notInLineWith(Vec3 direction) { public boolean notInLineWith(Vec3 direction) {
return this.direction != null return this.direction != null
&& Math.max(direction.dot(this.direction), direction.dot(this.direction.scale(-1))) < 7 / 8f; && Math.max(direction.dot(this.direction), direction.dot(this.direction.scale(-1))) < 7 / 8f;

View file

@ -234,10 +234,12 @@ public class TrackPropagator {
return true; return true;
if (location.shouldForceNode()) if (location.shouldForceNode())
return true; return true;
if (location.differentMaterials())
return true;
if (next.stream() if (next.stream()
.anyMatch(DiscoveredLocation::shouldForceNode)) .anyMatch(DiscoveredLocation::shouldForceNode))
return true; return true;
Vec3 direction = location.direction; Vec3 direction = location.direction;
if (direction != null && next.stream() if (direction != null && next.stream()
.anyMatch(dl -> dl.notInLineWith(direction))) .anyMatch(dl -> dl.notInLineWith(direction)))

View file

@ -0,0 +1,22 @@
package com.simibubi.create.content.logistics.trains.entity;
import com.jozufozu.flywheel.api.MaterialManager;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
import net.minecraft.nbt.CompoundTag;
public class BackupBogeyRenderer extends BogeyRenderer.CommonRenderer {
public static BackupBogeyRenderer INSTANCE = new BackupBogeyRenderer();
@Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
}
@Override
public void initialiseContraptionModelData(MaterialManager materialManager) {
}
}

View file

@ -1,235 +1,72 @@
package com.simibubi.create.content.logistics.trains.entity; package com.simibubi.create.content.logistics.trains.entity;
import com.jozufozu.flywheel.api.Material;
import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.logistics.trains.BogeyRenderer;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; import com.simibubi.create.content.logistics.trains.BogeySizes;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.LightLayer;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public sealed class BogeyInstance { import java.util.Optional;
public final class BogeyInstance {
private final BogeySizes.BogeySize size;
private final BogeyStyle style;
public final CarriageBogey bogey; public final CarriageBogey bogey;
private final ModelData[] shafts; public final BogeyRenderer renderer;
public final Optional<BogeyRenderer.CommonRenderer> commonRenderer;
protected BogeyInstance(CarriageBogey bogey, MaterialManager materialManager) { public BogeyInstance(CarriageBogey bogey, BogeyStyle style, BogeySizes.BogeySize size, MaterialManager materialManager) {
this.bogey = bogey; this.bogey = bogey;
this.size = size;
this.style = style;
shafts = new ModelData[2]; this.renderer = this.style.createRendererInstance(this.size);
this.commonRenderer = this.style.getNewCommonRenderInstance();
materialManager.defaultSolid()
.material(Materials.TRANSFORMED)
.getModel(AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Direction.Axis.Z))
.createInstances(shafts);
commonRenderer.ifPresent(bogeyRenderer ->
bogeyRenderer.initialiseContraptionModelData(materialManager));
renderer.initialiseContraptionModelData(materialManager);
} }
public void remove() { void hiddenFrame() {
for (ModelData shaft : shafts)
shaft.delete();
}
public void hiddenFrame() {
beginFrame(0, null); beginFrame(0, null);
} }
public void beginFrame(float wheelAngle, PoseStack ms) { public void beginFrame(float wheelAngle, PoseStack ms) {
if (ms == null) { if (ms == null) {
for (int i : Iterate.zeroAndOne) renderer.emptyTransforms();
shafts[i].setEmptyTransform();
return; return;
} }
for (int i : Iterate.zeroAndOne) commonRenderer.ifPresent(bogeyRenderer ->
shafts[i].setTransform(ms) bogeyRenderer.render(bogey.bogeyData, wheelAngle, ms));
.translate(-.5f, .25f, i * -1) renderer.render(bogey.bogeyData, wheelAngle, ms);
.centre()
.rotateZ(wheelAngle)
.unCentre();
} }
public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) { public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) {
var lightPos = new BlockPos(getLightPos(entity)); var lightPos = new BlockPos(getLightPos(entity));
commonRenderer.ifPresent(bogeyRenderer
updateLight(world.getBrightness(LightLayer.BLOCK, lightPos), world.getBrightness(LightLayer.SKY, lightPos)); -> bogeyRenderer.updateLight(world.getBrightness(LightLayer.BLOCK, lightPos),
world.getBrightness(LightLayer.SKY, lightPos)));
renderer.updateLight(world.getBrightness(LightLayer.BLOCK, lightPos),
world.getBrightness(LightLayer.SKY, lightPos));
} }
private Vec3 getLightPos(CarriageContraptionEntity entity) { private Vec3 getLightPos(CarriageContraptionEntity entity) {
if (bogey.getAnchorPosition() != null) { return bogey.getAnchorPosition() != null ? bogey.getAnchorPosition()
return bogey.getAnchorPosition(); : entity.getLightProbePosition(AnimationTickHolder.getPartialTicks());
} else {
return entity.getLightProbePosition(AnimationTickHolder.getPartialTicks());
}
} }
public void updateLight(int blockLight, int skyLight) { @FunctionalInterface
for (ModelData shaft : shafts) { interface BogeyInstanceFactory {
shaft.setBlockLight(blockLight) BogeyInstance create(CarriageBogey bogey, BogeySizes.BogeySize size,
.setSkyLight(skyLight); MaterialManager materialManager);
}
}
public static final class Frame extends BogeyInstance {
private final ModelData frame;
private final ModelData[] wheels;
public Frame(CarriageBogey bogey, MaterialManager materialManager) {
super(bogey, materialManager);
frame = materialManager.defaultSolid()
.material(Materials.TRANSFORMED)
.getModel(AllBlockPartials.BOGEY_FRAME)
.createInstance();
wheels = new ModelData[2];
materialManager.defaultSolid()
.material(Materials.TRANSFORMED)
.getModel(AllBlockPartials.SMALL_BOGEY_WHEELS)
.createInstances(wheels);
}
@Override
public void beginFrame(float wheelAngle, PoseStack ms) {
super.beginFrame(wheelAngle, ms);
if (ms == null) {
frame.setEmptyTransform();
for (int side : Iterate.positiveAndNegative)
wheels[(side + 1) / 2].setEmptyTransform();
return;
}
frame.setTransform(ms);
for (int side : Iterate.positiveAndNegative) {
wheels[(side + 1) / 2].setTransform(ms)
.translate(0, 12 / 16f, side)
.rotateX(wheelAngle);
}
}
@Override
public void updateLight(int blockLight, int skyLight) {
super.updateLight(blockLight, skyLight);
frame.setBlockLight(blockLight)
.setSkyLight(skyLight);
for (ModelData wheel : wheels)
wheel.setBlockLight(blockLight)
.setSkyLight(skyLight);
}
@Override
public void remove() {
super.remove();
frame.delete();
for (ModelData wheel : wheels)
wheel.delete();
}
}
public static final class Drive extends BogeyInstance {
private final ModelData[] secondShaft;
private final ModelData drive;
private final ModelData piston;
private final ModelData wheels;
private final ModelData pin;
public Drive(CarriageBogey bogey, MaterialManager materialManager) {
super(bogey, materialManager);
Material<ModelData> mat = materialManager.defaultSolid()
.material(Materials.TRANSFORMED);
secondShaft = new ModelData[2];
mat.getModel(AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Direction.Axis.X))
.createInstances(secondShaft);
drive = mat.getModel(AllBlockPartials.BOGEY_DRIVE)
.createInstance();
piston = mat.getModel(AllBlockPartials.BOGEY_PISTON)
.createInstance();
wheels = mat.getModel(AllBlockPartials.LARGE_BOGEY_WHEELS)
.createInstance();
pin = mat.getModel(AllBlockPartials.BOGEY_PIN)
.createInstance();
}
@Override
public void beginFrame(float wheelAngle, PoseStack ms) {
super.beginFrame(wheelAngle, ms);
if (ms == null) {
for (int i : Iterate.zeroAndOne)
secondShaft[i].setEmptyTransform();
drive.setEmptyTransform();
piston.setEmptyTransform();
wheels.setEmptyTransform();
pin.setEmptyTransform();
return;
}
for (int i : Iterate.zeroAndOne)
secondShaft[i].setTransform(ms)
.translate(-.5f, .25f, .5f + i * -2)
.centre()
.rotateX(wheelAngle)
.unCentre();
drive.setTransform(ms);
piston.setTransform(ms)
.translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle)));
wheels.setTransform(ms)
.translate(0, 1, 0)
.rotateX(wheelAngle);
pin.setTransform(ms)
.translate(0, 1, 0)
.rotateX(wheelAngle)
.translate(0, 1 / 4f, 0)
.rotateX(-wheelAngle);
}
@Override
public void updateLight(int blockLight, int skyLight) {
super.updateLight(blockLight, skyLight);
for (ModelData shaft : secondShaft)
shaft.setBlockLight(blockLight)
.setSkyLight(skyLight);
drive.setBlockLight(blockLight)
.setSkyLight(skyLight);
piston.setBlockLight(blockLight)
.setSkyLight(skyLight);
wheels.setBlockLight(blockLight)
.setSkyLight(skyLight);
pin.setBlockLight(blockLight)
.setSkyLight(skyLight);
}
@Override
public void remove() {
super.remove();
for (ModelData shaft : secondShaft)
shaft.delete();
drive.delete();
piston.delete();
wheels.delete();
pin.delete();
}
} }
} }

View file

@ -0,0 +1,114 @@
package com.simibubi.create.content.logistics.trains.entity;
import com.jozufozu.flywheel.api.MaterialManager;
import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
import com.simibubi.create.content.logistics.trains.BogeyRenderer.CommonRenderer;
import com.simibubi.create.content.logistics.trains.BogeySizes;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class BogeyStyle {
private final Optional<Supplier<? extends CommonRenderer>> commonRendererFactory;
public final ResourceLocation name;
public final ResourceLocation cycleGroup;
private final Optional<CommonRenderer> commonRenderer;
private final Map<BogeySizes.BogeySize, SizeData> sizes;
public final Component displayName;
public final ResourceLocation soundType;
public final ParticleOptions contactParticle;
public final ParticleOptions smokeParticle;
public final CompoundTag defaultData;
public BogeyStyle(ResourceLocation name, ResourceLocation cycleGroup, Component displayName, ResourceLocation soundType, ParticleOptions contactParticle, ParticleOptions smokeParticle,
CompoundTag defaultData, Map<BogeySizes.BogeySize, SizeData> sizes, Optional<Supplier<? extends CommonRenderer>> commonRenderer) {
this.name = name;
this.cycleGroup = cycleGroup;
this.displayName = displayName;
this.soundType = soundType;
this.contactParticle = contactParticle;
this.smokeParticle = smokeParticle;
this.defaultData = defaultData;
this.sizes = sizes;
this.commonRendererFactory = commonRenderer;
this.commonRenderer = commonRenderer.map(Supplier::get);
}
public Map<ResourceLocation, BogeyStyle> getCycleGroup() {
return AllBogeyStyles.getCycleGroup(cycleGroup);
}
public Block getNextBlock(BogeySizes.BogeySize currentSize) {
return Stream.iterate(currentSize.increment(), BogeySizes.BogeySize::increment)
.filter(sizes::containsKey)
.findFirst()
.map(size -> ForgeRegistries.BLOCKS.getValue(sizes.get(size).block()))
.orElse(ForgeRegistries.BLOCKS.getValue(sizes.get(currentSize).block()));
}
public Block getBlockOfSize(BogeySizes.BogeySize size) {
return ForgeRegistries.BLOCKS.getValue(sizes.get(size).block());
}
public Set<BogeySizes.BogeySize> validSizes() {
return sizes.keySet();
}
@NotNull
public SoundEvent getSoundType() {
AllSoundEvents.SoundEntry entry = AllSoundEvents.ALL.get(this.soundType);
if (entry == null || entry.getMainEvent() == null) entry = AllSoundEvents.TRAIN2;
return entry.getMainEvent();
}
public BogeyRenderer createRendererInstance(BogeySizes.BogeySize size) {
return this.sizes.get(size).createRenderInstance();
}
public BogeyRenderer getInWorldRenderInstance(BogeySizes.BogeySize size) {
SizeData sizeData = this.sizes.get(size);
return sizeData != null ? sizeData.getInWorldInstance() : BackupBogeyRenderer.INSTANCE;
}
public Optional<CommonRenderer> getInWorldCommonRenderInstance() {
return this.commonRenderer;
}
public Optional<CommonRenderer> getNewCommonRenderInstance() {
return this.commonRendererFactory.map(Supplier::get);
}
public BogeyInstance createInstance(CarriageBogey bogey, BogeySizes.BogeySize size, MaterialManager materialManager) {
return new BogeyInstance(bogey, this, size, materialManager);
}
public record SizeData(ResourceLocation block, Supplier<? extends BogeyRenderer> rendererFactory, BogeyRenderer instance) {
public BogeyRenderer createRenderInstance() {
return rendererFactory.get();
}
public BogeyRenderer getInWorldInstance() {
return instance;
}
}
}

View file

@ -85,6 +85,11 @@ public class Carriage {
bogey2.carriage = this; bogey2.carriage = this;
} }
public boolean isOnIncompatibleTrack() {
return leadingBogey().type.isOnIncompatibleTrack(this, true)
|| trailingBogey().type.isOnIncompatibleTrack(this, false);
}
public void setTrain(Train train) { public void setTrain(Train train) {
this.train = train; this.train = train;
} }
@ -306,6 +311,9 @@ public class Carriage {
double leadingWheelSpacing = leadingBogey.type.getWheelPointSpacing(); double leadingWheelSpacing = leadingBogey.type.getWheelPointSpacing();
double trailingWheelSpacing = trailingBogey.type.getWheelPointSpacing(); double trailingWheelSpacing = trailingBogey.type.getWheelPointSpacing();
boolean leadingUpsideDown = leadingBogey.isUpsideDown();
boolean trailingUpsideDown = trailingBogey.isUpsideDown();
for (boolean leading : Iterate.trueAndFalse) { for (boolean leading : Iterate.trueAndFalse) {
TravellingPoint point = leading ? getLeadingPoint() : getTrailingPoint(); TravellingPoint point = leading ? getLeadingPoint() : getTrailingPoint();
TravellingPoint otherPoint = !leading ? getLeadingPoint() : getTrailingPoint(); TravellingPoint otherPoint = !leading ? getLeadingPoint() : getTrailingPoint();
@ -321,24 +329,31 @@ public class Carriage {
dce.positionAnchor = dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() dce.positionAnchor = dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition()
: pivoted(dce, dimension, point, : pivoted(dce, dimension, point,
leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2); leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2,
leadingUpsideDown, trailingUpsideDown);
boolean backAnchorFlip = trailingBogey.isUpsideDown() ^ leadingBogey.isUpsideDown();
if (isOnTwoBogeys()) { if (isOnTwoBogeys()) {
dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition()
: pivoted(dce, dimension, point, : pivoted(dce, dimension, point,
leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2)); leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2,
dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition() leadingUpsideDown, trailingUpsideDown));
dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition(backAnchorFlip)
: pivoted(dce, dimension, point, : pivoted(dce, dimension, point,
leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2)); leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2,
leadingUpsideDown, trailingUpsideDown));
} else { } else {
if (dimension.equals(otherDimension)) { if (dimension.equals(otherDimension)) {
dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition); dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition);
} else { } else {
dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition() dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition()
: pivoted(dce, dimension, point, leadingWheelSpacing)); : pivoted(dce, dimension, point, leadingWheelSpacing,
leadingUpsideDown, trailingUpsideDown));
dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition() dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition()
: pivoted(dce, dimension, point, leadingWheelSpacing)); : pivoted(dce, dimension, point, leadingWheelSpacing,
leadingUpsideDown, trailingUpsideDown));
} }
} }
@ -356,15 +371,16 @@ public class Carriage {
} }
private Vec3 pivoted(DimensionalCarriageEntity dce, ResourceKey<Level> dimension, TravellingPoint start, private Vec3 pivoted(DimensionalCarriageEntity dce, ResourceKey<Level> dimension, TravellingPoint start,
double offset) { double offset, boolean leadingUpsideDown, boolean trailingUpsideDown) {
if (train.graph == null) if (train.graph == null)
return dce.pivot == null ? null : dce.pivot.getLocation(); return dce.pivot == null ? null : dce.pivot.getLocation();
TrackNodeLocation pivot = dce.findPivot(dimension, start == getLeadingPoint()); TrackNodeLocation pivot = dce.findPivot(dimension, start == getLeadingPoint());
if (pivot == null) if (pivot == null)
return null; return null;
Vec3 startVec = start.getPosition(); boolean flipped = start != getLeadingPoint() && (leadingUpsideDown != trailingUpsideDown);
Vec3 startVec = start.getPosition(flipped);
Vec3 portalVec = pivot.getLocation() Vec3 portalVec = pivot.getLocation()
.add(0, 1, 0); .add(0, leadingUpsideDown ? -1.0 : 1.0, 0);
return VecHelper.lerp((float) (offset / startVec.distanceTo(portalVec)), startVec, portalVec); return VecHelper.lerp((float) (offset / startVec.distanceTo(portalVec)), startVec, portalVec);
} }

View file

@ -3,13 +3,16 @@ package com.simibubi.create.content.logistics.trains.entity;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.MaterialManager;
import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.trains.DimensionPalette; import com.simibubi.create.content.logistics.trains.DimensionPalette;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.RegisteredObjects; import com.simibubi.create.foundation.utility.RegisteredObjects;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.animation.LerpedFloat; import com.simibubi.create.foundation.utility.animation.LerpedFloat;
@ -25,13 +28,20 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
import static com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity.BOGEY_DATA_KEY;
import static com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity.BOGEY_STYLE_KEY;
public class CarriageBogey { public class CarriageBogey {
public Carriage carriage; public static final String UPSIDE_DOWN_KEY = "UpsideDown";
public Carriage carriage;
boolean isLeading; boolean isLeading;
IBogeyBlock type; public CompoundTag bogeyData;
AbstractBogeyBlock<?> type;
boolean upsideDown;
Couple<TravellingPoint> points; Couple<TravellingPoint> points;
LerpedFloat wheelAngle; LerpedFloat wheelAngle;
@ -42,8 +52,15 @@ public class CarriageBogey {
int derailAngle; int derailAngle;
public CarriageBogey(IBogeyBlock type, TravellingPoint point, TravellingPoint point2) { public CarriageBogey(AbstractBogeyBlock<?> type, boolean upsideDown, CompoundTag bogeyData, TravellingPoint point, TravellingPoint point2) {
this.type = type; this.type = type;
this.upsideDown = type.canBeUpsideDown() && upsideDown;
point.upsideDown = this.upsideDown;
point2.upsideDown = this.upsideDown;
if (bogeyData == null || bogeyData.isEmpty())
bogeyData = this.createBogeyData(); // Prevent Crash When Updating
bogeyData.putBoolean(UPSIDE_DOWN_KEY, upsideDown);
this.bogeyData = bogeyData;
points = Couple.create(point, point2); points = Couple.create(point, point2);
wheelAngle = LerpedFloat.angular(); wheelAngle = LerpedFloat.angular();
yaw = LerpedFloat.angular(); yaw = LerpedFloat.angular();
@ -100,11 +117,15 @@ public class CarriageBogey {
} }
public TravellingPoint leading() { public TravellingPoint leading() {
return points.getFirst(); TravellingPoint point = points.getFirst();
point.upsideDown = isUpsideDown();
return point;
} }
public TravellingPoint trailing() { public TravellingPoint trailing() {
return points.getSecond(); TravellingPoint point = points.getSecond();
point.upsideDown = isUpsideDown();
return point;
} }
public double getStress() { public double getStress() {
@ -118,18 +139,25 @@ public class CarriageBogey {
@Nullable @Nullable
public Vec3 getAnchorPosition() { public Vec3 getAnchorPosition() {
return getAnchorPosition(false);
}
@Nullable
public Vec3 getAnchorPosition(boolean flipUpsideDown) {
if (leading().edge == null) if (leading().edge == null)
return null; return null;
return points.getFirst() return points.getFirst()
.getPosition() .getPosition(flipUpsideDown)
.add(points.getSecond() .add(points.getSecond()
.getPosition()) .getPosition(flipUpsideDown))
.scale(.5); .scale(.5);
} }
public void updateCouplingAnchor(Vec3 entityPos, float entityXRot, float entityYRot, int bogeySpacing, public void updateCouplingAnchor(Vec3 entityPos, float entityXRot, float entityYRot, int bogeySpacing,
float partialTicks, boolean leading) { float partialTicks, boolean leading) {
Vec3 thisOffset = type.getConnectorAnchorOffset(); boolean selfUpsideDown = isUpsideDown();
boolean leadingUpsideDown = carriage.leadingBogey().isUpsideDown();
Vec3 thisOffset = type.getConnectorAnchorOffset(selfUpsideDown);
thisOffset = thisOffset.multiply(1, 1, leading ? -1 : 1); thisOffset = thisOffset.multiply(1, 1, leading ? -1 : 1);
thisOffset = VecHelper.rotate(thisOffset, pitch.getValue(partialTicks), Axis.X); thisOffset = VecHelper.rotate(thisOffset, pitch.getValue(partialTicks), Axis.X);
@ -141,6 +169,8 @@ public class CarriageBogey {
thisOffset = VecHelper.rotate(thisOffset, 180, Axis.Y); thisOffset = VecHelper.rotate(thisOffset, 180, Axis.Y);
thisOffset = VecHelper.rotate(thisOffset, -entityXRot, Axis.X); thisOffset = VecHelper.rotate(thisOffset, -entityXRot, Axis.X);
thisOffset = VecHelper.rotate(thisOffset, entityYRot + 90, Axis.Y); thisOffset = VecHelper.rotate(thisOffset, entityYRot + 90, Axis.Y);
if (selfUpsideDown != leadingUpsideDown)
thisOffset = thisOffset.add(0, selfUpsideDown ? -2 : 2, 0);
couplingAnchors.set(leading, entityPos.add(thisOffset)); couplingAnchors.set(leading, entityPos.add(thisOffset));
} }
@ -150,23 +180,46 @@ public class CarriageBogey {
tag.putString("Type", RegisteredObjects.getKeyOrThrow((Block) type) tag.putString("Type", RegisteredObjects.getKeyOrThrow((Block) type)
.toString()); .toString());
tag.put("Points", points.serializeEach(tp -> tp.write(dimensions))); tag.put("Points", points.serializeEach(tp -> tp.write(dimensions)));
tag.putBoolean("UpsideDown", upsideDown);
bogeyData.putBoolean(UPSIDE_DOWN_KEY, upsideDown);
NBTHelper.writeResourceLocation(bogeyData, BOGEY_STYLE_KEY, getStyle().name);
tag.put(BOGEY_DATA_KEY, bogeyData);
return tag; return tag;
} }
public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
ResourceLocation location = new ResourceLocation(tag.getString("Type")); ResourceLocation location = new ResourceLocation(tag.getString("Type"));
IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(location); AbstractBogeyBlock<?> type = (AbstractBogeyBlock<?>) ForgeRegistries.BLOCKS.getValue(location);
boolean upsideDown = tag.getBoolean("UpsideDown");
Couple<TravellingPoint> points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND), Couple<TravellingPoint> points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND),
c -> TravellingPoint.read(c, graph, dimensions)); c -> TravellingPoint.read(c, graph, dimensions));
CarriageBogey carriageBogey = new CarriageBogey(type, points.getFirst(), points.getSecond()); CompoundTag data = tag.getCompound(AbstractBogeyTileEntity.BOGEY_DATA_KEY);
return carriageBogey; return new CarriageBogey(type, upsideDown, data, points.getFirst(), points.getSecond());
} }
public BogeyInstance createInstance(MaterialManager materialManager) { public BogeyInstance createInstance(MaterialManager materialManager) {
return type.createInstance(materialManager, this); return this.getStyle().createInstance(this, type.getSize(), materialManager);
}
public BogeyStyle getStyle() {
ResourceLocation location = NBTHelper.readResourceLocation(this.bogeyData, BOGEY_STYLE_KEY);
BogeyStyle style = AllBogeyStyles.BOGEY_STYLES.get(location);
return style != null ? style : AllBogeyStyles.STANDARD; // just for safety
}
private CompoundTag createBogeyData() {
BogeyStyle style = type != null ? type.getDefaultStyle() : AllBogeyStyles.STANDARD;
CompoundTag nbt = style.defaultData != null ? style.defaultData : new CompoundTag();
NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, style.name);
nbt.putBoolean(UPSIDE_DOWN_KEY, isUpsideDown());
return nbt;
} }
void setLeading() { void setLeading() {
isLeading = true; isLeading = true;
} }
public boolean isUpsideDown() {
return type.canBeUpsideDown() && upsideDown;
}
} }

View file

@ -22,7 +22,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.ren
import com.simibubi.create.content.contraptions.components.structureMovement.train.TrainCargoManager; import com.simibubi.create.content.contraptions.components.structureMovement.train.TrainCargoManager;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
@ -71,7 +71,7 @@ public class CarriageContraption extends Contraption {
// render // render
public int portalCutoffMin; public int portalCutoffMin;
public int portalCutoffMax; public int portalCutoffMax;
static final IItemHandlerModifiable fallbackItems = new ItemStackHandler(); static final IItemHandlerModifiable fallbackItems = new ItemStackHandler();
static final IFluidHandler fallbackFluids = new FluidTank(0); static final IFluidHandler fallbackFluids = new FluidTank(0);
@ -162,11 +162,13 @@ public class CarriageContraption extends Contraption {
.getStep(), toLocalPos(pos)); .getStep(), toLocalPos(pos));
} }
if (blockState.getBlock() instanceof IBogeyBlock) { if (blockState.getBlock() instanceof AbstractBogeyBlock<?> bogey) {
boolean captureTE = bogey.captureTileEntityForTrain();
bogeys++; bogeys++;
if (bogeys == 2) if (bogeys == 2)
secondBogeyPos = pos; secondBogeyPos = pos;
return Pair.of(new StructureBlockInfo(pos, blockState, null), null); return Pair.of(new StructureBlockInfo(pos, blockState, captureTE ? getTileEntityNBT(world, pos) : null),
captureTE ? world.getBlockEntity(pos) : null);
} }
if (AllBlocks.BLAZE_BURNER.has(blockState) if (AllBlocks.BLAZE_BURNER.has(blockState)
@ -235,7 +237,7 @@ public class CarriageContraption extends Contraption {
protected MountedStorageManager getStorageForSpawnPacket() { protected MountedStorageManager getStorageForSpawnPacket() {
return storageProxy; return storageProxy;
} }
@Override @Override
protected ContraptionType getType() { protected ContraptionType getType() {
return ContraptionType.CARRIAGE; return ContraptionType.CARRIAGE;

View file

@ -13,6 +13,7 @@ import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer<CarriageContraptionEntity> { public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer<CarriageContraptionEntity> {
@ -37,7 +38,7 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
MultiBufferSource buffers, int overlay) { MultiBufferSource buffers, int overlay) {
if (!entity.validForRender || entity.firstPositionUpdate) if (!entity.validForRender || entity.firstPositionUpdate)
return; return;
super.render(entity, yaw, partialTicks, ms, buffers, overlay); super.render(entity, yaw, partialTicks, ms, buffers, overlay);
Carriage carriage = entity.getCarriage(); Carriage carriage = entity.getCarriage();
@ -65,8 +66,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks); translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks);
int light = getBogeyLightCoords(entity, bogey, partialTicks); int light = getBogeyLightCoords(entity, bogey, partialTicks);
bogey.type.render(null, bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light, bogey.type.render(null, bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light,
overlay); overlay, bogey.getStyle(), bogey.bogeyData);
ms.popPose(); ms.popPose();
} }
@ -80,6 +82,8 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot, public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot,
float viewXRot, float partialTicks) { float viewXRot, float partialTicks) {
boolean selfUpsideDown = bogey.isUpsideDown();
boolean leadingUpsideDown = bogey.carriage.leadingBogey().isUpsideDown();
TransformStack.cast(ms) TransformStack.cast(ms)
.rotateY(viewYRot + 90) .rotateY(viewYRot + 90)
.rotateX(-viewXRot) .rotateX(-viewXRot)
@ -90,7 +94,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
.rotateY(-viewYRot - 90) .rotateY(-viewYRot - 90)
.rotateY(bogey.yaw.getValue(partialTicks)) .rotateY(bogey.yaw.getValue(partialTicks))
.rotateX(bogey.pitch.getValue(partialTicks)) .rotateX(bogey.pitch.getValue(partialTicks))
.translate(0, .5f, 0); .translate(0, .5f, 0)
.rotateZ(selfUpsideDown ? 180 : 0)
.translateY(selfUpsideDown != leadingUpsideDown ? 2 : 0);
} }
public static int getBogeyLightCoords(CarriageContraptionEntity entity, CarriageBogey bogey, float partialTicks) { public static int getBogeyLightCoords(CarriageContraptionEntity entity, CarriageBogey bogey, float partialTicks) {

View file

@ -7,6 +7,7 @@ import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.jozufozu.flywheel.util.transform.TransformStack; import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector3f; import com.mojang.math.Vector3f;
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
@ -31,7 +32,8 @@ public class CarriageContraptionInstance extends EntityInstance<CarriageContrapt
if (carriage == null) if (carriage == null)
return; return;
bogeys = carriage.bogeys.mapNotNullWithParam(CarriageBogey::createInstance, materialManager); bogeys = carriage.bogeys.mapNotNullWithParam((bogey, manager) ->
bogey.getStyle().createInstance(bogey, bogey.type.getSize(), manager), materialManager);
updateLight(); updateLight();
} }
@ -98,8 +100,10 @@ public class CarriageContraptionInstance extends EntityInstance<CarriageContrapt
return; return;
bogeys.forEach(instance -> { bogeys.forEach(instance -> {
if (instance != null) if (instance != null) {
instance.remove(); instance.commonRenderer.ifPresent(BogeyRenderer::remove);
instance.renderer.remove();
}
}); });
} }

View file

@ -79,7 +79,7 @@ public class CarriageCouplingRenderer {
float margin = 3 / 16f; float margin = 3 / 16f;
double couplingDistance = train.carriageSpacing.get(i) - 2 * margin double couplingDistance = train.carriageSpacing.get(i) - 2 * margin
- bogey1.type.getConnectorAnchorOffset().z - bogey2.type.getConnectorAnchorOffset().z; - bogey1.type.getConnectorAnchorOffset(bogey1.isUpsideDown()).z - bogey2.type.getConnectorAnchorOffset(bogey2.isUpsideDown()).z;
int couplingSegments = (int) Math.round(couplingDistance * 4); int couplingSegments = (int) Math.round(couplingDistance * 4);
double stretch = ((anchor2.distanceTo(anchor) - 2 * margin) * 4) / couplingSegments; double stretch = ((anchor2.distanceTo(anchor) - 2 * margin) * 4) / couplingSegments;
for (int j = 0; j < couplingSegments; j++) { for (int j = 0; j < couplingSegments; j++) {

View file

@ -10,7 +10,6 @@ import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.Axis;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
@ -110,7 +109,7 @@ public class CarriageParticles {
m = m.add(contraptionMotion.scale(.75f)); m = m.add(contraptionMotion.scale(.75f));
level.addParticle(spark ? ParticleTypes.CRIT : ParticleTypes.POOF, v.x, v.y, v.z, m.x, m.y, m.z); level.addParticle(spark ? bogey.getStyle().contactParticle : bogey.getStyle().smokeParticle, v.x, v.y, v.z, m.x, m.y, m.z);
} }
} }
} }

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.trains.entity;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.AllSoundEvents.SoundEntry; import com.simibubi.create.AllSoundEvents.SoundEntry;
import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity; import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.animation.LerpedFloat; import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
@ -29,6 +30,9 @@ public class CarriageSounds {
LoopingSound sharedWheelSoundSeated; LoopingSound sharedWheelSoundSeated;
LoopingSound sharedHonkSound; LoopingSound sharedHonkSound;
Couple<SoundEvent> bogeySounds;
SoundEvent closestBogeySound;
boolean arrived; boolean arrived;
int tick; int tick;
@ -36,6 +40,10 @@ public class CarriageSounds {
public CarriageSounds(CarriageContraptionEntity entity) { public CarriageSounds(CarriageContraptionEntity entity) {
this.entity = entity; this.entity = entity;
bogeySounds = entity.getCarriage().bogeys.map(bogey ->
bogey != null && bogey.getStyle() != null ? bogey.getStyle().getSoundType()
: AllSoundEvents.TRAIN2.getMainEvent());
closestBogeySound = bogeySounds.getFirst();
distanceFactor = LerpedFloat.linear(); distanceFactor = LerpedFloat.linear();
speedFactor = LerpedFloat.linear(); speedFactor = LerpedFloat.linear();
approachFactor = LerpedFloat.linear(); approachFactor = LerpedFloat.linear();
@ -79,6 +87,15 @@ public class CarriageSounds {
double distance1 = toBogey1.length(); double distance1 = toBogey1.length();
double distance2 = toBogey2.length(); double distance2 = toBogey2.length();
Couple<CarriageBogey> bogeys = entity.getCarriage().bogeys;
CarriageBogey relevantBogey = bogeys.get(distance1 > distance2);
if (relevantBogey == null) {
relevantBogey = bogeys.getFirst();
}
if (relevantBogey != null) {
closestBogeySound = relevantBogey.getStyle().getSoundType();
}
Vec3 toCarriage = distance1 > distance2 ? toBogey2 : toBogey1; Vec3 toCarriage = distance1 > distance2 ? toBogey2 : toBogey1;
double distance = Math.min(distance1, distance2); double distance = Math.min(distance1, distance2);
Vec3 soundLocation = cam.add(toCarriage); Vec3 soundLocation = cam.add(toCarriage);
@ -97,7 +114,7 @@ public class CarriageSounds {
seatCrossfade.tickChaser(); seatCrossfade.tickChaser();
minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent()); minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent());
sharedWheelSound = playIfMissing(mc, sharedWheelSound, AllSoundEvents.TRAIN2.getMainEvent()); sharedWheelSound = playIfMissing(mc, sharedWheelSound, closestBogeySound);
sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent()); sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent());
float volume = Math.min(Math.min(speedFactor.getValue(), distanceFactor.getValue() / 100), float volume = Math.min(Math.min(speedFactor.getValue(), distanceFactor.getValue() / 100),
@ -205,7 +222,7 @@ public class CarriageSounds {
public void submitSharedSoundVolume(Vec3 location, float volume) { public void submitSharedSoundVolume(Vec3 location, float volume) {
Minecraft mc = Minecraft.getInstance(); Minecraft mc = Minecraft.getInstance();
minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent()); minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent());
sharedWheelSound = playIfMissing(mc, sharedWheelSound, AllSoundEvents.TRAIN2.getMainEvent()); sharedWheelSound = playIfMissing(mc, sharedWheelSound, closestBogeySound);
sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent()); sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent());
boolean approach = true; boolean approach = true;

View file

@ -14,6 +14,8 @@ import java.util.UUID;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import org.apache.commons.lang3.mutable.MutableDouble; import org.apache.commons.lang3.mutable.MutableDouble;
import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.mutable.MutableObject;
@ -251,7 +253,7 @@ public class Navigation {
return; return;
} }
} }
topSpeed *= train.throttle; topSpeed *= train.throttle;
double turnTopSpeed = Math.min(topSpeed, train.maxTurnSpeed()); double turnTopSpeed = Math.min(topSpeed, train.maxTurnSpeed());
@ -540,6 +542,21 @@ public class Navigation {
if (graph == null) if (graph == null)
return; return;
// Cache the list of track types that the train can travel on
Set<TrackMaterial.TrackType> validTypes = new HashSet<>();
for (int i = 0; i < train.carriages.size(); i++) {
Carriage carriage = train.carriages.get(i);
if (i == 0) {
validTypes.addAll(carriage.leadingBogey().type.getValidPathfindingTypes(carriage.leadingBogey().getStyle()));
} else {
validTypes.retainAll(carriage.leadingBogey().type.getValidPathfindingTypes(carriage.leadingBogey().getStyle()));
}
if (carriage.isOnTwoBogeys())
validTypes.retainAll(carriage.trailingBogey().type.getValidPathfindingTypes(carriage.trailingBogey().getStyle()));
}
if (validTypes.isEmpty()) // if there are no valid track types, a route can't be found
return;
Map<TrackEdge, Integer> penalties = new IdentityHashMap<>(); Map<TrackEdge, Integer> penalties = new IdentityHashMap<>();
boolean costRelevant = maxCost >= 0; boolean costRelevant = maxCost >= 0;
if (costRelevant) { if (costRelevant) {
@ -579,7 +596,7 @@ public class Navigation {
.get(initialNode2); .get(initialNode2);
if (initialEdge == null) if (initialEdge == null)
return; return;
double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position; double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position;
frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge)); frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge));
@ -659,6 +676,8 @@ public class Navigation {
continue; continue;
for (Entry<TrackNode, TrackEdge> target : validTargets) { for (Entry<TrackNode, TrackEdge> target : validTargets) {
if (!validTypes.contains(target.getValue().getTrackMaterial().trackType))
continue;
TrackNode newNode = target.getKey(); TrackNode newNode = target.getKey();
TrackEdge newEdge = target.getValue(); TrackEdge newEdge = target.getValue();
double newDistance = newEdge.getLength() + distance; double newDistance = newEdge.getLength() + distance;

View file

@ -17,6 +17,10 @@ import java.util.function.Consumer;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.mutable.MutableObject;
@ -124,7 +128,7 @@ public class Train {
public int honkPitch; public int honkPitch;
public float accumulatedSteamRelease; public float accumulatedSteamRelease;
int tickOffset; int tickOffset;
double[] stress; double[] stress;
@ -277,7 +281,7 @@ public class Train {
int carriageCount = carriages.size(); int carriageCount = carriages.size();
boolean stalled = false; boolean stalled = false;
double maxStress = 0; double maxStress = 0;
if (carriageWaitingForChunks != -1) if (carriageWaitingForChunks != -1)
distance = 0; distance = 0;
@ -313,11 +317,17 @@ public class Train {
if (leadingAnchor == null || trailingAnchor == null) if (leadingAnchor == null || trailingAnchor == null)
continue; continue;
total += leadingAnchor.distanceTo(trailingAnchor); double distanceTo = leadingAnchor.distanceToSqr(trailingAnchor);
if (carriage.leadingBogey().isUpsideDown() != previousCarriage.trailingBogey().isUpsideDown()) {
distanceTo = Math.sqrt(distanceTo - 4);
} else {
distanceTo = Math.sqrt(distanceTo);
}
total += distanceTo;
entries++; entries++;
} }
} }
if (entries > 0) if (entries > 0)
actual = total / entries; actual = total / entries;
@ -369,13 +379,13 @@ public class Train {
.getLeadingPoint(); .getLeadingPoint();
double totalStress = derailed ? 0 : leadingStress + trailingStress; double totalStress = derailed ? 0 : leadingStress + trailingStress;
boolean first = i == 0; boolean first = i == 0;
boolean last = i == carriageCount - 1; boolean last = i == carriageCount - 1;
int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE; int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE;
double actualDistance = double actualDistance =
carriage.travel(level, graph, distance + totalStress, toFollowForward, toFollowBackward, carriageType); carriage.travel(level, graph, distance + totalStress, toFollowForward, toFollowBackward, carriageType);
blocked |= carriage.blocked; blocked |= carriage.blocked || carriage.isOnIncompatibleTrack();
boolean onTwoBogeys = carriage.isOnTwoBogeys(); boolean onTwoBogeys = carriage.isOnTwoBogeys();
maxStress = Math.max(maxStress, onTwoBogeys ? carriage.bogeySpacing - carriage.getAnchorDiff() : 0); maxStress = Math.max(maxStress, onTwoBogeys ? carriage.bogeySpacing - carriage.getAnchorDiff() : 0);
@ -722,9 +732,20 @@ public class Train {
if (entity.getContraption()instanceof CarriageContraption cc) if (entity.getContraption()instanceof CarriageContraption cc)
cc.returnStorageForDisassembly(carriage.storage); cc.returnStorageForDisassembly(carriage.storage);
entity.setPos(Vec3 entity.setPos(Vec3
.atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset))); .atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset).below(carriage.leadingBogey().isUpsideDown() ? 2 : 0)));
entity.disassemble(); entity.disassemble();
for (CarriageBogey bogey : carriage.bogeys) {
if (bogey == null)
continue;
Vec3 bogeyPosition = bogey.getAnchorPosition();
if (bogeyPosition == null) continue;
BlockEntity be = level.getBlockEntity(new BlockPos(bogeyPosition));
if (!(be instanceof AbstractBogeyTileEntity sbte))
continue;
sbte.setBogeyData(bogey.bogeyData);
}
offset += carriage.bogeySpacing; offset += carriage.bogeySpacing;
if (i < carriageSpacing.size()) if (i < carriageSpacing.size())
@ -944,7 +965,7 @@ public class Train {
occupiedObservers.clear(); occupiedObservers.clear();
cachedObserverFiltering.clear(); cachedObserverFiltering.clear();
TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position); TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position, false);
Map<UUID, SignalEdgeGroup> allGroups = Create.RAILWAYS.signalEdgeGroups; Map<UUID, SignalEdgeGroup> allGroups = Create.RAILWAYS.signalEdgeGroups;
MutableObject<UUID> prevGroup = new MutableObject<>(null); MutableObject<UUID> prevGroup = new MutableObject<>(null);

View file

@ -7,12 +7,13 @@ import java.util.UUID;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.simibubi.create.CreateClient; import com.simibubi.create.CreateClient;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.foundation.networking.SimplePacketBase; import com.simibubi.create.foundation.networking.SimplePacketBase;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.RegisteredObjects; import com.simibubi.create.foundation.utility.RegisteredObjects;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
@ -44,11 +45,13 @@ public class TrainPacket extends SimplePacketBase {
int size = buffer.readVarInt(); int size = buffer.readVarInt();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
Couple<CarriageBogey> bogies = Couple.create(null, null); Couple<CarriageBogey> bogies = Couple.create(null, null);
for (boolean first : Iterate.trueAndFalse) { for (boolean isFirst : Iterate.trueAndFalse) {
if (!first && !buffer.readBoolean()) if (!isFirst && !buffer.readBoolean())
continue; continue;
IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation()); AbstractBogeyBlock<?> type = (AbstractBogeyBlock<?>) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation());
bogies.set(first, new CarriageBogey(type, new TravellingPoint(), new TravellingPoint())); boolean upsideDown = buffer.readBoolean();
CompoundTag data = buffer.readNbt();
bogies.set(isFirst, new CarriageBogey(type, upsideDown, data, new TravellingPoint(), new TravellingPoint()));
} }
int spacing = buffer.readVarInt(); int spacing = buffer.readVarInt();
carriages.add(new Carriage(bogies.getFirst(), bogies.getSecond(), spacing)); carriages.add(new Carriage(bogies.getFirst(), bogies.getSecond(), spacing));
@ -86,6 +89,8 @@ public class TrainPacket extends SimplePacketBase {
} }
CarriageBogey bogey = carriage.bogeys.get(first); CarriageBogey bogey = carriage.bogeys.get(first);
buffer.writeResourceLocation(RegisteredObjects.getKeyOrThrow((Block) bogey.type)); buffer.writeResourceLocation(RegisteredObjects.getKeyOrThrow((Block) bogey.type));
buffer.writeBoolean(bogey.upsideDown);
buffer.writeNbt(bogey.bogeyData);
} }
buffer.writeVarInt(carriage.bogeySpacing); buffer.writeVarInt(carriage.bogeySpacing);
} }

View file

@ -115,10 +115,13 @@ public class TrainRelocator {
BlockPos blockPos = blockhit.getBlockPos(); BlockPos blockPos = blockhit.getBlockPos();
BezierTrackPointLocation hoveredBezier = null; BezierTrackPointLocation hoveredBezier = null;
boolean upsideDown = relocating.carriages.get(0).leadingBogey().isUpsideDown();
Vec3 offset = upsideDown ? new Vec3(0, -0.5, 0) : Vec3.ZERO;
if (simulate && toVisualise != null && lastHoveredResult != null) { if (simulate && toVisualise != null && lastHoveredResult != null) {
for (int i = 0; i < toVisualise.size() - 1; i++) { for (int i = 0; i < toVisualise.size() - 1; i++) {
Vec3 vec1 = toVisualise.get(i); Vec3 vec1 = toVisualise.get(i).add(offset);
Vec3 vec2 = toVisualise.get(i + 1); Vec3 vec2 = toVisualise.get(i + 1).add(offset);
CreateClient.OUTLINER.showLine(Pair.of(relocating, i), vec1.add(0, -.925f, 0), vec2.add(0, -.925f, 0)) CreateClient.OUTLINER.showLine(Pair.of(relocating, i), vec1.add(0, -.925f, 0), vec2.add(0, -.925f, 0))
.colored(lastHoveredResult || i != toVisualise.size() - 2 ? 0x95CD41 : 0xEA5C2B) .colored(lastHoveredResult || i != toVisualise.size() - 2 ? 0x95CD41 : 0xEA5C2B)
.disableLineNormals() .disableLineNormals()
@ -150,7 +153,7 @@ public class TrainRelocator {
boolean direction = bezierSelection != null && lookAngle.dot(bezierSelection.direction()) < 0; boolean direction = bezierSelection != null && lookAngle.dot(bezierSelection.direction()) < 0;
boolean result = relocate(relocating, mc.level, blockPos, hoveredBezier, direction, lookAngle, true); boolean result = relocate(relocating, mc.level, blockPos, hoveredBezier, direction, lookAngle, true);
if (!simulate && result) { if (!simulate && result) {
relocating.carriages.forEach(c -> c.forEachPresentEntity(e -> e.nonDamageTicks = 10)); relocating.carriages.forEach(c -> c.forEachPresentEntity(e -> e.nonDamageTicks = 10));
AllPackets.channel.sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, hoveredBezier, AllPackets.channel.sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, hoveredBezier,
direction, lookAngle, relocatingEntityId)); direction, lookAngle, relocatingEntityId));
} }
@ -182,7 +185,7 @@ public class TrainRelocator {
if (edge == null) if (edge == null)
return false; return false;
TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position); TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position, false);
IEdgePointListener ignoreSignals = probe.ignoreEdgePoints(); IEdgePointListener ignoreSignals = probe.ignoreEdgePoints();
ITurnListener ignoreTurns = probe.ignoreTurns(); ITurnListener ignoreTurns = probe.ignoreTurns();
List<Pair<Couple<TrackNode>, Double>> recordedLocations = new ArrayList<>(); List<Pair<Couple<TrackNode>, Double>> recordedLocations = new ArrayList<>();

View file

@ -38,6 +38,7 @@ public class TravellingPoint {
public TrackEdge edge; public TrackEdge edge;
public double position; public double position;
public boolean blocked; public boolean blocked;
public boolean upsideDown;
public static enum SteerDirection { public static enum SteerDirection {
NONE(0), LEFT(-1), RIGHT(1); NONE(0), LEFT(-1), RIGHT(1);
@ -64,11 +65,12 @@ public class TravellingPoint {
public TravellingPoint() {} public TravellingPoint() {}
public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position) { public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position, boolean upsideDown) {
this.node1 = node1; this.node1 = node1;
this.node2 = node2; this.node2 = node2;
this.edge = edge; this.edge = edge;
this.position = position; this.position = position;
this.upsideDown = upsideDown;
} }
public IEdgePointListener ignoreEdgePoints() { public IEdgePointListener ignoreEdgePoints() {
@ -395,14 +397,22 @@ public class TravellingPoint {
} }
public Vec3 getPosition() { public Vec3 getPosition() {
return getPositionWithOffset(0); return getPosition(false);
}
public Vec3 getPosition(boolean flipped) {
return getPositionWithOffset(0, flipped);
} }
public Vec3 getPositionWithOffset(double offset) { public Vec3 getPositionWithOffset(double offset) {
return getPositionWithOffset(offset, false);
}
public Vec3 getPositionWithOffset(double offset, boolean flipUpsideDown) {
double t = (position + offset) / edge.getLength(); double t = (position + offset) / edge.getLength();
return edge.getPosition(t) return edge.getPosition(t)
.add(edge.getNormal(node1, node2, t) .add(edge.getNormal(node1, node2, t)
.scale(1)); .scale(upsideDown^flipUpsideDown ? -1 : 1));
} }
public void migrateTo(List<GraphLocation> locations) { public void migrateTo(List<GraphLocation> locations) {
@ -423,12 +433,13 @@ public class TravellingPoint {
tag.put("Nodes", nodes.map(TrackNode::getLocation) tag.put("Nodes", nodes.map(TrackNode::getLocation)
.serializeEach(loc -> loc.write(dimensions))); .serializeEach(loc -> loc.write(dimensions)));
tag.putDouble("Position", position); tag.putDouble("Position", position);
tag.putBoolean("UpsideDown", upsideDown);
return tag; return tag;
} }
public static TravellingPoint read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { public static TravellingPoint read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
if (graph == null) if (graph == null)
return new TravellingPoint(null, null, null, 0); return new TravellingPoint(null, null, null, 0, false);
Couple<TrackNode> locs = tag.contains("Nodes") Couple<TrackNode> locs = tag.contains("Nodes")
? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions)) ? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions))
@ -436,11 +447,11 @@ public class TravellingPoint {
: Couple.create(null, null); : Couple.create(null, null);
if (locs.either(Objects::isNull)) if (locs.either(Objects::isNull))
return new TravellingPoint(null, null, null, 0); return new TravellingPoint(null, null, null, 0, false);
double position = tag.getDouble("Position"); double position = tag.getDouble("Position");
return new TravellingPoint(locs.getFirst(), locs.getSecond(), graph.getConnectionsFrom(locs.getFirst()) return new TravellingPoint(locs.getFirst(), locs.getSecond(), graph.getConnectionsFrom(locs.getFirst())
.get(locs.getSecond()), position); .get(locs.getSecond()), position, tag.getBoolean("UpsideDown"));
} }
} }

View file

@ -21,7 +21,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.ITr
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.block.depot.DepotBehaviour; import com.simibubi.create.content.logistics.block.depot.DepotBehaviour;
import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock;
import com.simibubi.create.content.logistics.trains.TrackEdge; import com.simibubi.create.content.logistics.trains.TrackEdge;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
@ -38,6 +38,7 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePoi
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour;
import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; import com.simibubi.create.content.logistics.trains.management.schedule.Schedule;
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleItem; import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleItem;
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
@ -51,6 +52,7 @@ import com.simibubi.create.foundation.utility.WorldAttached;
import com.simibubi.create.foundation.utility.animation.LerpedFloat; import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos; import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
@ -66,6 +68,7 @@ import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.BoundingBox;
@ -189,7 +192,8 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
Direction assemblyDirection; Direction assemblyDirection;
int assemblyLength; int assemblyLength;
int[] bogeyLocations; int[] bogeyLocations;
IBogeyBlock[] bogeyTypes; AbstractBogeyBlock<?>[] bogeyTypes;
boolean[] upsideDownBogeys;
int bogeyCount; int bogeyCount;
@Override @Override
@ -266,14 +270,30 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return false; return false;
BlockPos up = new BlockPos(track.getUpNormal(level, pos, state)); BlockPos up = new BlockPos(track.getUpNormal(level, pos, state));
BlockPos down = new BlockPos(track.getUpNormal(level, pos, state).scale(-1));
int bogeyOffset = pos.distManhattan(edgePoint.getGlobalPosition()) - 1; int bogeyOffset = pos.distManhattan(edgePoint.getGlobalPosition()) - 1;
if (!isValidBogeyOffset(bogeyOffset)) { if (!isValidBogeyOffset(bogeyOffset)) {
for (int i = -1; i <= 1; i++) { for (boolean upsideDown : Iterate.falseAndTrue) {
BlockPos bogeyPos = pos.relative(assemblyDirection, i) for (int i = -1; i <= 1; i++) {
.offset(up); BlockPos bogeyPos = pos.relative(assemblyDirection, i)
BlockState blockState = level.getBlockState(bogeyPos); .offset(upsideDown ? down : up);
if (blockState.getBlock() instanceof IBogeyBlock bogey) { BlockState blockState = level.getBlockState(bogeyPos);
level.setBlock(bogeyPos, bogey.getRotatedBlockState(blockState, Direction.DOWN), 3); if (!(blockState.getBlock() instanceof AbstractBogeyBlock<?> bogey))
continue;
BlockEntity be = level.getBlockEntity(bogeyPos);
if (!(be instanceof AbstractBogeyTileEntity oldTE))
continue;
CompoundTag oldData = oldTE.getBogeyData();
BlockState newBlock = bogey.getNextSize(oldTE);
if (newBlock.getBlock() == bogey)
player.displayClientMessage(Lang.translateDirect("bogey.style.no_other_sizes")
.withStyle(ChatFormatting.RED), true);
level.setBlock(bogeyPos, newBlock, 3);
BlockEntity newEntity = level.getBlockEntity(bogeyPos);
if (!(newEntity instanceof AbstractBogeyTileEntity newTE))
continue;
newTE.setBogeyData(oldData);
bogey.playRotateSound(level, bogeyPos); bogey.playRotateSound(level, bogeyPos);
return true; return true;
} }
@ -288,7 +308,9 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return false; return false;
} }
BlockPos targetPos = pos.offset(up); boolean upsideDown = (player.getViewXRot(1.0F) < 0 && (track.getBogeyAnchor(level, pos, state)).getBlock() instanceof AbstractBogeyBlock<?> bogey && bogey.canBeUpsideDown());
BlockPos targetPos = upsideDown ? pos.offset(down) : pos.offset(up);
if (level.getBlockState(targetPos) if (level.getBlockState(targetPos)
.getDestroySpeed(level, targetPos) == -1) { .getDestroySpeed(level, targetPos) == -1) {
return false; return false;
@ -296,7 +318,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
level.destroyBlock(targetPos, true); level.destroyBlock(targetPos, true);
BlockState bogeyAnchor = ProperWaterloggedBlock.withWater(level, track.getBogeyAnchor(level, pos, state), pos); BlockState bogeyAnchor = track.getBogeyAnchor(level, pos, state);
if (bogeyAnchor.getBlock() instanceof AbstractBogeyBlock<?> bogey) {
bogeyAnchor = bogey.getVersion(bogeyAnchor, upsideDown);
}
bogeyAnchor = ProperWaterloggedBlock.withWater(level, bogeyAnchor, pos);
level.setBlock(targetPos, bogeyAnchor, 3); level.setBlock(targetPos, bogeyAnchor, 3);
player.displayClientMessage(Lang.translateDirect("train_assembly.bogey_created"), true); player.displayClientMessage(Lang.translateDirect("train_assembly.bogey_created"), true);
SoundType soundtype = bogeyAnchor.getBlock() SoundType soundtype = bogeyAnchor.getBlock()
@ -370,9 +396,12 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
if (bogeyLocations == null) if (bogeyLocations == null)
bogeyLocations = new int[maxBogeyCount]; bogeyLocations = new int[maxBogeyCount];
if (bogeyTypes == null) if (bogeyTypes == null)
bogeyTypes = new IBogeyBlock[maxBogeyCount]; bogeyTypes = new AbstractBogeyBlock[maxBogeyCount];
if (upsideDownBogeys == null)
upsideDownBogeys = new boolean[maxBogeyCount];
Arrays.fill(bogeyLocations, -1); Arrays.fill(bogeyLocations, -1);
Arrays.fill(bogeyTypes, null); Arrays.fill(bogeyTypes, null);
Arrays.fill(upsideDownBogeys, false);
for (int i = 0; i < MAX_LENGTH; i++) { for (int i = 0; i < MAX_LENGTH; i++) {
if (i == MAX_LENGTH - 1) { if (i == MAX_LENGTH - 1) {
@ -385,10 +414,19 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
} }
BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos)); BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos));
if (potentialBogeyState.getBlock() instanceof IBogeyBlock bogey && bogeyIndex < bogeyLocations.length) { BlockPos upsideDownBogeyOffset = new BlockPos(bogeyOffset.getX(), bogeyOffset.getY()*-1, bogeyOffset.getZ());
bogeyTypes[bogeyIndex] = bogey; if (bogeyIndex < bogeyLocations.length) {
bogeyLocations[bogeyIndex] = i; if (potentialBogeyState.getBlock() instanceof AbstractBogeyBlock<?> bogey && !bogey.isUpsideDown(potentialBogeyState)) {
bogeyIndex++; bogeyTypes[bogeyIndex] = bogey;
bogeyLocations[bogeyIndex] = i;
upsideDownBogeys[bogeyIndex] = false;
bogeyIndex++;
} else if ((potentialBogeyState = level.getBlockState(upsideDownBogeyOffset.offset(currentPos))).getBlock() instanceof AbstractBogeyBlock<?> bogey && bogey.isUpsideDown(potentialBogeyState)) {
bogeyTypes[bogeyIndex] = bogey;
bogeyLocations[bogeyIndex] = i;
upsideDownBogeys[bogeyIndex] = true;
bogeyIndex++;
}
} }
currentPos.move(assemblyDirection); currentPos.move(assemblyDirection);
@ -548,7 +586,7 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return; return;
} }
points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge)); points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge, false));
} }
secondNode = node; secondNode = node;
@ -575,10 +613,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
spacing.add(bogeyLocations[bogeyIndex] - bogeyLocations[bogeyIndex - 1]); spacing.add(bogeyLocations[bogeyIndex] - bogeyLocations[bogeyIndex - 1]);
CarriageContraption contraption = new CarriageContraption(assemblyDirection); CarriageContraption contraption = new CarriageContraption(assemblyDirection);
BlockPos bogeyPosOffset = trackPosition.offset(bogeyOffset); BlockPos bogeyPosOffset = trackPosition.offset(bogeyOffset);
BlockPos upsideDownBogeyPosOffset = trackPosition.offset(new BlockPos(bogeyOffset.getX(), bogeyOffset.getY() * -1, bogeyOffset.getZ()));
try { try {
int offset = bogeyLocations[bogeyIndex] + 1; int offset = bogeyLocations[bogeyIndex] + 1;
boolean success = contraption.assemble(level, bogeyPosOffset.relative(assemblyDirection, offset)); boolean success = contraption.assemble(level, upsideDownBogeys[bogeyIndex] ? upsideDownBogeyPosOffset.relative(assemblyDirection, offset) : bogeyPosOffset.relative(assemblyDirection, offset));
atLeastOneForwardControls |= contraption.hasForwardControls(); atLeastOneForwardControls |= contraption.hasForwardControls();
contraption.setSoundQueueOffset(offset); contraption.setSoundQueueOffset(offset);
if (!success) { if (!success) {
@ -591,24 +630,28 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return; return;
} }
IBogeyBlock typeOfFirstBogey = bogeyTypes[bogeyIndex]; AbstractBogeyBlock<?> typeOfFirstBogey = bogeyTypes[bogeyIndex];
boolean firstBogeyIsUpsideDown = upsideDownBogeys[bogeyIndex];
BlockPos firstBogeyPos = contraption.anchor;
AbstractBogeyTileEntity firstBogeyTileEntity = (AbstractBogeyTileEntity) level.getBlockEntity(firstBogeyPos);
CarriageBogey firstBogey = CarriageBogey firstBogey =
new CarriageBogey(typeOfFirstBogey, points.get(pointIndex), points.get(pointIndex + 1)); new CarriageBogey(typeOfFirstBogey, firstBogeyIsUpsideDown, firstBogeyTileEntity.getBogeyData(), points.get(pointIndex), points.get(pointIndex + 1));
CarriageBogey secondBogey = null; CarriageBogey secondBogey = null;
BlockPos secondBogeyPos = contraption.getSecondBogeyPos(); BlockPos secondBogeyPos = contraption.getSecondBogeyPos();
int bogeySpacing = 0; int bogeySpacing = 0;
if (secondBogeyPos != null) { if (secondBogeyPos != null) {
if (bogeyIndex == bogeyCount - 1 || !secondBogeyPos if (bogeyIndex == bogeyCount - 1 || !secondBogeyPos
.equals(bogeyPosOffset.relative(assemblyDirection, bogeyLocations[bogeyIndex + 1] + 1))) { .equals((upsideDownBogeys[bogeyIndex + 1] ? upsideDownBogeyPosOffset : bogeyPosOffset).relative(assemblyDirection, bogeyLocations[bogeyIndex + 1] + 1))) {
exception(new AssemblyException(Lang.translateDirect("train_assembly.not_connected_in_order")), exception(new AssemblyException(Lang.translateDirect("train_assembly.not_connected_in_order")),
contraptions.size() + 1); contraptions.size() + 1);
return; return;
} }
AbstractBogeyTileEntity secondBogeyTileEntity =
(AbstractBogeyTileEntity) level.getBlockEntity(secondBogeyPos);
bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex]; bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex];
secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], points.get(pointIndex + 2), secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], upsideDownBogeys[bogeyIndex + 1], secondBogeyTileEntity.getBogeyData(),
points.get(pointIndex + 3)); points.get(pointIndex + 2), points.get(pointIndex + 3));
bogeyIndex++; bogeyIndex++;
} else if (!typeOfFirstBogey.allowsSingleBogeyCarriage()) { } else if (!typeOfFirstBogey.allowsSingleBogeyCarriage()) {

View file

@ -0,0 +1,119 @@
package com.simibubi.create.content.logistics.trains.track;
import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import org.jetbrains.annotations.NotNull;
import static com.simibubi.create.content.logistics.trains.entity.CarriageBogey.UPSIDE_DOWN_KEY;
public abstract class AbstractBogeyTileEntity extends CachedRenderBBTileEntity {
public static final String BOGEY_STYLE_KEY = "BogeyStyle";
public static final String BOGEY_DATA_KEY = "BogeyData";
private CompoundTag bogeyData;
public AbstractBogeyTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}
public abstract BogeyStyle getDefaultStyle();
public CompoundTag getBogeyData() {
if (this.bogeyData == null || !this.bogeyData.contains(BOGEY_STYLE_KEY))
this.bogeyData = this.createBogeyData();
return this.bogeyData;
}
public void setBogeyData(@NotNull CompoundTag newData) {
if (!newData.contains(BOGEY_STYLE_KEY)) {
ResourceLocation style = getDefaultStyle().name;
NBTHelper.writeResourceLocation(newData, BOGEY_STYLE_KEY, style);
}
this.bogeyData = newData;
}
public void setBogeyStyle(@NotNull BogeyStyle style) {
ResourceLocation location = style.name;
CompoundTag data = this.getBogeyData();
NBTHelper.writeResourceLocation(data, BOGEY_STYLE_KEY, location);
markUpdated();
}
@NotNull
public BogeyStyle getStyle() {
CompoundTag data = this.getBogeyData();
ResourceLocation currentStyle = NBTHelper.readResourceLocation(data, BOGEY_STYLE_KEY);
BogeyStyle style = AllBogeyStyles.BOGEY_STYLES.get(currentStyle);
if (style == null) {
setBogeyStyle(getDefaultStyle());
return getStyle();
}
return style;
}
@Override
protected void saveAdditional(@NotNull CompoundTag pTag) {
CompoundTag data = this.getBogeyData();
if (data != null) pTag.put(BOGEY_DATA_KEY, data); // Now contains style
super.saveAdditional(pTag);
}
@Override
public void load(CompoundTag pTag) {
if (pTag.contains(BOGEY_DATA_KEY))
this.bogeyData = pTag.getCompound(BOGEY_DATA_KEY);
else
this.bogeyData = this.createBogeyData();
super.load(pTag);
}
private CompoundTag createBogeyData() {
CompoundTag nbt = new CompoundTag();
NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, getDefaultStyle().name);
boolean upsideDown = false;
if (getBlockState().getBlock() instanceof AbstractBogeyBlock<?> bogeyBlock)
upsideDown = bogeyBlock.isUpsideDown(getBlockState());
nbt.putBoolean(UPSIDE_DOWN_KEY, upsideDown);
return nbt;
}
@Override
protected AABB createRenderBoundingBox() {
return super.createRenderBoundingBox().inflate(2);
}
// Ponder
LerpedFloat virtualAnimation = LerpedFloat.angular();
public float getVirtualAngle(float partialTicks) {
return virtualAnimation.getValue(partialTicks);
}
public void animate(float distanceMoved) {
BlockState blockState = getBlockState();
if (!(blockState.getBlock() instanceof AbstractBogeyBlock<?> type))
return;
double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius());
double newWheelAngle = (virtualAnimation.getValue() - angleDiff) % 360;
virtualAnimation.setValue(newWheelAngle);
}
private void markUpdated() {
setChanged();
Level level = getLevel();
if (level != null)
getLevel().sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
}

View file

@ -1,7 +1,7 @@
package com.simibubi.create.content.logistics.trains.track; package com.simibubi.create.content.logistics.trains.track;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllTags;
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem;
import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection; import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection;
import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.AllPackets;
@ -117,7 +117,7 @@ public class CurvedTrackInteraction {
if (event.isUseItem()) { if (event.isUseItem()) {
ItemStack heldItem = player.getMainHandItem(); ItemStack heldItem = player.getMainHandItem();
Item item = heldItem.getItem(); Item item = heldItem.getItem();
if (AllBlocks.TRACK.isIn(heldItem)) { if (AllTags.AllBlockTags.TRACKS.matches(heldItem)) {
player.displayClientMessage(Lang.translateDirect("track.turn_start") player.displayClientMessage(Lang.translateDirect("track.turn_start")
.withStyle(ChatFormatting.RED), true); .withStyle(ChatFormatting.RED), true);
player.swing(InteractionHand.MAIN_HAND); player.swing(InteractionHand.MAIN_HAND);

View file

@ -2,7 +2,7 @@ package com.simibubi.create.content.logistics.trains.track;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTags;
import com.simibubi.create.foundation.networking.SimplePacketBase; import com.simibubi.create.foundation.networking.SimplePacketBase;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -16,7 +16,7 @@ public class PlaceExtendedCurvePacket extends SimplePacketBase {
boolean mainHand; boolean mainHand;
boolean ctrlDown; boolean ctrlDown;
public PlaceExtendedCurvePacket(boolean mainHand, boolean ctrlDown) { public PlaceExtendedCurvePacket(boolean mainHand, boolean ctrlDown) {
this.mainHand = mainHand; this.mainHand = mainHand;
this.ctrlDown = ctrlDown; this.ctrlDown = ctrlDown;
@ -39,7 +39,7 @@ public class PlaceExtendedCurvePacket extends SimplePacketBase {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
ServerPlayer sender = ctx.getSender(); ServerPlayer sender = ctx.getSender();
ItemStack stack = sender.getItemInHand(mainHand ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); ItemStack stack = sender.getItemInHand(mainHand ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND);
if (!AllBlocks.TRACK.isIn(stack) || !stack.hasTag()) if (!AllTags.AllBlockTags.TRACKS.matches(stack) || !stack.hasTag())
return; return;
CompoundTag tag = stack.getTag(); CompoundTag tag = stack.getTag();
tag.putBoolean("ExtendCurve", true); tag.putBoolean("ExtendCurve", true);

View file

@ -1,87 +1,35 @@
package com.simibubi.create.content.logistics.trains.track; package com.simibubi.create.content.logistics.trains.track;
import java.util.EnumSet;
import com.jozufozu.flywheel.api.MaterialManager;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Vector3f;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.BogeySizes;
import com.simibubi.create.content.logistics.trains.entity.BogeyInstance; import com.simibubi.create.content.logistics.trains.TrackMaterial;
import com.simibubi.create.content.logistics.trains.entity.CarriageBogey; import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class StandardBogeyBlock extends Block public class StandardBogeyBlock extends AbstractBogeyBlock<StandardBogeyTileEntity> implements ITE<StandardBogeyTileEntity>, ProperWaterloggedBlock, ISpecialBlockItemRequirement {
implements IBogeyBlock, ITE<StandardBogeyTileEntity>, ProperWaterloggedBlock, ISpecialBlockItemRequirement {
public static final EnumProperty<Axis> AXIS = BlockStateProperties.HORIZONTAL_AXIS; public StandardBogeyBlock(Properties props, BogeySizes.BogeySize size) {
private final boolean large; super(props, size);
public StandardBogeyBlock(Properties p_i48440_1_, boolean large) {
super(p_i48440_1_);
this.large = large;
registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false));
} }
@Override @Override
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) { public TrackMaterial.TrackType getTrackType(BogeyStyle style) {
builder.add(AXIS, WATERLOGGED); return TrackMaterial.TrackType.STANDARD;
super.createBlockStateDefinition(builder);
}
static final EnumSet<Direction> STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST);
static final EnumSet<Direction> STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH);
@Override
public EnumSet<Direction> getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state) {
return state.getValue(BlockStateProperties.HORIZONTAL_AXIS) == Axis.X ? STICKY_X : STICKY_Z;
}
@Override
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
updateWater(pLevel, pState, pCurrentPos);
return pState;
}
@Override
public FluidState getFluidState(BlockState pState) {
return fluidState(pState);
} }
@Override @Override
@ -91,7 +39,7 @@ public class StandardBogeyBlock extends Block
@Override @Override
public double getWheelRadius() { public double getWheelRadius() {
return (large ? 12.5 : 6.5) / 16d; return (size == BogeySizes.LARGE ? 12.5 : 6.5) / 16d;
} }
@Override @Override
@ -100,122 +48,8 @@ public class StandardBogeyBlock extends Block
} }
@Override @Override
public boolean allowsSingleBogeyCarriage() { public BogeyStyle getDefaultStyle() {
return true; return AllBogeyStyles.STANDARD;
}
@Override
public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst) {
if (upDirection != Direction.UP)
return null;
return defaultBlockState().setValue(AXIS, axisAlongFirst ? Axis.X : Axis.Z);
}
@Override
public boolean isTrackAxisAlongFirstCoordinate(BlockState state) {
return state.getValue(AXIS) == Axis.X;
}
@Override
@OnlyIn(Dist.CLIENT)
public void render(BlockState state, float wheelAngle, PoseStack ms, float partialTicks, MultiBufferSource buffers,
int light, int overlay) {
if (state != null) {
ms.translate(.5f, .5f, .5f);
if (state.getValue(AXIS) == Axis.X)
ms.mulPose(Vector3f.YP.rotationDegrees(90));
}
ms.translate(0, -1.5 - 1 / 128f, 0);
VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped());
BlockState air = Blocks.AIR.defaultBlockState();
for (int i : Iterate.zeroAndOne)
CachedBufferer.block(AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Axis.Z))
.translate(-.5f, .25f, i * -1)
.centre()
.rotateZ(wheelAngle)
.unCentre()
.light(light)
.renderInto(ms, vb);
if (large) {
renderLargeBogey(wheelAngle, ms, light, vb, air);
} else {
renderBogey(wheelAngle, ms, light, vb, air);
}
}
private void renderBogey(float wheelAngle, PoseStack ms, int light, VertexConsumer vb, BlockState air) {
CachedBufferer.partial(AllBlockPartials.BOGEY_FRAME, air)
.scale(1 - 1 / 512f)
.light(light)
.renderInto(ms, vb);
for (int side : Iterate.positiveAndNegative) {
ms.pushPose();
CachedBufferer.partial(AllBlockPartials.SMALL_BOGEY_WHEELS, air)
.translate(0, 12 / 16f, side)
.rotateX(wheelAngle)
.light(light)
.renderInto(ms, vb);
ms.popPose();
}
}
private void renderLargeBogey(float wheelAngle, PoseStack ms, int light, VertexConsumer vb, BlockState air) {
for (int i : Iterate.zeroAndOne)
CachedBufferer.block(AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Axis.X))
.translate(-.5f, .25f, .5f + i * -2)
.centre()
.rotateX(wheelAngle)
.unCentre()
.light(light)
.renderInto(ms, vb);
CachedBufferer.partial(AllBlockPartials.BOGEY_DRIVE, air)
.scale(1 - 1 / 512f)
.light(light)
.renderInto(ms, vb);
CachedBufferer.partial(AllBlockPartials.BOGEY_PISTON, air)
.translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle)))
.light(light)
.renderInto(ms, vb);
ms.pushPose();
CachedBufferer.partial(AllBlockPartials.LARGE_BOGEY_WHEELS, air)
.translate(0, 1, 0)
.rotateX(wheelAngle)
.light(light)
.renderInto(ms, vb);
CachedBufferer.partial(AllBlockPartials.BOGEY_PIN, air)
.translate(0, 1, 0)
.rotateX(wheelAngle)
.translate(0, 1 / 4f, 0)
.rotateX(-wheelAngle)
.light(light)
.renderInto(ms, vb);
ms.popPose();
}
@Override
public BogeyInstance createInstance(MaterialManager materialManager, CarriageBogey bogey) {
if (large) {
return new BogeyInstance.Drive(bogey, materialManager);
} else {
return new BogeyInstance.Frame(bogey, materialManager);
}
}
@Override
public BlockState rotate(BlockState pState, Rotation pRotation) {
return switch (pRotation) {
case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> pState.cycle(AXIS);
default -> pState;
};
} }
@Override @Override
@ -233,10 +67,4 @@ public class StandardBogeyBlock extends Block
public BlockEntityType<? extends StandardBogeyTileEntity> getTileEntityType() { public BlockEntityType<? extends StandardBogeyTileEntity> getTileEntityType() {
return AllTileEntities.BOGEY.get(); return AllTileEntities.BOGEY.get();
} }
@Override
public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) {
return new ItemRequirement(ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack());
}
} }

View file

@ -1,40 +1,19 @@
package com.simibubi.create.content.logistics.trains.track; package com.simibubi.create.content.logistics.trains.track;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity; import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
public class StandardBogeyTileEntity extends CachedRenderBBTileEntity {
public class StandardBogeyTileEntity extends AbstractBogeyTileEntity {
public StandardBogeyTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { public StandardBogeyTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state); super(type, pos, state);
} }
@Override @Override
protected AABB createRenderBoundingBox() { public BogeyStyle getDefaultStyle() {
return super.createRenderBoundingBox().inflate(2); return AllBogeyStyles.STANDARD;
} }
// Ponder
LerpedFloat virtualAnimation = LerpedFloat.angular();
public float getVirtualAngle(float partialTicks) {
return virtualAnimation.getValue(partialTicks);
}
public void animate(float distanceMoved) {
BlockState blockState = getBlockState();
if (!(blockState.getBlock() instanceof IBogeyBlock type))
return;
double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius());
double newWheelAngle = (virtualAnimation.getValue() - angleDiff) % 360;
virtualAnimation.setValue(newWheelAngle);
}
} }

View file

@ -19,6 +19,13 @@ import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import com.simibubi.create.AllTags;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
@ -106,25 +113,30 @@ import net.minecraft.world.ticks.LevelTickAccess;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.IBlockRenderProperties; import net.minecraftforge.client.IBlockRenderProperties;
//init
public class TrackBlock extends Block public class TrackBlock extends Block
implements ITE<TrackTileEntity>, IWrenchable, ITrackBlock, ISpecialBlockItemRequirement, ProperWaterloggedBlock { implements ITE<TrackTileEntity>, IWrenchable, ITrackBlock, ISpecialBlockItemRequirement, ProperWaterloggedBlock {
public static final EnumProperty<TrackShape> SHAPE = EnumProperty.create("shape", TrackShape.class); public static final EnumProperty<TrackShape> SHAPE = EnumProperty.create("shape", TrackShape.class);
public static final BooleanProperty HAS_TE = BooleanProperty.create("turn"); public static final BooleanProperty HAS_TE = BooleanProperty.create("turn");
public TrackBlock(Properties p_49795_) { protected final TrackMaterial material;
public TrackBlock(Properties p_49795_, TrackMaterial material) {
super(p_49795_); super(p_49795_);
registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO) registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO)
.setValue(HAS_TE, false) .setValue(HAS_TE, false)
.setValue(WATERLOGGED, false)); .setValue(WATERLOGGED, false));
this.material = material;
} }
@Override @Override
protected void createBlockStateDefinition(Builder<Block, BlockState> p_49915_) { protected void createBlockStateDefinition(Builder<Block, BlockState> p_49915_) {
super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TE, WATERLOGGED)); super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TE, WATERLOGGED));
} }
@Override @Override
public BlockPathTypes getAiPathNodeType(BlockState state, BlockGetter world, BlockPos pos, Mob entity) { public BlockPathTypes getAiPathNodeType(BlockState state, BlockGetter world, BlockPos pos, Mob entity) {
return BlockPathTypes.RAIL; return BlockPathTypes.RAIL;
@ -379,7 +391,7 @@ public class TrackBlock extends Block
(d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d) (d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d)
.add(center), .add(center),
b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis, b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis,
null); null, (b, v) -> ITrackBlock.getMaterialSimple(world, v));
} else } else
list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo); list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo);
@ -395,7 +407,7 @@ public class TrackBlock extends Block
Map<BlockPos, BezierConnection> connections = trackTE.getConnections(); Map<BlockPos, BezierConnection> connections = trackTE.getConnections();
connections.forEach((connectedPos, bc) -> ITrackBlock.addToListIfConnected(connectedTo, list, connections.forEach((connectedPos, bc) -> ITrackBlock.addToListIfConnected(connectedTo, list,
(d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get, (d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get,
b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, null, bc)); b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, null, bc, (b, v) -> ITrackBlock.getMaterialSimple(world, v, bc.getMaterial())));
if (trackTE.boundLocation == null || !(world instanceof ServerLevel level)) if (trackTE.boundLocation == null || !(world instanceof ServerLevel level))
return list; return list;
@ -407,7 +419,7 @@ public class TrackBlock extends Block
return list; return list;
BlockPos boundPos = trackTE.boundLocation.getSecond(); BlockPos boundPos = trackTE.boundLocation.getSecond();
BlockState boundState = otherLevel.getBlockState(boundPos); BlockState boundState = otherLevel.getBlockState(boundPos);
if (!AllBlocks.TRACK.has(boundState)) if (!AllTags.AllBlockTags.TRACKS.matches(boundState))
return list; return list;
Vec3 center = Vec3.atBottomCenterOf(pos) Vec3 center = Vec3.atBottomCenterOf(pos)
@ -421,7 +433,7 @@ public class TrackBlock extends Block
getTrackAxes(world, pos, state).forEach(axis -> { getTrackAxes(world, pos, state).forEach(axis -> {
ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d) ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d)
.add(b ? center : boundCenter), b -> (b ? shape : boundShape).getNormal(), .add(b ? center : boundCenter), b -> (b ? shape : boundShape).getNormal(),
b -> b ? level.dimension() : otherLevel.dimension(), axis, null); b -> b ? level.dimension() : otherLevel.dimension(), axis, null, (b, v) -> ITrackBlock.getMaterialSimple(b ? level : otherLevel, v));
}); });
return list; return list;
@ -750,7 +762,8 @@ public class TrackBlock extends Block
@Override @Override
public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) {
int trackAmount = 1; int sameTypeTrackAmount = 1;
Object2IntMap<TrackMaterial> otherTrackAmounts = new Object2IntArrayMap<>();
int girderAmount = 0; int girderAmount = 0;
if (te instanceof TrackTileEntity track) { if (te instanceof TrackTileEntity track) {
@ -758,15 +771,27 @@ public class TrackBlock extends Block
.values()) { .values()) {
if (!bezierConnection.isPrimary()) if (!bezierConnection.isPrimary())
continue; continue;
trackAmount += bezierConnection.getTrackItemCost(); TrackMaterial material = bezierConnection.getMaterial();
if (material == getMaterial()) {
sameTypeTrackAmount += bezierConnection.getTrackItemCost();
} else {
otherTrackAmounts.put(material, otherTrackAmounts.getOrDefault(material, 0) + 1);
}
girderAmount += bezierConnection.getGirderItemCost(); girderAmount += bezierConnection.getGirderItemCost();
} }
} }
List<ItemStack> stacks = new ArrayList<>(); List<ItemStack> stacks = new ArrayList<>();
while (trackAmount > 0) { while (sameTypeTrackAmount > 0) {
stacks.add(AllBlocks.TRACK.asStack(Math.min(trackAmount, 64))); stacks.add(new ItemStack(state.getBlock(), Math.min(sameTypeTrackAmount, 64)));
trackAmount -= 64; sameTypeTrackAmount -= 64;
}
for (TrackMaterial material : otherTrackAmounts.keySet()) {
int amt = otherTrackAmounts.getOrDefault(material, 0);
while (amt > 0) {
stacks.add(new ItemStack(material.getTrackBlock().get(), Math.min(amt, 64)));
amt -= 64;
}
} }
while (girderAmount > 0) { while (girderAmount > 0) {
stacks.add(AllBlocks.METAL_GIRDER.asStack(Math.min(girderAmount, 64))); stacks.add(AllBlocks.METAL_GIRDER.asStack(Math.min(girderAmount, 64)));
@ -776,6 +801,11 @@ public class TrackBlock extends Block
return new ItemRequirement(ItemUseType.CONSUME, stacks); return new ItemRequirement(ItemUseType.CONSUME, stacks);
} }
@Override
public TrackMaterial getMaterial() {
return material;
}
public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler { public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler {
@Override @Override
@Nullable @Nullable

View file

@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.track;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.AllTags;
import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock;
import com.simibubi.create.content.logistics.trains.track.TrackPlacement.PlacementInfo; import com.simibubi.create.content.logistics.trains.track.TrackPlacement.PlacementInfo;
import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.AllPackets;
@ -111,7 +112,7 @@ public class TrackBlockItem extends BlockItem {
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
stack = player.getMainHandItem(); stack = player.getMainHandItem();
if (AllBlocks.TRACK.isIn(stack)) { if (AllTags.AllBlockTags.TRACKS.matches(stack)) {
stack.setTag(null); stack.setTag(null);
player.setItemInHand(pContext.getHand(), stack); player.setItemInHand(pContext.getHand(), stack);
} }
@ -154,7 +155,7 @@ public class TrackBlockItem extends BlockItem {
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public static void sendExtenderPacket(PlayerInteractEvent.RightClickBlock event) { public static void sendExtenderPacket(PlayerInteractEvent.RightClickBlock event) {
ItemStack stack = event.getItemStack(); ItemStack stack = event.getItemStack();
if (!AllBlocks.TRACK.isIn(stack) || !stack.hasTag()) if (!AllTags.AllBlockTags.TRACKS.matches(stack) || !stack.hasTag())
return; return;
if (Minecraft.getInstance().options.keySprint.isDown()) if (Minecraft.getInstance().options.keySprint.isDown())
AllPackets.channel AllPackets.channel

View file

@ -8,8 +8,8 @@ import java.util.function.Consumer;
import com.jozufozu.flywheel.util.transform.TransformStack; import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes; import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTags;
import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
@ -162,7 +162,7 @@ public class TrackBlockOutline {
.rotateXRadians(angles.x) .rotateXRadians(angles.x)
.translate(-.5, -.125f, -.5); .translate(-.5, -.125f, -.5);
boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem()); boolean holdingTrack = AllTags.AllBlockTags.TRACKS.matches(Minecraft.getInstance().player.getMainHandItem());
renderShape(AllShapes.TRACK_ORTHO.get(Direction.SOUTH), ms, vb, holdingTrack ? false : null); renderShape(AllShapes.TRACK_ORTHO.get(Direction.SOUTH), ms, vb, holdingTrack ? false : null);
ms.popPose(); ms.popPose();
} }
@ -190,7 +190,7 @@ public class TrackBlockOutline {
ms.pushPose(); ms.pushPose();
ms.translate(pos.getX() - camPos.x, pos.getY() - camPos.y, pos.getZ() - camPos.z); ms.translate(pos.getX() - camPos.x, pos.getY() - camPos.y, pos.getZ() - camPos.z);
boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem()); boolean holdingTrack = AllTags.AllBlockTags.TRACKS.matches(Minecraft.getInstance().player.getMainHandItem());
TrackShape shape = blockstate.getValue(TrackBlock.SHAPE); TrackShape shape = blockstate.getValue(TrackBlock.SHAPE);
boolean isJunction = shape.isJunction(); boolean isJunction = shape.isJunction();
walkShapes(shape, TransformStack.cast(ms), s -> { walkShapes(shape, TransformStack.cast(ms), s -> {

View file

@ -20,6 +20,7 @@ import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection;
import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles; import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles;
import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles; import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
@ -38,7 +39,7 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
@Override @Override
public void update() { public void update() {
if (blockEntity.connections.isEmpty()) if (blockEntity.connections.isEmpty())
return; return;
remove(); remove();
@ -112,11 +113,13 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
leftLightPos = new BlockPos[segCount]; leftLightPos = new BlockPos[segCount];
rightLightPos = new BlockPos[segCount]; rightLightPos = new BlockPos[segCount];
mat.getModel(AllBlockPartials.TRACK_TIE) TrackMaterial.TrackModelHolder modelHolder = bc.getMaterial().getModelHolder();
mat.getModel(modelHolder.tie())
.createInstances(ties); .createInstances(ties);
mat.getModel(AllBlockPartials.TRACK_SEGMENT_LEFT) mat.getModel(modelHolder.segment_left())
.createInstances(left); .createInstances(left);
mat.getModel(AllBlockPartials.TRACK_SEGMENT_RIGHT) mat.getModel(modelHolder.segment_right())
.createInstances(right); .createInstances(right);
SegmentAngles[] segments = bc.getBakedSegments(); SegmentAngles[] segments = bc.getBakedSegments();

View file

@ -7,12 +7,13 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import com.jozufozu.flywheel.util.Color; import com.jozufozu.flywheel.util.Color;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.AllTags;
import com.simibubi.create.CreateClient; import com.simibubi.create.CreateClient;
import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer; import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer;
import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection;
import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
@ -47,6 +48,7 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.HitResult.Type; import net.minecraft.world.phys.HitResult.Type;
@ -58,6 +60,11 @@ import net.minecraftforge.items.ItemHandlerHelper;
public class TrackPlacement { public class TrackPlacement {
public static class PlacementInfo { public static class PlacementInfo {
public PlacementInfo(TrackMaterial material) {
this.trackMaterial = material;
}
BezierConnection curve = null; BezierConnection curve = null;
boolean valid = false; boolean valid = false;
int end1Extent = 0; int end1Extent = 0;
@ -69,6 +76,7 @@ public class TrackPlacement {
public int requiredPavement = 0; public int requiredPavement = 0;
public boolean hasRequiredPavement = false; public boolean hasRequiredPavement = false;
public final TrackMaterial trackMaterial;
// for visualisation // for visualisation
Vec3 end1; Vec3 end1;
@ -108,7 +116,7 @@ public class TrackPlacement {
&& hoveringMaxed == maximiseTurn && lookAngle == hoveringAngle) && hoveringMaxed == maximiseTurn && lookAngle == hoveringAngle)
return cached; return cached;
PlacementInfo info = new PlacementInfo(); PlacementInfo info = new PlacementInfo(TrackMaterial.fromItem(stack.getItem()));
hoveringMaxed = maximiseTurn; hoveringMaxed = maximiseTurn;
hoveringAngle = lookAngle; hoveringAngle = lookAngle;
hoveringPos = pos2; hoveringPos = pos2;
@ -192,7 +200,7 @@ public class TrackPlacement {
BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z); BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z);
info.curve = new BezierConnection(Couple.create(targetPos1, targetPos2), info.curve = new BezierConnection(Couple.create(targetPos1, targetPos2),
Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2), Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2),
Couple.create(normal1, normal2), true, girder); Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem()));
} }
// S curve or Straight // S curve or Straight
@ -281,10 +289,10 @@ public class TrackPlacement {
if (skipCurve && !Mth.equal(ascend, 0)) { if (skipCurve && !Mth.equal(ascend, 0)) {
int hDistance = info.end1Extent; int hDistance = info.end1Extent;
if (axis1.y == 0 || !Mth.equal(absAscend + 1, dist / axis1.length())) { if (axis1.y == 0 || !Mth.equal(absAscend + 1, dist / axis1.length())) {
if (axis1.y != 0 && axis1.y == -axis2.y) if (axis1.y != 0 && axis1.y == -axis2.y)
return info.withMessage("ascending_s_curve"); return info.withMessage("ascending_s_curve");
info.end1Extent = 0; info.end1Extent = 0;
double minHDistance = Math.max(absAscend < 4 ? absAscend * 4 : absAscend * 3, 6) / axis1.length(); double minHDistance = Math.max(absAscend < 4 ? absAscend * 4 : absAscend * 3, 6) / axis1.length();
if (hDistance < minHDistance) if (hDistance < minHDistance)
@ -352,7 +360,7 @@ public class TrackPlacement {
info.curve = skipCurve ? null info.curve = skipCurve ? null
: new BezierConnection(Couple.create(targetPos1, targetPos2), : new BezierConnection(Couple.create(targetPos1, targetPos2),
Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2), Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2),
Couple.create(normal1, normal2), true, girder); Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem()));
info.valid = true; info.valid = true;
@ -397,7 +405,7 @@ public class TrackPlacement {
continue; continue;
ItemStack stackInSlot = (offhand ? inv.offhand : inv.items).get(i); ItemStack stackInSlot = (offhand ? inv.offhand : inv.items).get(i);
boolean isTrack = AllBlocks.TRACK.isIn(stackInSlot); boolean isTrack = AllTags.AllBlockTags.TRACKS.matches(stackInSlot) && stackInSlot.is(stack.getItem());
if (!isTrack && (!shouldPave || offhandItem.getItem() != stackInSlot.getItem())) if (!isTrack && (!shouldPave || offhandItem.getItem() != stackInSlot.getItem()))
continue; continue;
if (isTrack ? foundTracks >= tracks : foundPavement >= pavement) if (isTrack ? foundTracks >= tracks : foundPavement >= pavement)
@ -445,10 +453,10 @@ public class TrackPlacement {
BlockItem paveItem = (BlockItem) offhandItem.getItem(); BlockItem paveItem = (BlockItem) offhandItem.getItem();
paveTracks(level, info, paveItem, false); paveTracks(level, info, paveItem, false);
} }
if (info.curve != null && info.curve.getLength() > 29) if (info.curve != null && info.curve.getLength() > 29)
AllAdvancements.LONG_BEND.awardTo(player); AllAdvancements.LONG_BEND.awardTo(player);
return placeTracks(level, info, state1, state2, targetPos1, targetPos2, false); return placeTracks(level, info, state1, state2, targetPos1, targetPos2, false);
} }
@ -474,6 +482,18 @@ public class TrackPlacement {
info.requiredPavement += TrackPaver.paveCurve(level, info.curve, block, simulate, visited); info.requiredPavement += TrackPaver.paveCurve(level, info.curve, block, simulate, visited);
} }
private static BlockState copyProperties(BlockState from, BlockState onto) {
for (Property property : onto.getProperties()) {
if (from.hasProperty(property))
onto = onto.setValue(property, from.getValue(property));
}
return onto;
}
private static BlockState copyProperties(BlockState from, BlockState onto, boolean keepFrom) {
return keepFrom ? from : copyProperties(from, onto);
}
private static PlacementInfo placeTracks(Level level, PlacementInfo info, BlockState state1, BlockState state2, private static PlacementInfo placeTracks(Level level, PlacementInfo info, BlockState state1, BlockState state2,
BlockPos targetPos1, BlockPos targetPos2, boolean simulate) { BlockPos targetPos1, BlockPos targetPos2, boolean simulate) {
info.requiredTracks = 0; info.requiredTracks = 0;
@ -501,7 +521,8 @@ public class TrackPlacement {
Vec3 offset = axis.scale(i); Vec3 offset = axis.scale(i);
BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z); BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z);
BlockState stateAtPos = level.getBlockState(offsetPos); BlockState stateAtPos = level.getBlockState(offsetPos);
BlockState toPlace = state; // copy over all shared properties from the shaped state to the correct track material block
BlockState toPlace = copyProperties(state, info.trackMaterial.getTrackBlock().get().defaultBlockState());
boolean canPlace = stateAtPos.getMaterial() boolean canPlace = stateAtPos.getMaterial()
.isReplaceable(); .isReplaceable();
@ -524,15 +545,16 @@ public class TrackPlacement {
return info; return info;
if (!simulate) { if (!simulate) {
BlockState onto = info.trackMaterial.getTrackBlock().get().defaultBlockState();
BlockState stateAtPos = level.getBlockState(targetPos1); BlockState stateAtPos = level.getBlockState(targetPos1);
level.setBlock(targetPos1, ProperWaterloggedBlock.withWater(level, level.setBlock(targetPos1, ProperWaterloggedBlock.withWater(level,
(stateAtPos.getBlock() == state1.getBlock() ? stateAtPos : state1).setValue(TrackBlock.HAS_TE, true), (AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state1, onto))
targetPos1), 3); .setValue(TrackBlock.HAS_TE, true), targetPos1), 3);
stateAtPos = level.getBlockState(targetPos2); stateAtPos = level.getBlockState(targetPos2);
level.setBlock(targetPos2, ProperWaterloggedBlock.withWater(level, level.setBlock(targetPos2, ProperWaterloggedBlock.withWater(level,
(stateAtPos.getBlock() == state2.getBlock() ? stateAtPos : state2).setValue(TrackBlock.HAS_TE, true), (AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state2, onto))
targetPos2), 3); .setValue(TrackBlock.HAS_TE, true), targetPos2), 3);
} }
BlockEntity te1 = level.getBlockEntity(targetPos1); BlockEntity te1 = level.getBlockEntity(targetPos1);
@ -579,10 +601,10 @@ public class TrackPlacement {
return; return;
InteractionHand hand = InteractionHand.MAIN_HAND; InteractionHand hand = InteractionHand.MAIN_HAND;
if (!AllBlocks.TRACK.isIn(stack)) { if (!AllTags.AllBlockTags.TRACKS.matches(stack)) {
stack = player.getOffhandItem(); stack = player.getOffhandItem();
hand = InteractionHand.OFF_HAND; hand = InteractionHand.OFF_HAND;
if (!AllBlocks.TRACK.isIn(stack)) if (!AllTags.AllBlockTags.TRACKS.matches(stack))
return; return;
} }
@ -621,7 +643,7 @@ public class TrackPlacement {
if (bhr.getDirection() == Direction.UP) { if (bhr.getDirection() == Direction.UP) {
Vec3 lookVec = player.getLookAngle(); Vec3 lookVec = player.getLookAngle();
int lookAngle = (int) (22.5 + AngleHelper.deg(Mth.atan2(lookVec.z, lookVec.x)) % 360) / 8; int lookAngle = (int) (22.5 + AngleHelper.deg(Mth.atan2(lookVec.z, lookVec.x)) % 360) / 8;
if (!pos.equals(hintPos) || lookAngle != hintAngle) { if (!pos.equals(hintPos) || lookAngle != hintAngle) {
hints = Couple.create(ArrayList::new); hints = Couple.create(ArrayList::new);
hintAngle = lookAngle; hintAngle = lookAngle;

View file

@ -3,9 +3,6 @@ package com.simibubi.create.content.logistics.trains.track;
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_BOTTOM; import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_BOTTOM;
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_MIDDLE; import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_MIDDLE;
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_TOP; import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_TOP;
import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_LEFT;
import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_RIGHT;
import static com.simibubi.create.AllBlockPartials.TRACK_TIE;
import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.util.transform.TransformStack; import com.jozufozu.flywheel.util.transform.TransformStack;
@ -15,6 +12,7 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection;
import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles; import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles;
import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles; import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import com.simibubi.create.foundation.render.CachedBufferer; import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
@ -66,7 +64,9 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
SegmentAngles segment = segments[i]; SegmentAngles segment = segments[i];
int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition)); int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition));
CachedBufferer.partial(TRACK_TIE, air) TrackMaterial.TrackModelHolder modelHolder = bc.getMaterial().getModelHolder();
CachedBufferer.partial(modelHolder.tie(), air)
.mulPose(segment.tieTransform.pose()) .mulPose(segment.tieTransform.pose())
.mulNormal(segment.tieTransform.normal()) .mulNormal(segment.tieTransform.normal())
.light(light) .light(light)
@ -74,7 +74,7 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
for (boolean first : Iterate.trueAndFalse) { for (boolean first : Iterate.trueAndFalse) {
Pose transform = segment.railTransforms.get(first); Pose transform = segment.railTransforms.get(first);
CachedBufferer.partial(first ? TRACK_SEGMENT_LEFT : TRACK_SEGMENT_RIGHT, air) CachedBufferer.partial(first ? modelHolder.segment_left() : modelHolder.segment_right(), air)
.mulPose(transform.pose()) .mulPose(transform.pose())
.mulNormal(transform.normal()) .mulNormal(transform.normal())
.light(light) .light(light)

View file

@ -9,6 +9,7 @@ import java.util.Set;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection;
@ -112,6 +113,9 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
} }
public void addConnection(BezierConnection connection) { public void addConnection(BezierConnection connection) {
// don't replace existing connections with different materials
if (connections.containsKey(connection.getKey()) && connection.equalsSansMaterial(connections.get(connection.getKey())))
return;
connections.put(connection.getKey(), connection); connections.put(connection.getKey(), connection);
level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); level.scheduleTick(worldPosition, getBlockState().getBlock(), 1);
notifyUpdate(); notifyUpdate();
@ -287,7 +291,7 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
.getLevel(boundLocation.getFirst()); .getLevel(boundLocation.getFirst());
if (otherLevel == null) if (otherLevel == null)
return; return;
if (AllBlocks.TRACK.has(otherLevel.getBlockState(boundLocation.getSecond()))) if (AllTags.AllBlockTags.TRACKS.matches(otherLevel.getBlockState(boundLocation.getSecond())))
otherLevel.destroyBlock(boundLocation.getSecond(), false); otherLevel.destroyBlock(boundLocation.getSecond(), false);
} }
} }

View file

@ -62,9 +62,11 @@ import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.forgespi.language.IModFileInfo; import net.minecraftforge.forgespi.language.IModFileInfo;
import net.minecraftforge.forgespi.locating.IModFile; import net.minecraftforge.forgespi.locating.IModFile;
import net.minecraftforge.registries.NewRegistryEvent;
@EventBusSubscriber @EventBusSubscriber
public class CommonEvents { public class CommonEvents {
@ -90,7 +92,7 @@ public class CommonEvents {
ToolboxHandler.playerLogin(player); ToolboxHandler.playerLogin(player);
Create.RAILWAYS.playerLogin(player); Create.RAILWAYS.playerLogin(player);
} }
@SubscribeEvent @SubscribeEvent
public static void playerLoggedOut(PlayerLoggedOutEvent event) { public static void playerLoggedOut(PlayerLoggedOutEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
@ -166,7 +168,7 @@ public class CommonEvents {
public static void onEntityEnterSection(EntityEvent.EnteringSection event) { public static void onEntityEnterSection(EntityEvent.EnteringSection event) {
CarriageEntityHandler.onEntityEnterSection(event); CarriageEntityHandler.onEntityEnterSection(event);
} }
@SubscribeEvent @SubscribeEvent
public static void addReloadListeners(AddReloadListenerEvent event) { public static void addReloadListeners(AddReloadListenerEvent event) {
event.addListener(RecipeFinder.LISTENER); event.addListener(RecipeFinder.LISTENER);
@ -248,7 +250,5 @@ public class CommonEvents {
}); });
} }
} }
} }
} }

View file

@ -60,6 +60,7 @@ public class AllCommands {
.then(CameraDistanceCommand.register()) .then(CameraDistanceCommand.register())
.then(CameraAngleCommand.register()) .then(CameraAngleCommand.register())
.then(FlySpeedCommand.register()) .then(FlySpeedCommand.register())
//.then(DebugValueCommand.register())
//.then(KillTPSCommand.register()) //.then(KillTPSCommand.register())
.build(); .build();

View file

@ -0,0 +1,41 @@
package com.simibubi.create.foundation.command;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.simibubi.create.Create;
import net.minecraft.SharedConstants;
import org.apache.commons.lang3.mutable.MutableInt;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.foundation.utility.Components;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.BaseCommandBlock;
import net.minecraft.world.level.block.CommandBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.CommandBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
public class DebugValueCommand {
public static float value = 0;
public static ArgumentBuilder<CommandSourceStack, ?> register() {
return Commands.literal("debugValue")
.requires(cs -> cs.hasPermission(4))
.then(Commands.argument("value", FloatArgumentType.floatArg())
.executes((ctx) -> {
value = FloatArgumentType.getFloat(ctx, "value");
ctx.getSource().sendSuccess(Components.literal("Set value to: "+value), true);
return 1;
}));
}
}

View file

@ -77,6 +77,7 @@ public class CClient extends ConfigBase {
public final ConfigGroup trains = group(1, "trains", Comments.trains); public final ConfigGroup trains = group(1, "trains", Comments.trains);
public final ConfigFloat mountedZoomMultiplier = f(3, 0, "mountedZoomMultiplier", Comments.mountedZoomMultiplier); public final ConfigFloat mountedZoomMultiplier = f(3, 0, "mountedZoomMultiplier", Comments.mountedZoomMultiplier);
public final ConfigBool showTrackGraphOnF3 = b(false, "showTrackGraphOnF3", Comments.showTrackGraphOnF3); public final ConfigBool showTrackGraphOnF3 = b(false, "showTrackGraphOnF3", Comments.showTrackGraphOnF3);
public final ConfigBool showExtendedTrackGraphOnF3 = b(false, "showExtendedTrackGraphOnF3", Comments.showExtendedTrackGraphOnF3);
@Override @Override
public String getName() { public String getName() {
@ -147,6 +148,7 @@ public class CClient extends ConfigBase {
static String trains = "Railway related settings"; static String trains = "Railway related settings";
static String mountedZoomMultiplier = "How far away the Camera should zoom when seated on a train"; static String mountedZoomMultiplier = "How far away the Camera should zoom when seated on a train";
static String showTrackGraphOnF3 = "Display nodes and edges of a Railway Network while f3 debug mode is active"; static String showTrackGraphOnF3 = "Display nodes and edges of a Railway Network while f3 debug mode is active";
static String showExtendedTrackGraphOnF3 = "Additionally display materials of a Rail Network while f3 debug mode is active";
} }
} }

View file

@ -33,7 +33,7 @@ import com.simibubi.create.content.curiosities.deco.SlidingDoorMovementBehaviour
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelItem; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelItem;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyBlock; import com.simibubi.create.content.logistics.trains.track.StandardBogeyBlock;
import com.simibubi.create.foundation.block.BlockStressDefaults; import com.simibubi.create.foundation.block.BlockStressDefaults;
import com.simibubi.create.foundation.block.ItemUseOverrides; import com.simibubi.create.foundation.block.ItemUseOverrides;
@ -80,6 +80,7 @@ public class BuilderTransformers {
.build(); .build();
} }
@SuppressWarnings("deprecation")
public static <B extends StandardBogeyBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> bogey() { public static <B extends StandardBogeyBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> bogey() {
return b -> b.initialProperties(SharedProperties::softMetal) return b -> b.initialProperties(SharedProperties::softMetal)
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) .properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
@ -88,7 +89,7 @@ public class BuilderTransformers {
.blockstate((c, p) -> BlockStateGen.horizontalAxisBlock(c, p, s -> p.models() .blockstate((c, p) -> BlockStateGen.horizontalAxisBlock(c, p, s -> p.models()
.getExistingFile(p.modLoc("block/track/bogey/top")))) .getExistingFile(p.modLoc("block/track/bogey/top"))))
.loot((p, l) -> p.dropOther(l, AllBlocks.RAILWAY_CASING.get())) .loot((p, l) -> p.dropOther(l, AllBlocks.RAILWAY_CASING.get()))
.onRegister(block -> IBogeyBlock.register(RegisteredObjects.getKeyOrThrow(block))); .onRegister(block -> AbstractBogeyBlock.registerStandardBogey(RegisteredObjects.getKeyOrThrow(block)));
} }
public static <B extends TrapDoorBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> trapdoor(boolean orientable) { public static <B extends TrapDoorBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> trapdoor(boolean orientable) {

View file

@ -16,8 +16,10 @@ import com.simibubi.create.CreateClient;
import com.simibubi.create.content.AllSections; import com.simibubi.create.content.AllSections;
import com.simibubi.create.content.contraptions.fluids.VirtualFluid; import com.simibubi.create.content.contraptions.fluids.VirtualFluid;
import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity; import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity;
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.foundation.block.connected.CTModel; import com.simibubi.create.foundation.block.connected.CTModel;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour;
import com.simibubi.create.foundation.utility.CreateRegistry;
import com.simibubi.create.foundation.utility.RegisteredObjects; import com.simibubi.create.foundation.utility.RegisteredObjects;
import com.tterrag.registrate.AbstractRegistrate; import com.tterrag.registrate.AbstractRegistrate;
import com.tterrag.registrate.builders.BlockBuilder; import com.tterrag.registrate.builders.BlockBuilder;

View file

@ -3,6 +3,8 @@ package com.simibubi.create.foundation.ponder.content;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.ponder.PonderRegistrationHelper; import com.simibubi.create.foundation.ponder.PonderRegistrationHelper;
import com.simibubi.create.foundation.ponder.PonderRegistry; import com.simibubi.create.foundation.ponder.PonderRegistry;
@ -20,8 +22,15 @@ import com.simibubi.create.foundation.ponder.content.trains.TrainScenes;
import com.simibubi.create.foundation.ponder.content.trains.TrainSignalScenes; import com.simibubi.create.foundation.ponder.content.trains.TrainSignalScenes;
import com.simibubi.create.foundation.ponder.content.trains.TrainStationScenes; import com.simibubi.create.foundation.ponder.content.trains.TrainStationScenes;
import com.tterrag.registrate.util.entry.BlockEntry;
import com.tterrag.registrate.util.entry.ItemProviderEntry;
import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import java.util.stream.Collectors;
public class PonderIndex { public class PonderIndex {
@ -303,7 +312,12 @@ public class PonderIndex {
.addStoryBoard("rose_quartz_lamp", RedstoneScenes2::roseQuartzLamp); .addStoryBoard("rose_quartz_lamp", RedstoneScenes2::roseQuartzLamp);
// Trains // Trains
HELPER.forComponents(AllBlocks.TRACK) HELPER.forComponents(TrackMaterial.allBlocks().stream()
.map((trackSupplier) -> new BlockEntry<TrackBlock>(
// note: these blocks probably WON'T be in the Create Registrate, but a simple code trace reveals the Entry's registrate isn't used
Create.REGISTRATE,
RegistryObject.create(trackSupplier.get().getRegistryName(), ForgeRegistries.BLOCKS)))
.toList())
.addStoryBoard("train_track/placement", TrackScenes::placement) .addStoryBoard("train_track/placement", TrackScenes::placement)
.addStoryBoard("train_track/portal", TrackScenes::portal) .addStoryBoard("train_track/portal", TrackScenes::portal)
.addStoryBoard("train_track/chunks", TrackScenes::chunks); .addStoryBoard("train_track/chunks", TrackScenes::chunks);

View file

@ -7,7 +7,7 @@ import java.util.function.Function;
import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity; import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.IBearingTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.IBearingTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.foundation.ponder.PonderScene; import com.simibubi.create.foundation.ponder.PonderScene;
import com.simibubi.create.foundation.ponder.PonderWorld; import com.simibubi.create.foundation.ponder.PonderWorld;
@ -34,7 +34,7 @@ public class AnimateTileEntityInstruction extends TickingInstruction {
public static AnimateTileEntityInstruction bogey(BlockPos location, float totalDelta, int ticks) { public static AnimateTileEntityInstruction bogey(BlockPos location, float totalDelta, int ticks) {
float movedPerTick = totalDelta / ticks; float movedPerTick = totalDelta / ticks;
return new AnimateTileEntityInstruction(location, totalDelta, ticks, return new AnimateTileEntityInstruction(location, totalDelta, ticks,
(w, f) -> castIfPresent(w, location, StandardBogeyTileEntity.class) (w, f) -> castIfPresent(w, location, AbstractBogeyTileEntity.class)
.ifPresent(bte -> bte.animate(f.equals(totalDelta) ? 0 : movedPerTick)), .ifPresent(bte -> bte.animate(f.equals(totalDelta) ? 0 : movedPerTick)),
(w) -> 0f); (w) -> 0f);
} }

View file

@ -45,4 +45,13 @@ public class Iterate {
public static List<BlockPos> hereBelowAndAbove(BlockPos pos) { public static List<BlockPos> hereBelowAndAbove(BlockPos pos) {
return Arrays.asList(pos, pos.below(), pos.above()); return Arrays.asList(pos, pos.below(), pos.above());
} }
public static <T> T cycleValue(List<T> list, T current) {
int currentIndex = list.indexOf(current);
if (currentIndex == -1) {
throw new IllegalArgumentException("Current value not found in list");
}
int nextIndex = (currentIndex + 1) % list.size();
return list.get(nextIndex);
}
} }

View file

@ -13,6 +13,7 @@ import net.minecraft.nbt.FloatTag;
import net.minecraft.nbt.IntTag; import net.minecraft.nbt.IntTag;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
@ -108,4 +109,12 @@ public class NBTHelper {
return new CompoundTag(); return new CompoundTag();
} }
public static void writeResourceLocation(CompoundTag nbt, String key, ResourceLocation location) {
nbt.putString(key, location.toString());
}
public static ResourceLocation readResourceLocation(CompoundTag nbt, String key) {
return new ResourceLocation(nbt.getString(key));
}
} }

View file

@ -0,0 +1,51 @@
package com.simibubi.create.foundation.utility.outliner;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.render.RenderTypes;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import java.util.*;
public class ItemOutline extends Outline {
protected Vec3 pos;
protected ItemStack stack;
public ItemOutline(Vec3 pos, ItemStack stack) {
this.pos = pos;
this.stack = stack;
}
@Override
public void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt) {
Minecraft mc = Minecraft.getInstance();
ms.pushPose();
TransformStack.cast(ms)
.translate(pos.x - camera.x, pos.y - camera.y, pos.z - camera.z)
.scale(params.alpha);
mc.getItemRenderer().render(stack, ItemTransforms.TransformType.FIXED, false, ms,
buffer, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY,
mc.getItemRenderer().getModel(stack, null, null, 0));
ms.popPose();
}
}

View file

@ -14,6 +14,7 @@ import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
@ -81,6 +82,13 @@ public class Outliner {
// //
public OutlineParams showItem(Object slot, Vec3 pos, ItemStack stack) {
ItemOutline outline = new ItemOutline(pos, stack);
OutlineEntry entry = new OutlineEntry(outline);
outlines.put(slot, entry);
return entry.getOutline().getParams();
}
public void keep(Object slot) { public void keep(Object slot) {
if (outlines.containsKey(slot)) if (outlines.containsKey(slot))
outlines.get(slot).ticksTillRemoval = 1; outlines.get(slot).ticksTillRemoval = 1;

View file

@ -920,8 +920,14 @@
"create.contraption.minecart_contraption_too_big": "This Cart Contraption seems too big to pick up", "create.contraption.minecart_contraption_too_big": "This Cart Contraption seems too big to pick up",
"create.contraption.minecart_contraption_illegal_pickup": "A mystical force is binding this Cart Contraption to the world", "create.contraption.minecart_contraption_illegal_pickup": "A mystical force is binding this Cart Contraption to the world",
"enchantment.create.capacity.desc": "Increases Backtank air capacity.", "enchantment.create.capacity.desc": "Increases Backtank air capacity.",
"enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused." "enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.",
"create.bogey.style.updated_style": "Updated style",
"create.bogey.style.updated_style_and_size": "Updated style and size",
"create.bogey.style.no_other_sizes": "No other sizes",
"create.bogey.style.invalid": "Unnamed style",
"create.bogey.style.standard": "Standard"
} }