From e5c6ca157c4acd11ad4f4a516fc456e8a54b3511 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue, 9 May 2023 18:23:47 +0200 Subject: [PATCH] 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 ecc645eba7bfd5f86b9bfb16ee1236a5d6432d3d Author: Rabbitminers 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 205e47352ec46f8e300167db69023c7938a52b58 Author: techno-sam Date: Mon May 8 21:02:19 2023 -0700 Fix up ItemOutline commit 6cf204f6afd12671060d198d5a09efe9cd04c7b5 Merge: fe049bc77 2e3c906ce Author: techno-sam 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 fe049bc771cc3a4dd91f5c91f098aa7448af6c8d Author: techno-sam Date: Mon May 8 20:26:16 2023 -0700 Revert "Revert "Rewrite outline buffering"" This reverts commit 726bfaf0 commit 435b4c1c16153e30740d6878cf1f676b7a442c19 Author: techno-sam Date: Mon May 8 20:20:23 2023 -0700 Clean up last bits of upside down rendering commit 662da6bab1f6ad96a4fa05c9ff8538080ac69ac2 Merge: 122fe77af d83285e8a Author: techno-sam 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 122fe77afa2df18dde7afe0bc6aee536f33b18bd Author: techno-sam Date: Mon May 8 20:15:46 2023 -0700 Fix up upside down rendering commit d83285e8a4da5fcb6900c032e6bd8cd59f81bde8 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 cdb0ad210b7c984b9fcfbecae8a2a0ebf052eb9d Author: Rabbitminers Date: Sun May 7 10:15:47 2023 +0100 Fixed merge artifact commit 457d5f33ed05075dbd0ffc38c17d3135b494dc26 Merge: 4e4e227a3 00e953a58 Author: Rabbitminers Date: Sun May 7 10:14:07 2023 +0100 Merge remote-tracking branch 'origin/1.18/api' into 1.18/api commit 00e953a585bd8e146b6304a19cebd174404ab1c3 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 a7a25896c1a5a0a353400ed329a46a461347553e 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 4e4e227a351cb7f70aa4476bebfad1c0e963b561 Author: Rabbitminers Date: Sun May 7 10:10:30 2023 +0100 Cleanup to cycle groups commit aa94fc97d154dcdcaaaa5b4d5e8311af9470d38a Author: Rabbitminers Date: Sun May 7 09:50:50 2023 +0100 Removed unused import of Railways commit 7622128bec17931ea4029792d62c645d0f354e5f 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 1e4d5504ee4fe32d655e08acbeb6c492b5e8bb0b Author: techno-sam Date: Sat May 6 18:03:39 2023 -0700 Don't revert non-buggy changes commit b306cf212471f2842311af071dc6b595cbf79216 Author: techno-sam Date: Sat May 6 18:00:59 2023 -0700 Take materials into consideration when trains pathfind commit fca02ae4bfade6f839533c11785cc3e56332f463 Author: techno-sam Date: Sat May 6 10:25:51 2023 -0700 Add materials to track graph commit 726bfaf0b5226a657b45ce4bd1aa365d891a27a4 Author: techno-sam Date: Fri May 5 21:16:49 2023 -0700 Revert "Rewrite outline buffering" This reverts commit d4106d545b0381c3bec304e727a136ea105a8468. commit 171897bed25ed8f7ad3999c8527bb649bb932c81 Author: techno-sam Date: Fri May 5 20:55:25 2023 -0700 Fix up style cycling commit cbd0cf20da482851f98f5312cbc40770a6c14f16 Author: techno-sam Date: Fri May 5 07:32:06 2023 -0700 clean up nether portal carriage handling commit d556f0887632664126a2e10cbb1c8fc6d37e2582 Author: techno-sam Date: Fri May 5 07:06:02 2023 -0700 upside down bogeys work in nether portals fixed coupling anchor offsets commit da26c0ccbf26b892013f6e365556eea6952009f2 Author: techno-sam Date: Thu May 4 09:32:53 2023 -0700 working on upside down bogeys in nether portals commit 81eeadb8532599d482f2259e58cedeaa602e8628 Author: Rabbitminers Date: Mon May 1 16:15:28 2023 +0100 Small cleanup commit c7e9df973cf3d0dab15992d06e6a51985d305ba8 Author: Rabbitminers Date: Mon May 1 16:13:51 2023 +0100 Fixed issue raised in #1 commit 2f285b6eb7341879899895b1c5bbadd0137abb83 Author: techno-sam Date: Mon May 1 08:13:27 2023 -0700 add data gen commit 206de013111a879de133f62846e4f10d7228ea0a 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 6564f4fa730f71920552fd2ad6f2c8255df69995 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 e5d759582279b3a761c7011174ec77119f4f4f93 Author: Rabbitminers Date: Mon May 1 10:09:03 2023 +0100 Connected Custom Bogey Particle Types To CarriageParticles commit e91753a33cde6dbe0caaface45a7f377d75acbed Author: techno-sam Date: Sun Apr 30 19:51:26 2023 -0700 Fix up some problems commit 9815f1490f9d540986f85f49f297e2f014c312c4 Author: Rabbitminers Date: Sun Apr 30 21:12:43 2023 +0100 Implemented default data when shifting styles commit da30e78815afd7906ea82a9fba293f202c036fa8 Author: Rabbitminers Date: Sun Apr 30 21:12:14 2023 +0100 Added Particles To Bogey Style (And Respective Builder) commit 08c000b8ba302a1c14f7479e70445e2c6d360bc3 Author: Rabbitminers Date: Sun Apr 30 21:01:19 2023 +0100 Added Backup Rendering If A Size Is Not Present commit 2b76e8d7b3b8d88355868ea31d4b6e3df11a7169 Author: Rabbitminers Date: Sun Apr 30 21:00:40 2023 +0100 Added Common Renderer To Remove Function commit 411ec36f573a570284b2bda566d8a006550983e8 Author: Rabbitminers Date: Sun Apr 30 20:59:50 2023 +0100 Added Display Name To Standard Bogey Style commit 112306d5d49db10176d091f1f2ece893afb274dd Author: Rabbitminers Date: Sun Apr 30 20:59:30 2023 +0100 Displayed new style name when changing betweeen them commit 5634670b2750a2df5dfee6de3f93bc895391300d Author: Rabbitminers Date: Sun Apr 30 20:06:00 2023 +0100 General Cleanup commit 0f7a8b7b24ef25c4266fc88f82995b609087904e Author: Rabbitminers Date: Sun Apr 30 20:05:50 2023 +0100 Implemented Changes To Remaining Classes commit 8aedc00f963413ac0a02335bc9f914d45a82b4de Author: Rabbitminers Date: Sun Apr 30 20:02:06 2023 +0100 Removed Bogey Style Handling From Registrate commit edf8079abf9750dc9f3ccf1aedf58fef80428385 Author: Rabbitminers Date: Sun Apr 30 20:01:40 2023 +0100 Removed Unused Registry Handling commit 6a185c4e727ecf55183cb885b109c0f5c5319854 Author: Rabbitminers Date: Sun Apr 30 20:01:16 2023 +0100 Refactored Bogey Sizes commit e10d07ddc3b70cfa6f4a210aa9a9e6bcc6200b7f Author: Rabbitminers Date: Sun Apr 30 20:01:00 2023 +0100 Overhauled Bogey Style commit 74d98a2ad538e2b9d35fdfd2270a14597d29f957 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 e629d02f505c7de2d786a126fe49168351f17124 Author: techno-sam Date: Sun Apr 9 07:18:22 2023 -0700 Track API Clean up code a bit commit d9ce6ce995128e64d079145b96273235c4fec783 Author: techno-sam Date: Sun Apr 9 07:14:46 2023 -0700 Track API? Fix placement commit 7fbf08ba54ce3397045a8acdd6b7be813009ee7b Author: techno-sam Date: Sat Apr 8 11:11:24 2023 -0700 Track API? Fix up some placement issues commit 35644f143426bc2cae1a63c4f09d7145a4e18983 Author: techno-sam Date: Sat Apr 8 08:11:13 2023 -0700 Track API maybe? Datagen Seems to be working commit f7c56b867a6afe52fa742f4d4c310db9788cc2ef Author: techno-sam Date: Thu Apr 6 21:24:31 2023 -0700 Track API maybe? Fix build - broken generic Not yet tested, but it is progress commit 2a59fd7e8ab91a6004abe4b92152a2a936a22c1b Author: techno-sam Date: Thu Apr 6 21:13:54 2023 -0700 Track API maybe? Not yet tested, but it is progress commit 5ba30d6a85dd2cfa49434cb55a25b258b02a9665 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 d52065808c5d250e6aec35878a5349be563c1d24 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 53240bd42f08d839b233a3b75cb59aabb4648fb9 Author: Rabbitminers Date: Mon Apr 3 21:42:29 2023 +0100 Corrected Bogey InteractionResult To Pass commit 69326e361ab7d982a577f1e864c772967ad9c134 Author: Rabbitminers Date: Mon Apr 3 21:30:28 2023 +0100 Fixed Default Values When Used Styles Are Removed commit 4f176979de161c35d6c7b07744bf0b982490f49f Author: Rabbitminers Date: Mon Apr 3 19:33:17 2023 +0100 Fixed Carriage Sounds (Again) commit 1e80af3303e5bf9f9179857944cc233b4be7ebaf Author: Rabbitminers Date: Mon Apr 3 19:27:58 2023 +0100 Refactored Bogey Sizes To Seperate Class commit 129be61fee13e15e17c2e2a4ee0b08c9bc004846 Author: Rabbitminers Date: Mon Apr 3 17:20:17 2023 +0100 Fixed Bogey Sound Loading commit 2543185a55a60197494850582ca45d729e463f40 Author: Rabbitminers Date: Mon Apr 3 09:45:23 2023 +0100 Added Bogey Sound Customisation commit 1ad5ae95143f5240fcb83448a99a3924e6d96ce8 Author: Rabbitminers Date: Mon Apr 3 00:44:53 2023 +0100 Added Size Transforms If Size Is Not Available For New Style commit 96566b161441928f2b419340796a27631e1aeb91 Author: Rabbitminers Date: Sun Apr 2 23:02:02 2023 +0100 Moved Bogey Style Inside Of Bogey Data And Implemented Bogey Data Communication commit eedd98473807f1261c7d5edaf0a222c081b57e69 Author: Rabbitminers Date: Sun Apr 2 16:53:55 2023 +0100 Fixed Large Bogey Size commit 68ca0974c6867e61980990a345634963079faf10 Author: Rabbitminers Date: Sun Apr 2 16:47:58 2023 +0100 Implemented Style Cycling & Default Values commit a55ba4267a5fd01ec77e9d826a01f0157c3a1271 Author: Rabbitminers Date: Sun Apr 2 16:46:15 2023 +0100 Implemented renderer instance creator commit 43523302c22d5da374d71c69499269eb8c98dadf Author: Rabbitminers Date: Sun Apr 2 16:45:33 2023 +0100 Removed Unused Standard Bogey Instance commit 773e084422d5cba7e0c599c4e9e9199252e843a3 Merge: 0c0b5a1ed d1e1f7ec5 Author: Rabbitminers 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 0c0b5a1ed65c5f425265b340772b1177a309c46d Author: Rabbitminers Date: Sat Apr 1 18:39:58 2023 +0100 Linked Style Registry To Bogey Blocks commit 71f839ee51c4d609a19fe57632fb2e8fb0d2e5b7 Author: Rabbitminers Date: Sat Apr 1 18:39:03 2023 +0100 Replaced size boolean with direct use of size enum commit 50ff0817045029c721a0a5e38956b3ecd228e52f Author: Rabbitminers Date: Thu Mar 30 18:47:13 2023 +0100 Added Resource Location To NBT helper methods commit d1e1f7ec5abeb825a3170a8f6972ffae43d58381 Author: Rabbitminers Date: Thu Mar 30 18:47:13 2023 +0100 Re-worked BogeyStyles commit da593fccb1cb95232290289775affd097153e30d Author: Rabbitminers Date: Thu Mar 30 18:46:02 2023 +0100 Refactored IBogeyBlock to AbstractBogeyBlock and extracted relevant StandardBogeyBlock implementations commit 17432c911342b1d4937a8d2d22d50a58296639e6 Author: Rabbitminers Date: Sat Mar 25 10:20:50 2023 +0000 Fixed Incorrect Registry Loading commit c7d899369a4ad1a9962ed18c2ab02f58c985f5ae Author: Rabbitminers Date: Fri Mar 24 23:44:03 2023 +0000 Registered Registers commit 6d862290d71b24b1d841444fa21dcb44ecc0d6c7 Author: Rabbitminers Date: Fri Mar 24 23:43:23 2023 +0000 Added BogeyStyleBuilder To Registrate commit 3dfb9e3b3b4b7cec3833b65838ce9523b0cf7666 Author: Rabbitminers Date: Fri Mar 24 23:43:08 2023 +0000 Implemented AllBogeyStyles commit c9e71b462d00e138778f3064bfcc3549a6f28f22 Author: Rabbitminers Date: Fri Mar 24 23:42:56 2023 +0000 Created BogeyStyleBuilder commit a90977d6429657ade13c889d90ec8cd733f176e9 Author: Rabbitminers Date: Fri Mar 24 23:42:25 2023 +0000 Created AllRegistries and BogeyStyle Registry commit 154d455f3fbdef3000ad3e35e88b0909b66c69f8 Author: Rabbitminers Date: Fri Mar 24 23:41:56 2023 +0000 Added BogeyStyle Wrapper commit dfb7640bfc9850604c4ce05ff56338a4e2bbe2fa Author: Rabbitminers Date: Thu Mar 23 18:50:41 2023 +0000 Removed left over logging statement commit 9920536cc319897a89dc1fc974c67cd0975fbcfd Author: Rabbitminers Date: Thu Mar 23 18:50:18 2023 +0000 Implemented Secondary Shaft To Large Renderer commit 6cd40cc6f982226f2bbb9e04e3b8241f9cc36cb5 Author: Rabbitminers Date: Thu Mar 23 18:49:56 2023 +0000 Prevented Overwrite When Using Two BlockStates Of The Same Type With Different Properties commit 06fb901144de8d8df5b907e6261c76a018468f7d Author: Rabbitminers Date: Thu Mar 23 18:39:11 2023 +0000 Implemented Common Rendering For StandardBogeyRenderer commit 435b0f826663284f6544c034217516e36a0687d8 Author: Rabbitminers Date: Thu Mar 23 18:38:40 2023 +0000 Added Common Renderer commit 96a0623dab84d7062a0871ddacabf4342e568867 Author: Rabbitminers Date: Thu Mar 23 18:38:29 2023 +0000 Implemented BlockState Models For Rendering commit 469d9d592b9aa925b26b1206a4ad03d73d422a92 Author: Rabbitminers Date: Thu Mar 23 17:42:28 2023 +0000 Added Standard Bogey Instance (Might be redundant) commit 2661d260d8c21e57df751b17812d89919713120f Author: Rabbitminers Date: Thu Mar 23 17:42:06 2023 +0000 Refactored Changes To Existing Methods commit 9ded16fbabb38e3415cc7b5452cbaea1bef98f61 Author: Rabbitminers Date: Thu Mar 23 17:41:15 2023 +0000 Integrated BogeyRenderer To BogeyInstance (Also Corrected Rendering In Contraption) commit 4a82fcbca1002267fc70998e7ac9c22cd92de52e Author: Rabbitminers Date: Thu Mar 23 17:40:13 2023 +0000 Implemented Changes To StandardBogeyBlock commit 7238fb93f3d0fed43b091f44fd30814e505c544c Author: Rabbitminers Date: Thu Mar 23 17:39:51 2023 +0000 Added Renderer To IBogeyBlock commit ded4c1f613cb33ae29b6bf631eb49abd2ec037f4 Merge: 91727cc84 3c02fe6ec Author: Rabbitminers Date: Wed Mar 22 17:03:37 2023 +0000 Merge remote-tracking branch 'origin/mc1.18/dev' into mc1.18/dev commit 91727cc84a12b2fd27b1ce6e0d67bd182e34880b Author: Rabbitminers Date: Wed Mar 22 17:03:28 2023 +0000 Implemented Model Data Initializer to StandardBogeyRenderer commit 6d98a1f46942d319729c2d61451da462f4188167 Author: Rabbitminers Date: Wed Mar 22 17:03:00 2023 +0000 Added Contraption Model Instance Initializer commit 3c02fe6ecc0c20f1c8ba6bd2ffd2334c2d9d9d73 Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Tue Mar 21 22:45:34 2023 +0000 Added missing render type check commit 6672c49649026e6a6f9a71d9a0bc9411016bcfce Author: Rabbitminers Date: Tue Mar 21 22:37:36 2023 +0000 Re-created standard bogey with test api commit a8a9491fa07777218c7de3fe780ae17e05d5ac03 Author: Rabbitminers Date: Tue Mar 21 22:34:54 2023 +0000 Implemented Proof Of Concept Generic Bogey Renderer commit e4e5ac1c40cadb708429018dc17439eca87ee74e Author: SpottyTheTurtle <69260662+SpottyTheTurtle@users.noreply.github.com> Date: Sat Mar 11 21:34:59 2023 +0000 init --- .gitignore | 3 +- build.gradle | 4 + src/generated/resources/.cache/cache | 4 +- .../resources/assets/create/lang/en_us.json | 6 + .../create/tags/blocks/girdable_tracks.json | 6 + .../data/create/tags/blocks/tracks.json | 6 + .../java/com/simibubi/create/AllBlocks.java | 15 +- .../com/simibubi/create/AllBogeyStyles.java | 122 ++++++ .../java/com/simibubi/create/AllTags.java | 6 + .../com/simibubi/create/AllTileEntities.java | 13 +- src/main/java/com/simibubi/create/Create.java | 4 + .../actors/DrillMovementBehaviour.java | 4 +- .../press/MechanicalPressTileEntity.java | 4 +- .../BlockMovementChecks.java | 4 +- .../structureMovement/Contraption.java | 6 +- .../curiosities/girder/GirderBlock.java | 3 +- .../tools/BlueprintOverlayRenderer.java | 3 +- .../logistics/trains/AbstractBogeyBlock.java | 361 ++++++++++++++++++ .../logistics/trains/BezierConnection.java | 44 ++- .../logistics/trains/BogeyRenderer.java | 309 +++++++++++++++ .../content/logistics/trains/BogeySizes.java | 70 ++++ .../trains/BogeyTileEntityRenderer.java | 12 +- .../trains/GlobalRailwayManager.java | 8 +- .../content/logistics/trains/IBogeyBlock.java | 91 ----- .../content/logistics/trains/ITrackBlock.java | 29 +- .../trains/StandardBogeyRenderer.java | 137 +++++++ .../content/logistics/trains/TrackEdge.java | 12 +- .../content/logistics/trains/TrackGraph.java | 7 +- .../logistics/trains/TrackGraphSync.java | 6 +- .../trains/TrackGraphSyncPacket.java | 15 +- .../trains/TrackGraphVisualizer.java | 25 +- .../logistics/trains/TrackMaterial.java | 144 +++++++ .../trains/TrackMaterialFactory.java | 133 +++++++ .../logistics/trains/TrackNodeLocation.java | 30 +- .../logistics/trains/TrackPropagator.java | 4 +- .../trains/entity/BackupBogeyRenderer.java | 22 ++ .../trains/entity/BogeyInstance.java | 233 ++--------- .../logistics/trains/entity/BogeyStyle.java | 114 ++++++ .../logistics/trains/entity/Carriage.java | 34 +- .../trains/entity/CarriageBogey.java | 83 +++- .../trains/entity/CarriageContraption.java | 12 +- .../CarriageContraptionEntityRenderer.java | 12 +- .../entity/CarriageContraptionInstance.java | 10 +- .../entity/CarriageCouplingRenderer.java | 2 +- .../trains/entity/CarriageParticles.java | 3 +- .../trains/entity/CarriageSounds.java | 21 +- .../logistics/trains/entity/Navigation.java | 23 +- .../logistics/trains/entity/Train.java | 37 +- .../logistics/trains/entity/TrainPacket.java | 15 +- .../trains/entity/TrainRelocator.java | 11 +- .../trains/entity/TravellingPoint.java | 25 +- .../edgePoint/station/StationTileEntity.java | 89 +++-- .../trains/track/AbstractBogeyTileEntity.java | 119 ++++++ .../trains/track/CurvedTrackInteraction.java | 4 +- .../track/PlaceExtendedCurvePacket.java | 6 +- .../trains/track/StandardBogeyBlock.java | 198 +--------- .../trains/track/StandardBogeyTileEntity.java | 31 +- .../logistics/trains/track/TrackBlock.java | 54 ++- .../trains/track/TrackBlockItem.java | 5 +- .../trains/track/TrackBlockOutline.java | 6 +- .../logistics/trains/track/TrackInstance.java | 11 +- .../trains/track/TrackPlacement.java | 56 ++- .../logistics/trains/track/TrackRenderer.java | 10 +- .../trains/track/TrackTileEntity.java | 6 +- .../simibubi/create/events/CommonEvents.java | 8 +- .../foundation/command/AllCommands.java | 1 + .../foundation/command/DebugValueCommand.java | 41 ++ .../create/foundation/config/CClient.java | 2 + .../foundation/data/BuilderTransformers.java | 5 +- .../foundation/data/CreateRegistrate.java | 2 + .../ponder/content/PonderIndex.java | 16 +- .../AnimateTileEntityInstruction.java | 4 +- .../create/foundation/utility/Iterate.java | 9 + .../create/foundation/utility/NBTHelper.java | 9 + .../utility/outliner/ItemOutline.java | 51 +++ .../foundation/utility/outliner/Outliner.java | 8 + .../assets/create/lang/default/interface.json | 10 +- 77 files changed, 2357 insertions(+), 711 deletions(-) create mode 100644 src/generated/resources/data/create/tags/blocks/girdable_tracks.json create mode 100644 src/generated/resources/data/create/tags/blocks/tracks.json create mode 100644 src/main/java/com/simibubi/create/AllBogeyStyles.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/BogeyRenderer.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java delete mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/entity/BackupBogeyRenderer.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyTileEntity.java create mode 100644 src/main/java/com/simibubi/create/foundation/command/DebugValueCommand.java create mode 100644 src/main/java/com/simibubi/create/foundation/utility/outliner/ItemOutline.java diff --git a/.gitignore b/.gitignore index 4afb35865..b9a3321f8 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ local.properties # PDT-specific .buildpath -.DS_Store \ No newline at end of file +.DS_Store +/libs/ diff --git a/build.gradle b/build.gradle index d8e3a2d87..47e73e743 100644 --- a/build.gradle +++ b/build.gradle @@ -135,6 +135,9 @@ repositories { includeGroup "maven.modrinth" } } + flatDir { + dirs 'libs' + } } dependencies { @@ -169,6 +172,7 @@ dependencies { // 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("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 // Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index d50c09db9..9ee732055 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -559,7 +559,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.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 b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.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 d99d5c67bdffff60789a19bd51a5c5267c75e0a4 data/create/tags/blocks/casing.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 6e5d3b2123fbb00e7f439c091623619502551bca data/create/tags/blocks/non_movable.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 6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json d063e12c9ef75f39518c6d129ea35d833464d547 data/create/tags/blocks/toolboxes.json +ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/tracks.json 9460e92c8e483446318b849abe7e6f52dcd4a269 data/create/tags/blocks/tree_attachments.json 50936b211d94167a35ec78c89954082a336b6269 data/create/tags/blocks/valve_handles.json eac71740fb12bdb38b5dfaa2268613d7ba82b809 data/create/tags/blocks/windmill_sails.json diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 2603c07fc..dcee7c629 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1754,6 +1754,12 @@ "enchantment.create.capacity.desc": "Increases Backtank air capacity.", "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 [------------------------<-", diff --git a/src/generated/resources/data/create/tags/blocks/girdable_tracks.json b/src/generated/resources/data/create/tags/blocks/girdable_tracks.json new file mode 100644 index 000000000..ef33e72ef --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/girdable_tracks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:track" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/tracks.json b/src/generated/resources/data/create/tags/blocks/tracks.json new file mode 100644 index 000000000..ef33e72ef --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/tracks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:track" + ] +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 255f0037e..ee2e4fd13 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -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.ItemVaultItem; 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.edgePoint.EdgePointType; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem; @@ -667,7 +670,7 @@ public class AllBlocks { .onRegister(movementBehaviour(new BlazeBurnerMovementBehaviour())) .onRegister(interactionBehaviour(new BlazeBurnerInteractionBehaviour())) .item(BlazeBurnerBlockItem::withBlaze) - .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze")) + .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze")) .build() .register(); @@ -926,7 +929,7 @@ public class AllBlocks { .onRegister(assignDataBehaviour(new BoilerDisplaySource(), "boiler_status")) .addLayer(() -> RenderType::cutoutMipped) .item(FluidTankItem::new) - .model(AssetLookup.customBlockItemModel("_", "block_single_window")) + .model(AssetLookup.customBlockItemModel("_", "block_single_window")) .build() .register(); @@ -1500,7 +1503,7 @@ public class AllBlocks { .transform(customItemModel()) .register(); - public static final BlockEntry TRACK = REGISTRATE.block("track", TrackBlock::new) + public static final BlockEntry TRACK = REGISTRATE.block("track", TrackMaterial.ANDESITE::createBlock) .initialProperties(Material.STONE) .properties(p -> p.color(MaterialColor.METAL) .strength(0.8F) @@ -1510,6 +1513,8 @@ public class AllBlocks { .transform(pickaxeOnly()) .blockstate(new TrackBlockStateGenerator()::generate) .tag(AllBlockTags.RELOCATION_NOT_SUPPORTED.tag) + .tag(AllBlockTags.TRACKS.tag) + .tag(AllBlockTags.GIRDABLE_TRACKS.tag) .lang("Train Track") .item(TrackBlockItem::new) .model((c, p) -> p.generated(c, Create.asResource("item/" + c.getName()))) @@ -1578,13 +1583,13 @@ public class AllBlocks { .register(); public static final BlockEntry 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)) .transform(BuilderTransformers.bogey()) .register(); public static final BlockEntry 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)) .transform(BuilderTransformers.bogey()) .register(); diff --git a/src/main/java/com/simibubi/create/AllBogeyStyles.java b/src/main/java/com/simibubi/create/AllBogeyStyles.java new file mode 100644 index 000000000..dde09ec26 --- /dev/null +++ b/src/main/java/com/simibubi/create/AllBogeyStyles.java @@ -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 BOGEY_STYLES = new HashMap<>(); + public static final Map> CYCLE_GROUPS = new HashMap<>(); + private static final Map EMPTY_GROUP = ImmutableMap.of(); + + public static Map 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 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> 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 renderer, + BlockEntry> blockEntry) { + this.size(size, renderer, blockEntry.getId()); + return this; + } + + public BogeyStyleBuilder size(BogeySizes.BogeySize size, Supplier 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 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; + } + } +} diff --git a/src/main/java/com/simibubi/create/AllTags.java b/src/main/java/com/simibubi/create/AllTags.java index 725836177..027ca062d 100644 --- a/src/main/java/com/simibubi/create/AllTags.java +++ b/src/main/java/com/simibubi/create/AllTags.java @@ -107,6 +107,8 @@ public class AllTags { SAFE_NBT, SEATS, TOOLBOXES, + TRACKS, + GIRDABLE_TRACKS, TREE_ATTACHMENTS, VALVE_HANDLES, WINDMILL_SAILS, @@ -155,6 +157,10 @@ public class AllTags { .is(tag); } + public boolean matches(ItemStack stack) { + return stack != null && stack.getItem() instanceof BlockItem blockItem && matches(blockItem.getBlock()); + } + public boolean matches(BlockState state) { return state.is(tag); } diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 6f74119bb..a6f0f7456 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -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.LecternControllerTileEntity; 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.FlapDisplayTileEntity; 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.StationTileEntity; 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.TrackBlock; 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.TrackTileEntity; @@ -202,6 +205,8 @@ import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.tterrag.registrate.util.entry.BlockEntityEntry; +import com.tterrag.registrate.util.nullness.NonNullSupplier; + public class AllTileEntities { // Schematics @@ -656,7 +661,7 @@ public class AllTileEntities { .validBlocks(AllBlocks.ANALOG_LEVER) .renderer(() -> AnalogLeverRenderer::new) .register(); - + public static final BlockEntityEntry PLACARD = REGISTRATE .tileEntity("placard", PlacardTileEntity::new) .validBlocks(AllBlocks.PLACARD) @@ -781,9 +786,9 @@ public class AllTileEntities { .tileEntity("track", TrackTileEntity::new) .instance(() -> TrackInstance::new) .renderer(() -> TrackRenderer::new) - .validBlocks(AllBlocks.TRACK) + .validBlocks((NonNullSupplier[]) TrackMaterial.allBlocks().toArray(new NonNullSupplier[0])) .register(); - + public static final BlockEntityEntry FAKE_TRACK = REGISTRATE .tileEntity("fake_track", FakeTrackTileEntity::new) .validBlocks(AllBlocks.FAKE_TRACK) @@ -800,7 +805,7 @@ public class AllTileEntities { .renderer(() -> StationRenderer::new) .validBlocks(AllBlocks.TRACK_STATION) .register(); - + public static final BlockEntityEntry SLIDING_DOOR = REGISTRATE .tileEntity("sliding_door", SlidingDoorTileEntity::new) .renderer(() -> SlidingDoorRenderer::new) diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 420c74a30..df9200de7 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -2,6 +2,8 @@ package com.simibubi.create; import java.util.Random; +import com.simibubi.create.content.logistics.trains.BogeySizes; + import org.slf4j.Logger; import com.google.gson.Gson; @@ -121,6 +123,8 @@ public class Create { AllFeatures.register(modEventBus); AllPlacementModifiers.register(modEventBus); BuiltinRegistration.register(modEventBus); + BogeySizes.init(); + AllBogeyStyles.register(); AllConfigs.register(modLoadingContext); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java index 89ebb9582..d0a7a7cb6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java @@ -4,7 +4,7 @@ import javax.annotation.Nullable; import com.jozufozu.flywheel.api.MaterialManager; 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.render.ActorInstance; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; @@ -61,7 +61,7 @@ public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour { @Override public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) { return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos) - .isEmpty() && !AllBlocks.TRACK.has(state); + .isEmpty() && !AllTags.AllBlockTags.TRACKS.matches(state); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java index 0fb8b8b73..6c70c56b0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java @@ -3,8 +3,8 @@ package com.simibubi.create.content.contraptions.components.press; import java.util.List; import java.util.Optional; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.AllTags; import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCraftingRecipe; 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) { award(AllAdvancements.PRESS); - if (AllBlocks.TRACK.isIn(result)) + if (AllTags.AllBlockTags.TRACKS.matches(result)) tracksCreated += result.getCount(); if (tracksCreated >= 1000) { award(AllAdvancements.TRACK_CRAFTING); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java index ce06099e4..72cc6524a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java @@ -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.logistics.block.redstone.RedstoneLinkBlock; 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.management.edgePoint.station.StationBlock; import com.simibubi.create.foundation.config.ContraptionMovementSetting; @@ -337,7 +337,7 @@ public class BlockMovementChecks { return direction == state.getValue(StickerBlock.FACING) && !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite()); } - if (block instanceof IBogeyBlock bogey) + if (block instanceof AbstractBogeyBlock bogey) return bogey.getStickySurfaces(world, pos, state) .contains(direction); if (block instanceof WhistleBlock) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index 1133742ea..12807830f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -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.redstone.RedstoneContactBlock; 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.tileEntity.IMultiTileContainer; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; @@ -342,7 +342,7 @@ public abstract class Contraption { } // 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)) if (!visited.contains(pos.relative(d))) frontier.add(pos.relative(d)); @@ -1006,7 +1006,7 @@ public abstract class Contraption { if (disassembled) return; disassembled = true; - + for (boolean nonBrittles : Iterate.trueAndFalse) { for (StructureBlockInfo block : blocks.values()) { if (nonBrittles == BlockMovementChecks.isBrittle(block.state)) diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java b/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java index ff20a1c6b..4e206b1d9 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java +++ b/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java @@ -8,6 +8,7 @@ import java.util.Random; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; +import com.simibubi.create.AllTags; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlock; 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)) { BlockState above = level.getBlockState(pos.above() .relative(d2)); - if (AllBlocks.TRACK.has(above)) { + if (AllTags.AllBlockTags.GIRDABLE_TRACKS.matches(above)) { TrackShape shape = above.getValue(TrackBlock.SHAPE); if (shape == (axis == Axis.X ? TrackShape.XO : TrackShape.ZO)) state = state.setValue(updateProperty, true); diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java index 6889a801e..a3aec3eab 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java @@ -9,7 +9,6 @@ import java.util.Optional; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintCraftingInventory; import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; @@ -106,7 +105,7 @@ public class BlueprintOverlayRenderer { int tracks = info.requiredTracks; 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; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java new file mode 100644 index 000000000..3f86c660c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java @@ -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 extends Block implements ITE, ProperWaterloggedBlock, ISpecialBlockItemRequirement, IWrenchable { + public static final EnumProperty AXIS = BlockStateProperties.HORIZONTAL_AXIS; + static final List 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 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 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 STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST); + static final EnumSet STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH); + + public EnumSet 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 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 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 getBogeyBlockCycle() { + return BOGEYS; + } + + + @Override + public BlockState getRotatedBlockState(BlockState state, Direction targetedFace) { + Block block = state.getBlock(); + List 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> propertiesToCopy() { + return ImmutableList.of(WATERLOGGED, AXIS); + } + + // generic method needed to satisfy Property and BlockState's generic requirements + private > BlockState copyProperty(BlockState source, BlockState target, Property 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 allStyles = style.getCycleGroup().values(); + if (allStyles.size() <= 1) + return style; + List 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; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java b/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java index 5c543536d..a65cdb8f6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java @@ -24,6 +24,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; @@ -39,6 +40,7 @@ public class BezierConnection implements Iterable { public Couple normals; public boolean primary; public boolean hasGirder; + protected TrackMaterial trackMaterial; // runtime @@ -55,19 +57,37 @@ public class BezierConnection implements Iterable { private AABB bounds; public BezierConnection(Couple positions, Couple starts, Couple axes, Couple normals, - boolean primary, boolean girder) { + boolean primary, boolean girder, TrackMaterial material) { tePositions = positions; this.starts = starts; this.axes = axes; this.normals = normals; this.primary = primary; this.hasGirder = girder; + this.trackMaterial = material; resolved = false; } public BezierConnection secondary() { 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) { @@ -77,7 +97,7 @@ public class BezierConnection implements Iterable { .map(v -> v.add(Vec3.atLowerCornerOf(localTo))), Couple.deserializeEach(compound.getList("Axes", 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) { @@ -91,13 +111,14 @@ public class BezierConnection implements Iterable { compound.put("Starts", starts.serializeEach(VecHelper::writeNBTCompound)); compound.put("Axes", axes.serializeEach(VecHelper::writeNBTCompound)); compound.put("Normals", normals.serializeEach(VecHelper::writeNBTCompound)); + compound.putString("Material", getMaterial().id.toString()); return compound; } public BezierConnection(FriendlyByteBuf buffer) { this(Couple.create(buffer::readBlockPos), 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) { @@ -107,6 +128,7 @@ public class BezierConnection implements Iterable { normals.forEach(v -> VecHelper.write(v, buffer)); buffer.writeBoolean(primary); buffer.writeBoolean(hasGirder); + buffer.writeUtf(getMaterial().id.toString()); } public BlockPos getKey() { @@ -300,7 +322,7 @@ public class BezierConnection implements Iterable { Inventory inv = player.getInventory(); int tracks = getTrackItemCost(); 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; } int girders = getGirderItemCost(); @@ -328,7 +350,7 @@ public class BezierConnection implements Iterable { continue; Vec3 v = VecHelper.offsetRandomly(segment.position, level.random, .125f) .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(); level.addFreshEntity(entity); if (!hasGirder) @@ -342,7 +364,7 @@ public class BezierConnection implements Iterable { } 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 = new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.METAL_GIRDER.getDefaultState()); if (!(level instanceof ServerLevel slevel)) @@ -360,6 +382,14 @@ public class BezierConnection implements Iterable { } } + public TrackMaterial getMaterial() { + return trackMaterial; + } + + public void setMaterial(TrackMaterial material) { + trackMaterial = material; + } + public static class Segment { public int index; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BogeyRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/BogeyRenderer.java new file mode 100644 index 000000000..02ea4f185 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BogeyRenderer.java @@ -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 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 Generic alias for both contraption and in-world model data + */ + + public static > 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; + } + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java b/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java new file mode 100644 index 000000000..95bf3a5c8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java @@ -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 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 getAllSizesSmallToLarge() { + return BOGEY_SIZES.stream() + .sorted(Comparator.comparing(BogeySize::wheelRadius)) + .collect(Collectors.toList()); + } + + public static List getAllSizesLargeToSmall() { + List 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 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() { + + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java index 94a08b145..fb96b989b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java @@ -1,7 +1,7 @@ package com.simibubi.create.content.logistics.trains; 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 net.minecraft.client.renderer.MultiBufferSource; @@ -17,11 +17,11 @@ public class BogeyTileEntityRenderer extends SafeTileEnti protected void renderSafe(T te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { BlockState blockState = te.getBlockState(); - float angle = 0; - if (te instanceof StandardBogeyTileEntity sbte) - angle = sbte.getVirtualAngle(partialTicks); - if (blockState.getBlock()instanceof IBogeyBlock bogey) - bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay); + if (te instanceof AbstractBogeyTileEntity sbte) { + float angle = sbte.getVirtualAngle(partialTicks); + if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) + bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay, sbte.getStyle(), sbte.getBogeyData()); + } } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java index 990e876cb..4dda3fb56 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java @@ -265,13 +265,17 @@ public class GlobalRailwayManager { public void clientTick() { if (isTrackGraphDebugActive()) for (TrackGraph trackGraph : trackNetworks.values()) - TrackGraphVisualizer.debugViewGraph(trackGraph); + TrackGraphVisualizer.debugViewGraph(trackGraph, isTrackGraphDebugExtended()); } - + private static boolean isTrackGraphDebugActive() { return KineticDebugger.isF3DebugModeActive() && AllConfigs.CLIENT.showTrackGraphOnF3.get(); } + private static boolean isTrackGraphDebugExtended() { + return AllConfigs.CLIENT.showExtendedTrackGraphOnF3.get(); + } + public GlobalRailwayManager sided(LevelAccessor level) { if (level != null && !level.isClientSide()) return this; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java deleted file mode 100644 index dea2966aa..000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java +++ /dev/null @@ -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 BOGEYS = new ArrayList<>(); - - public static void register(ResourceLocation block) { - BOGEYS.add(block); - } - - public EnumSet 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; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java index 33946c2a5..f0ef234d9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java @@ -25,6 +25,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; @@ -74,22 +75,42 @@ public interface ITrackBlock { getTrackAxes(world, pos, state).forEach(axis -> { addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d) .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; } + 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 list, BiFunction offsetFactory, Function normalFactory, - Function> dimensionFactory, Vec3 axis, BezierConnection viaTurn) { + Function> dimensionFactory, Vec3 axis, BezierConnection viaTurn, BiFunction materialFactory) { DiscoveredLocation firstLocation = 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)) .withDirection(axis); DiscoveredLocation secondLocation = 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)) .withDirection(axis); @@ -97,7 +118,7 @@ public interface ITrackBlock { firstLocation.forceNode(); secondLocation.forceNode(); } - + boolean skipFirst = false; boolean skipSecond = false; @@ -152,4 +173,6 @@ public interface ITrackBlock { .normalize()) < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE); } + TrackMaterial getMaterial(); + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java new file mode 100644 index 000000000..d49625a2f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java @@ -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(); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java index d5e3affe0..501b437bf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java @@ -22,13 +22,19 @@ public class TrackEdge { BezierConnection turn; EdgeData edgeData; 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.edgeData = new EdgeData(this); this.node1 = node1; this.node2 = node2; this.turn = turn; + this.trackMaterial = trackMaterial; + } + + public TrackMaterial getTrackMaterial() { + return trackMaterial; } public boolean isTurn() { @@ -181,13 +187,15 @@ public class TrackEdge { public CompoundTag write(DimensionPalette dimensions) { CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag(); baseCompound.put("Signals", edgeData.write(dimensions)); + baseCompound.putString("Material", getTrackMaterial().id.toString()); return baseCompound; } public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { 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); return trackEdge; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java index 897713e94..8bb92da9f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java @@ -393,14 +393,15 @@ public class TrackGraph { 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) { TrackNode node1 = nodes.get(location); TrackNode node2 = nodes.get(location2); boolean bezier = turn != null; - TrackEdge edge = new TrackEdge(node1, node2, turn); - TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null); + TrackMaterial material = bezier ? turn.getMaterial() : location2.materialA; + 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 (TrackNode otherNode1 : graph.nodes.values()) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java index dfd5d0e36..36e1fa5f4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java @@ -60,7 +60,7 @@ public class TrackGraphSync { public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) { flushGraphPacket(graph); 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++; } @@ -82,7 +82,7 @@ public class TrackGraphSync { if (currentGraphSyncPacket.addedNodes.remove(nodeId) == null) currentGraphSyncPacket.removedNodes.add(nodeId); currentGraphSyncPacket.addedEdges.removeIf(pair -> { - Couple ids = pair.getFirst(); + Couple ids = pair.getFirst().getFirst(); return ids.getFirst() .intValue() == nodeId || ids.getSecond() @@ -156,7 +156,7 @@ public class TrackGraphSync { graph.connectionsByNode.get(node) .forEach((node2, edge) -> { Couple 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); }); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java index 33e5e0790..7707db41b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java @@ -22,7 +22,7 @@ import net.minecraft.world.phys.Vec3; public class TrackGraphSyncPacket extends TrackGraphPacket { Map> addedNodes; - List, BezierConnection>> addedEdges; + List, TrackMaterial>, BezierConnection>> addedEdges; List removedNodes; List addedEdgePoints; List removedEdgePoints; @@ -79,7 +79,7 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { size = buffer.readVarInt(); for (int i = 0; i < size; i++) 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(); for (int i = 0; i < size; i++) @@ -134,8 +134,9 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { buffer.writeVarInt(addedEdges.size()); addedEdges.forEach(pair -> { - pair.getFirst() + pair.getFirst().getFirst() .forEach(buffer::writeVarInt); + buffer.writeUtf(pair.getFirst().getSecond().id.toString()); BezierConnection turn = pair.getSecond(); buffer.writeBoolean(turn != null); if (turn != null) @@ -192,13 +193,13 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond()); } - for (Pair, BezierConnection> pair : addedEdges) { - Couple nodes = pair.getFirst() + for (Pair, TrackMaterial>, BezierConnection> pair : addedEdges) { + Couple nodes = pair.getFirst().getFirst() .map(graph::getNode); TrackNode node1 = nodes.getFirst(); TrackNode node2 = nodes.getSecond(); 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) @@ -268,4 +269,4 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { updatedEdgeData.put(key, Pair.of(groupType, list)); } -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java index 66988f041..bc2c24241 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java @@ -5,6 +5,15 @@ import java.util.Map; import java.util.Map.Entry; 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 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(); Entity cameraEntity = mc.cameraEntity; if (cameraEntity == null) @@ -262,6 +271,13 @@ public class TrackGraphVisualizer { yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0); 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) .add(yOffset), edge.getPosition(1) @@ -273,6 +289,13 @@ public class TrackGraphVisualizer { Vec3 previous = null; 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++) { Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount()); if (previous != null) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java new file mode 100644 index 000000000..03794a220 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java @@ -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 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> 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> trackBlock, + ResourceLocation particle, Ingredient sleeperIngredient, Ingredient railsIngredient, + TrackType trackType, Supplier> 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 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> allCustomBlocks(String modid) { + List> list = new ArrayList<>(); + for (TrackMaterial material : allCustom(modid)) { + list.add(material.getTrackBlock()); + } + return list; + } + + public static List> allBlocks() { + List> 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); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java new file mode 100644 index 000000000..878f09ce2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java @@ -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> 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> 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> tieModel, Supplier> leftSegmentModel, Supplier> 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); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java index 509eedd23..ad8c0e009 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java @@ -24,8 +24,8 @@ public class TrackNodeLocation extends Vec3i { this(vec.x, vec.y, vec.z); } - public TrackNodeLocation(double p_121865_, double p_121866_, double p_121867_) { - super(Math.round(p_121865_ * 2), Math.floor(p_121866_ * 2), Math.round(p_121867_ * 2)); + public TrackNodeLocation(double x, double y, double z) { + super(Math.round(x * 2), Math.floor(y * 2), Math.round(z * 2)); } public TrackNodeLocation in(Level level) { @@ -116,9 +116,11 @@ public class TrackNodeLocation extends Vec3i { boolean forceNode = false; Vec3 direction; Vec3 normal; + TrackMaterial materialA; + TrackMaterial materialB; - public DiscoveredLocation(Level level, double p_121865_, double p_121866_, double p_121867_) { - super(p_121865_, p_121866_, p_121867_); + public DiscoveredLocation(Level level, double x, double y, double z) { + super(x, y, z); in(level); } @@ -131,6 +133,22 @@ public class TrackNodeLocation extends Vec3i { 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) { this.turn = turn; if (turn != null) @@ -165,6 +183,10 @@ public class TrackNodeLocation extends Vec3i { return forceNode; } + public boolean differentMaterials() { + return materialA != materialB; + } + public boolean notInLineWith(Vec3 direction) { return this.direction != null && Math.max(direction.dot(this.direction), direction.dot(this.direction.scale(-1))) < 7 / 8f; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java index 611787364..c755b4613 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java @@ -234,10 +234,12 @@ public class TrackPropagator { return true; if (location.shouldForceNode()) return true; + if (location.differentMaterials()) + return true; if (next.stream() .anyMatch(DiscoveredLocation::shouldForceNode)) return true; - + Vec3 direction = location.direction; if (direction != null && next.stream() .anyMatch(dl -> dl.notInLineWith(direction))) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BackupBogeyRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BackupBogeyRenderer.java new file mode 100644 index 000000000..80494a94a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BackupBogeyRenderer.java @@ -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) { + + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java index 9a8a6c9c1..a9b0ff8af 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java @@ -1,235 +1,72 @@ package com.simibubi.create.content.logistics.trains.entity; -import com.jozufozu.flywheel.api.Material; 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.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -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 com.simibubi.create.content.logistics.trains.BogeyRenderer; + +import com.simibubi.create.content.logistics.trains.BogeySizes; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.LightLayer; 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; - private final ModelData[] shafts; + public final BogeyRenderer renderer; + public final Optional commonRenderer; - protected BogeyInstance(CarriageBogey bogey, MaterialManager materialManager) { + public BogeyInstance(CarriageBogey bogey, BogeyStyle style, BogeySizes.BogeySize size, MaterialManager materialManager) { this.bogey = bogey; + this.size = size; + this.style = style; - shafts = new ModelData[2]; - - materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, Direction.Axis.Z)) - .createInstances(shafts); + this.renderer = this.style.createRendererInstance(this.size); + this.commonRenderer = this.style.getNewCommonRenderInstance(); + commonRenderer.ifPresent(bogeyRenderer -> + bogeyRenderer.initialiseContraptionModelData(materialManager)); + renderer.initialiseContraptionModelData(materialManager); } - public void remove() { - for (ModelData shaft : shafts) - shaft.delete(); - } - - public void hiddenFrame() { + void hiddenFrame() { beginFrame(0, null); } - + public void beginFrame(float wheelAngle, PoseStack ms) { if (ms == null) { - for (int i : Iterate.zeroAndOne) - shafts[i].setEmptyTransform(); + renderer.emptyTransforms(); return; } - for (int i : Iterate.zeroAndOne) - shafts[i].setTransform(ms) - .translate(-.5f, .25f, i * -1) - .centre() - .rotateZ(wheelAngle) - .unCentre(); + commonRenderer.ifPresent(bogeyRenderer -> + bogeyRenderer.render(bogey.bogeyData, wheelAngle, ms)); + renderer.render(bogey.bogeyData, wheelAngle, ms); } public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) { var lightPos = new BlockPos(getLightPos(entity)); - - updateLight(world.getBrightness(LightLayer.BLOCK, lightPos), world.getBrightness(LightLayer.SKY, lightPos)); + commonRenderer.ifPresent(bogeyRenderer + -> 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) { - if (bogey.getAnchorPosition() != null) { - return bogey.getAnchorPosition(); - } else { - return entity.getLightProbePosition(AnimationTickHolder.getPartialTicks()); - } + return bogey.getAnchorPosition() != null ? bogey.getAnchorPosition() + : entity.getLightProbePosition(AnimationTickHolder.getPartialTicks()); } - public void updateLight(int blockLight, int skyLight) { - for (ModelData shaft : shafts) { - shaft.setBlockLight(blockLight) - .setSkyLight(skyLight); - } - } - - 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 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(); - } + @FunctionalInterface + interface BogeyInstanceFactory { + BogeyInstance create(CarriageBogey bogey, BogeySizes.BogeySize size, + MaterialManager materialManager); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java new file mode 100644 index 000000000..2b3efc8d7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java @@ -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> commonRendererFactory; + + public final ResourceLocation name; + public final ResourceLocation cycleGroup; + private final Optional commonRenderer; + private final Map 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 sizes, Optional> 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 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 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 getInWorldCommonRenderInstance() { + return this.commonRenderer; + } + + public Optional 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 rendererFactory, BogeyRenderer instance) { + public BogeyRenderer createRenderInstance() { + return rendererFactory.get(); + } + + public BogeyRenderer getInWorldInstance() { + return instance; + } + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java index 12d25eea7..ec7e9f1d7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java @@ -85,6 +85,11 @@ public class Carriage { bogey2.carriage = this; } + public boolean isOnIncompatibleTrack() { + return leadingBogey().type.isOnIncompatibleTrack(this, true) + || trailingBogey().type.isOnIncompatibleTrack(this, false); + } + public void setTrain(Train train) { this.train = train; } @@ -306,6 +311,9 @@ public class Carriage { double leadingWheelSpacing = leadingBogey.type.getWheelPointSpacing(); double trailingWheelSpacing = trailingBogey.type.getWheelPointSpacing(); + boolean leadingUpsideDown = leadingBogey.isUpsideDown(); + boolean trailingUpsideDown = trailingBogey.isUpsideDown(); + for (boolean leading : Iterate.trueAndFalse) { TravellingPoint point = leading ? getLeadingPoint() : getTrailingPoint(); TravellingPoint otherPoint = !leading ? getLeadingPoint() : getTrailingPoint(); @@ -321,24 +329,31 @@ public class Carriage { dce.positionAnchor = dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() : 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()) { dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() : pivoted(dce, dimension, point, - leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2)); - dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition() + leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2, + leadingUpsideDown, trailingUpsideDown)); + dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition(backAnchorFlip) : pivoted(dce, dimension, point, - leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2)); + leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2, + leadingUpsideDown, trailingUpsideDown)); } else { if (dimension.equals(otherDimension)) { dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition); } else { 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() - : 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 dimension, TravellingPoint start, - double offset) { + double offset, boolean leadingUpsideDown, boolean trailingUpsideDown) { if (train.graph == null) return dce.pivot == null ? null : dce.pivot.getLocation(); TrackNodeLocation pivot = dce.findPivot(dimension, start == getLeadingPoint()); if (pivot == null) return null; - Vec3 startVec = start.getPosition(); + boolean flipped = start != getLeadingPoint() && (leadingUpsideDown != trailingUpsideDown); + Vec3 startVec = start.getPosition(flipped); 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); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java index c9e2d7220..1d22c4aec 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java @@ -3,13 +3,16 @@ package com.simibubi.create.content.logistics.trains.entity; import javax.annotation.Nullable; import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllBogeyStyles; import com.simibubi.create.Create; 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.track.AbstractBogeyTileEntity; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Couple; 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.VecHelper; 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.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 Carriage carriage; + public static final String UPSIDE_DOWN_KEY = "UpsideDown"; + public Carriage carriage; boolean isLeading; - IBogeyBlock type; + public CompoundTag bogeyData; + + AbstractBogeyBlock type; + boolean upsideDown; Couple points; LerpedFloat wheelAngle; @@ -42,8 +52,15 @@ public class CarriageBogey { 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.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); wheelAngle = LerpedFloat.angular(); yaw = LerpedFloat.angular(); @@ -100,11 +117,15 @@ public class CarriageBogey { } public TravellingPoint leading() { - return points.getFirst(); + TravellingPoint point = points.getFirst(); + point.upsideDown = isUpsideDown(); + return point; } public TravellingPoint trailing() { - return points.getSecond(); + TravellingPoint point = points.getSecond(); + point.upsideDown = isUpsideDown(); + return point; } public double getStress() { @@ -118,18 +139,25 @@ public class CarriageBogey { @Nullable public Vec3 getAnchorPosition() { + return getAnchorPosition(false); + } + + @Nullable + public Vec3 getAnchorPosition(boolean flipUpsideDown) { if (leading().edge == null) return null; return points.getFirst() - .getPosition() - .add(points.getSecond() - .getPosition()) - .scale(.5); + .getPosition(flipUpsideDown) + .add(points.getSecond() + .getPosition(flipUpsideDown)) + .scale(.5); } public void updateCouplingAnchor(Vec3 entityPos, float entityXRot, float entityYRot, int bogeySpacing, 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 = 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, -entityXRot, Axis.X); 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)); } @@ -150,23 +180,46 @@ public class CarriageBogey { tag.putString("Type", RegisteredObjects.getKeyOrThrow((Block) type) .toString()); 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; } public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { 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 points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND), c -> TravellingPoint.read(c, graph, dimensions)); - CarriageBogey carriageBogey = new CarriageBogey(type, points.getFirst(), points.getSecond()); - return carriageBogey; + CompoundTag data = tag.getCompound(AbstractBogeyTileEntity.BOGEY_DATA_KEY); + return new CarriageBogey(type, upsideDown, data, points.getFirst(), points.getSecond()); } 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() { isLeading = true; } + + public boolean isUpsideDown() { + return type.canBeUpsideDown() && upsideDown; + } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java index ad2396191..1b185055f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java @@ -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.processing.burner.BlazeBurnerBlock; 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.Iterate; import com.simibubi.create.foundation.utility.Lang; @@ -71,7 +71,7 @@ public class CarriageContraption extends Contraption { // render public int portalCutoffMin; public int portalCutoffMax; - + static final IItemHandlerModifiable fallbackItems = new ItemStackHandler(); static final IFluidHandler fallbackFluids = new FluidTank(0); @@ -162,11 +162,13 @@ public class CarriageContraption extends Contraption { .getStep(), toLocalPos(pos)); } - if (blockState.getBlock() instanceof IBogeyBlock) { + if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) { + boolean captureTE = bogey.captureTileEntityForTrain(); bogeys++; if (bogeys == 2) 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) @@ -235,7 +237,7 @@ public class CarriageContraption extends Contraption { protected MountedStorageManager getStorageForSpawnPacket() { return storageProxy; } - + @Override protected ContraptionType getType() { return ContraptionType.CARRIAGE; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java index 5de635e4a..02b219074 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java @@ -13,6 +13,7 @@ import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.core.BlockPos; import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.phys.Vec3; public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer { @@ -37,7 +38,7 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer MultiBufferSource buffers, int overlay) { if (!entity.validForRender || entity.firstPositionUpdate) return; - + super.render(entity, yaw, partialTicks, ms, buffers, overlay); Carriage carriage = entity.getCarriage(); @@ -65,8 +66,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks); int light = getBogeyLightCoords(entity, bogey, partialTicks); + bogey.type.render(null, bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light, - overlay); + overlay, bogey.getStyle(), bogey.bogeyData); ms.popPose(); } @@ -80,6 +82,8 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot, float viewXRot, float partialTicks) { + boolean selfUpsideDown = bogey.isUpsideDown(); + boolean leadingUpsideDown = bogey.carriage.leadingBogey().isUpsideDown(); TransformStack.cast(ms) .rotateY(viewYRot + 90) .rotateX(-viewXRot) @@ -90,7 +94,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer .rotateY(-viewYRot - 90) .rotateY(bogey.yaw.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) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java index 4d18e2525..6797c05cd 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java @@ -7,6 +7,7 @@ import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; 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.Iterate; @@ -31,7 +32,8 @@ public class CarriageContraptionInstance extends EntityInstance + bogey.getStyle().createInstance(bogey, bogey.type.getSize(), manager), materialManager); updateLight(); } @@ -98,8 +100,10 @@ public class CarriageContraptionInstance extends EntityInstance { - if (instance != null) - instance.remove(); + if (instance != null) { + instance.commonRenderer.ifPresent(BogeyRenderer::remove); + instance.renderer.remove(); + } }); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java index a77635d64..d736e15f8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java @@ -79,7 +79,7 @@ public class CarriageCouplingRenderer { float margin = 3 / 16f; 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); double stretch = ((anchor2.distanceTo(anchor) - 2 * margin) * 4) / couplingSegments; for (int j = 0; j < couplingSegments; j++) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java index be2e6fe41..e25db67d8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java @@ -10,7 +10,6 @@ import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; import net.minecraft.client.Minecraft; import net.minecraft.core.Direction.Axis; -import net.minecraft.core.particles.ParticleTypes; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -110,7 +109,7 @@ public class CarriageParticles { 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); } } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java index 6d109d1ad..932ce903f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.trains.entity; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents.SoundEntry; 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.Chaser; @@ -29,6 +30,9 @@ public class CarriageSounds { LoopingSound sharedWheelSoundSeated; LoopingSound sharedHonkSound; + Couple bogeySounds; + SoundEvent closestBogeySound; + boolean arrived; int tick; @@ -36,6 +40,10 @@ public class CarriageSounds { public CarriageSounds(CarriageContraptionEntity 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(); speedFactor = LerpedFloat.linear(); approachFactor = LerpedFloat.linear(); @@ -79,6 +87,15 @@ public class CarriageSounds { double distance1 = toBogey1.length(); double distance2 = toBogey2.length(); + Couple 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; double distance = Math.min(distance1, distance2); Vec3 soundLocation = cam.add(toCarriage); @@ -97,7 +114,7 @@ public class CarriageSounds { seatCrossfade.tickChaser(); 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()); 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) { Minecraft mc = Minecraft.getInstance(); 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()); boolean approach = true; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java index 258bc4da1..9e08613d5 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java @@ -14,6 +14,8 @@ import java.util.UUID; 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.MutableObject; @@ -251,7 +253,7 @@ public class Navigation { return; } } - + topSpeed *= train.throttle; double turnTopSpeed = Math.min(topSpeed, train.maxTurnSpeed()); @@ -540,6 +542,21 @@ public class Navigation { if (graph == null) return; + // Cache the list of track types that the train can travel on + Set 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 penalties = new IdentityHashMap<>(); boolean costRelevant = maxCost >= 0; if (costRelevant) { @@ -579,7 +596,7 @@ public class Navigation { .get(initialNode2); if (initialEdge == null) return; - + double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position; frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge)); @@ -659,6 +676,8 @@ public class Navigation { continue; for (Entry target : validTargets) { + if (!validTypes.contains(target.getValue().getTrackMaterial().trackType)) + continue; TrackNode newNode = target.getKey(); TrackEdge newEdge = target.getValue(); double newDistance = newEdge.getLength() + distance; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index a5a371013..dea3d9782 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -17,6 +17,10 @@ import java.util.function.Consumer; 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.MutableObject; @@ -124,7 +128,7 @@ public class Train { public int honkPitch; public float accumulatedSteamRelease; - + int tickOffset; double[] stress; @@ -277,7 +281,7 @@ public class Train { int carriageCount = carriages.size(); boolean stalled = false; double maxStress = 0; - + if (carriageWaitingForChunks != -1) distance = 0; @@ -313,11 +317,17 @@ public class Train { if (leadingAnchor == null || trailingAnchor == null) 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++; } } - + if (entries > 0) actual = total / entries; @@ -369,13 +379,13 @@ public class Train { .getLeadingPoint(); double totalStress = derailed ? 0 : leadingStress + trailingStress; - + boolean first = i == 0; boolean last = i == carriageCount - 1; int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE; double actualDistance = carriage.travel(level, graph, distance + totalStress, toFollowForward, toFollowBackward, carriageType); - blocked |= carriage.blocked; + blocked |= carriage.blocked || carriage.isOnIncompatibleTrack(); boolean onTwoBogeys = carriage.isOnTwoBogeys(); maxStress = Math.max(maxStress, onTwoBogeys ? carriage.bogeySpacing - carriage.getAnchorDiff() : 0); @@ -722,9 +732,20 @@ public class Train { if (entity.getContraption()instanceof CarriageContraption cc) cc.returnStorageForDisassembly(carriage.storage); 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(); + 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; if (i < carriageSpacing.size()) @@ -944,7 +965,7 @@ public class Train { occupiedObservers.clear(); cachedObserverFiltering.clear(); - TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position); + TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position, false); Map allGroups = Create.RAILWAYS.signalEdgeGroups; MutableObject prevGroup = new MutableObject<>(null); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java index 479b2699e..238124743 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java @@ -7,12 +7,13 @@ import java.util.UUID; import java.util.function.Supplier; 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.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.RegisteredObjects; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.Block; @@ -44,11 +45,13 @@ public class TrainPacket extends SimplePacketBase { int size = buffer.readVarInt(); for (int i = 0; i < size; i++) { Couple bogies = Couple.create(null, null); - for (boolean first : Iterate.trueAndFalse) { - if (!first && !buffer.readBoolean()) + for (boolean isFirst : Iterate.trueAndFalse) { + if (!isFirst && !buffer.readBoolean()) continue; - IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation()); - bogies.set(first, new CarriageBogey(type, new TravellingPoint(), new TravellingPoint())); + AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation()); + boolean upsideDown = buffer.readBoolean(); + CompoundTag data = buffer.readNbt(); + bogies.set(isFirst, new CarriageBogey(type, upsideDown, data, new TravellingPoint(), new TravellingPoint())); } int spacing = buffer.readVarInt(); carriages.add(new Carriage(bogies.getFirst(), bogies.getSecond(), spacing)); @@ -86,6 +89,8 @@ public class TrainPacket extends SimplePacketBase { } CarriageBogey bogey = carriage.bogeys.get(first); buffer.writeResourceLocation(RegisteredObjects.getKeyOrThrow((Block) bogey.type)); + buffer.writeBoolean(bogey.upsideDown); + buffer.writeNbt(bogey.bogeyData); } buffer.writeVarInt(carriage.bogeySpacing); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java index 149120c53..edde7903d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java @@ -115,10 +115,13 @@ public class TrainRelocator { BlockPos blockPos = blockhit.getBlockPos(); 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) { for (int i = 0; i < toVisualise.size() - 1; i++) { - Vec3 vec1 = toVisualise.get(i); - Vec3 vec2 = toVisualise.get(i + 1); + Vec3 vec1 = toVisualise.get(i).add(offset); + 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)) .colored(lastHoveredResult || i != toVisualise.size() - 2 ? 0x95CD41 : 0xEA5C2B) .disableLineNormals() @@ -150,7 +153,7 @@ public class TrainRelocator { boolean direction = bezierSelection != null && lookAngle.dot(bezierSelection.direction()) < 0; boolean result = relocate(relocating, mc.level, blockPos, hoveredBezier, direction, lookAngle, true); 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, direction, lookAngle, relocatingEntityId)); } @@ -182,7 +185,7 @@ public class TrainRelocator { if (edge == null) 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(); ITurnListener ignoreTurns = probe.ignoreTurns(); List, Double>> recordedLocations = new ArrayList<>(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java index 194d926a6..827380139 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java @@ -38,6 +38,7 @@ public class TravellingPoint { public TrackEdge edge; public double position; public boolean blocked; + public boolean upsideDown; public static enum SteerDirection { NONE(0), LEFT(-1), RIGHT(1); @@ -64,11 +65,12 @@ public class 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.node2 = node2; this.edge = edge; this.position = position; + this.upsideDown = upsideDown; } public IEdgePointListener ignoreEdgePoints() { @@ -395,14 +397,22 @@ public class TravellingPoint { } public Vec3 getPosition() { - return getPositionWithOffset(0); + return getPosition(false); + } + + public Vec3 getPosition(boolean flipped) { + return getPositionWithOffset(0, flipped); } public Vec3 getPositionWithOffset(double offset) { + return getPositionWithOffset(offset, false); + } + + public Vec3 getPositionWithOffset(double offset, boolean flipUpsideDown) { double t = (position + offset) / edge.getLength(); return edge.getPosition(t) - .add(edge.getNormal(node1, node2, t) - .scale(1)); + .add(edge.getNormal(node1, node2, t) + .scale(upsideDown^flipUpsideDown ? -1 : 1)); } public void migrateTo(List locations) { @@ -423,12 +433,13 @@ public class TravellingPoint { tag.put("Nodes", nodes.map(TrackNode::getLocation) .serializeEach(loc -> loc.write(dimensions))); tag.putDouble("Position", position); + tag.putBoolean("UpsideDown", upsideDown); return tag; } public static TravellingPoint read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { if (graph == null) - return new TravellingPoint(null, null, null, 0); + return new TravellingPoint(null, null, null, 0, false); Couple locs = tag.contains("Nodes") ? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions)) @@ -436,11 +447,11 @@ public class TravellingPoint { : Couple.create(null, null); 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"); return new TravellingPoint(locs.getFirst(), locs.getSecond(), graph.getConnectionsFrom(locs.getFirst()) - .get(locs.getSecond()), position); + .get(locs.getSecond()), position, tag.getBoolean("UpsideDown")); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java index 9fdb9a96b..5e73be778 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java @@ -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.logistics.block.depot.DepotBehaviour; 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.TrackEdge; 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.schedule.Schedule; 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.block.ProperWaterloggedBlock; 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.Chaser; +import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos.MutableBlockPos; 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.item.ItemStack; 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.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; @@ -189,7 +192,8 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable Direction assemblyDirection; int assemblyLength; int[] bogeyLocations; - IBogeyBlock[] bogeyTypes; + AbstractBogeyBlock[] bogeyTypes; + boolean[] upsideDownBogeys; int bogeyCount; @Override @@ -266,14 +270,30 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable return false; 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; + if (!isValidBogeyOffset(bogeyOffset)) { - for (int i = -1; i <= 1; i++) { - BlockPos bogeyPos = pos.relative(assemblyDirection, i) - .offset(up); - BlockState blockState = level.getBlockState(bogeyPos); - if (blockState.getBlock() instanceof IBogeyBlock bogey) { - level.setBlock(bogeyPos, bogey.getRotatedBlockState(blockState, Direction.DOWN), 3); + for (boolean upsideDown : Iterate.falseAndTrue) { + for (int i = -1; i <= 1; i++) { + BlockPos bogeyPos = pos.relative(assemblyDirection, i) + .offset(upsideDown ? down : up); + BlockState blockState = level.getBlockState(bogeyPos); + 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); return true; } @@ -288,7 +308,9 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable 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) .getDestroySpeed(level, targetPos) == -1) { return false; @@ -296,7 +318,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable 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); player.displayClientMessage(Lang.translateDirect("train_assembly.bogey_created"), true); SoundType soundtype = bogeyAnchor.getBlock() @@ -370,9 +396,12 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable if (bogeyLocations == null) bogeyLocations = new int[maxBogeyCount]; if (bogeyTypes == null) - bogeyTypes = new IBogeyBlock[maxBogeyCount]; + bogeyTypes = new AbstractBogeyBlock[maxBogeyCount]; + if (upsideDownBogeys == null) + upsideDownBogeys = new boolean[maxBogeyCount]; Arrays.fill(bogeyLocations, -1); Arrays.fill(bogeyTypes, null); + Arrays.fill(upsideDownBogeys, false); for (int i = 0; i < MAX_LENGTH; i++) { if (i == MAX_LENGTH - 1) { @@ -385,10 +414,19 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable } BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos)); - if (potentialBogeyState.getBlock() instanceof IBogeyBlock bogey && bogeyIndex < bogeyLocations.length) { - bogeyTypes[bogeyIndex] = bogey; - bogeyLocations[bogeyIndex] = i; - bogeyIndex++; + BlockPos upsideDownBogeyOffset = new BlockPos(bogeyOffset.getX(), bogeyOffset.getY()*-1, bogeyOffset.getZ()); + if (bogeyIndex < bogeyLocations.length) { + if (potentialBogeyState.getBlock() instanceof AbstractBogeyBlock bogey && !bogey.isUpsideDown(potentialBogeyState)) { + 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); @@ -548,7 +586,7 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable return; } - points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge)); + points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge, false)); } secondNode = node; @@ -575,10 +613,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable spacing.add(bogeyLocations[bogeyIndex] - bogeyLocations[bogeyIndex - 1]); CarriageContraption contraption = new CarriageContraption(assemblyDirection); BlockPos bogeyPosOffset = trackPosition.offset(bogeyOffset); + BlockPos upsideDownBogeyPosOffset = trackPosition.offset(new BlockPos(bogeyOffset.getX(), bogeyOffset.getY() * -1, bogeyOffset.getZ())); try { 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(); contraption.setSoundQueueOffset(offset); if (!success) { @@ -591,24 +630,28 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable 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 = - 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; BlockPos secondBogeyPos = contraption.getSecondBogeyPos(); int bogeySpacing = 0; if (secondBogeyPos != null) { 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")), contraptions.size() + 1); return; } - + AbstractBogeyTileEntity secondBogeyTileEntity = + (AbstractBogeyTileEntity) level.getBlockEntity(secondBogeyPos); bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex]; - secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], points.get(pointIndex + 2), - points.get(pointIndex + 3)); + secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], upsideDownBogeys[bogeyIndex + 1], secondBogeyTileEntity.getBogeyData(), + points.get(pointIndex + 2), points.get(pointIndex + 3)); bogeyIndex++; } else if (!typeOfFirstBogey.allowsSingleBogeyCarriage()) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyTileEntity.java new file mode 100644 index 000000000..8ec37da45 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyTileEntity.java @@ -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); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java index 4194b591e..2af5b5f38 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java @@ -1,7 +1,7 @@ package com.simibubi.create.content.logistics.trains.track; -import com.simibubi.create.AllBlocks; 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.track.TrackBlockOutline.BezierPointSelection; import com.simibubi.create.foundation.networking.AllPackets; @@ -117,7 +117,7 @@ public class CurvedTrackInteraction { if (event.isUseItem()) { ItemStack heldItem = player.getMainHandItem(); Item item = heldItem.getItem(); - if (AllBlocks.TRACK.isIn(heldItem)) { + if (AllTags.AllBlockTags.TRACKS.matches(heldItem)) { player.displayClientMessage(Lang.translateDirect("track.turn_start") .withStyle(ChatFormatting.RED), true); player.swing(InteractionHand.MAIN_HAND); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java index 4d1859325..c488947b1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java @@ -2,7 +2,7 @@ package com.simibubi.create.content.logistics.trains.track; import java.util.function.Supplier; -import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllTags; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.nbt.CompoundTag; @@ -16,7 +16,7 @@ public class PlaceExtendedCurvePacket extends SimplePacketBase { boolean mainHand; boolean ctrlDown; - + public PlaceExtendedCurvePacket(boolean mainHand, boolean ctrlDown) { this.mainHand = mainHand; this.ctrlDown = ctrlDown; @@ -39,7 +39,7 @@ public class PlaceExtendedCurvePacket extends SimplePacketBase { ctx.enqueueWork(() -> { ServerPlayer sender = ctx.getSender(); 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; CompoundTag tag = stack.getTag(); tag.putBoolean("ExtendCurve", true); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java index 9db10db41..4e12babab 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java @@ -1,87 +1,35 @@ 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.AllBogeyStyles; import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.content.logistics.trains.entity.BogeyInstance; -import com.simibubi.create.content.logistics.trains.entity.CarriageBogey; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; +import com.simibubi.create.content.logistics.trains.BogeySizes; +import com.simibubi.create.content.logistics.trains.TrackMaterial; +import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; 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.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.Direction; -import net.minecraft.core.Direction.Axis; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; 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.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.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -public class StandardBogeyBlock extends Block - implements IBogeyBlock, ITE, ProperWaterloggedBlock, ISpecialBlockItemRequirement { +public class StandardBogeyBlock extends AbstractBogeyBlock implements ITE, ProperWaterloggedBlock, ISpecialBlockItemRequirement { - public static final EnumProperty AXIS = BlockStateProperties.HORIZONTAL_AXIS; - private final boolean large; - - public StandardBogeyBlock(Properties p_i48440_1_, boolean large) { - super(p_i48440_1_); - this.large = large; + public StandardBogeyBlock(Properties props, BogeySizes.BogeySize size) { + super(props, size); registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); } @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(AXIS, WATERLOGGED); - super.createBlockStateDefinition(builder); - } - - static final EnumSet STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST); - static final EnumSet STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH); - - @Override - public EnumSet 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); + public TrackMaterial.TrackType getTrackType(BogeyStyle style) { + return TrackMaterial.TrackType.STANDARD; } @Override @@ -91,7 +39,7 @@ public class StandardBogeyBlock extends Block @Override public double getWheelRadius() { - return (large ? 12.5 : 6.5) / 16d; + return (size == BogeySizes.LARGE ? 12.5 : 6.5) / 16d; } @Override @@ -100,122 +48,8 @@ public class StandardBogeyBlock extends Block } @Override - public boolean allowsSingleBogeyCarriage() { - return true; - } - - @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; - }; + public BogeyStyle getDefaultStyle() { + return AllBogeyStyles.STANDARD; } @Override @@ -233,10 +67,4 @@ public class StandardBogeyBlock extends Block public BlockEntityType getTileEntityType() { return AllTileEntities.BOGEY.get(); } - - @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - return new ItemRequirement(ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack()); - } - } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java index 9a4c8a621..834a1b4c8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java @@ -1,40 +1,19 @@ package com.simibubi.create.content.logistics.trains.track; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity; -import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; 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) { super(type, pos, state); } @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().inflate(2); + public BogeyStyle getDefaultStyle() { + 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); - } - } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java index a30072daf..78cc17b3b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java @@ -19,6 +19,13 @@ import java.util.Random; import java.util.Set; 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 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.OnlyIn; import net.minecraftforge.client.IBlockRenderProperties; - +//init public class TrackBlock extends Block implements ITE, IWrenchable, ITrackBlock, ISpecialBlockItemRequirement, ProperWaterloggedBlock { public static final EnumProperty SHAPE = EnumProperty.create("shape", TrackShape.class); 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_); registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO) .setValue(HAS_TE, false) .setValue(WATERLOGGED, false)); + this.material = material; } + + @Override protected void createBlockStateDefinition(Builder p_49915_) { super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TE, WATERLOGGED)); } - + @Override public BlockPathTypes getAiPathNodeType(BlockState state, BlockGetter world, BlockPos pos, Mob entity) { return BlockPathTypes.RAIL; @@ -379,7 +391,7 @@ public class TrackBlock extends Block (d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d) .add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis, - null); + null, (b, v) -> ITrackBlock.getMaterialSimple(world, v)); } else list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo); @@ -395,7 +407,7 @@ public class TrackBlock extends Block Map connections = trackTE.getConnections(); 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, - 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)) return list; @@ -407,7 +419,7 @@ public class TrackBlock extends Block return list; BlockPos boundPos = trackTE.boundLocation.getSecond(); BlockState boundState = otherLevel.getBlockState(boundPos); - if (!AllBlocks.TRACK.has(boundState)) + if (!AllTags.AllBlockTags.TRACKS.matches(boundState)) return list; Vec3 center = Vec3.atBottomCenterOf(pos) @@ -421,7 +433,7 @@ public class TrackBlock extends Block getTrackAxes(world, pos, state).forEach(axis -> { ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d) .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; @@ -750,7 +762,8 @@ public class TrackBlock extends Block @Override public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - int trackAmount = 1; + int sameTypeTrackAmount = 1; + Object2IntMap otherTrackAmounts = new Object2IntArrayMap<>(); int girderAmount = 0; if (te instanceof TrackTileEntity track) { @@ -758,15 +771,27 @@ public class TrackBlock extends Block .values()) { if (!bezierConnection.isPrimary()) 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(); } } List stacks = new ArrayList<>(); - while (trackAmount > 0) { - stacks.add(AllBlocks.TRACK.asStack(Math.min(trackAmount, 64))); - trackAmount -= 64; + while (sameTypeTrackAmount > 0) { + stacks.add(new ItemStack(state.getBlock(), Math.min(sameTypeTrackAmount, 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) { 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); } + @Override + public TrackMaterial getMaterial() { + return material; + } + public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler { @Override @Nullable diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java index a8b5929dc..5cd2f93cc 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.track; import com.simibubi.create.AllBlocks; 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.track.TrackPlacement.PlacementInfo; import com.simibubi.create.foundation.networking.AllPackets; @@ -111,7 +112,7 @@ public class TrackBlockItem extends BlockItem { return InteractionResult.SUCCESS; stack = player.getMainHandItem(); - if (AllBlocks.TRACK.isIn(stack)) { + if (AllTags.AllBlockTags.TRACKS.matches(stack)) { stack.setTag(null); player.setItemInHand(pContext.getHand(), stack); } @@ -154,7 +155,7 @@ public class TrackBlockItem extends BlockItem { @OnlyIn(Dist.CLIENT) public static void sendExtenderPacket(PlayerInteractEvent.RightClickBlock event) { ItemStack stack = event.getItemStack(); - if (!AllBlocks.TRACK.isIn(stack) || !stack.hasTag()) + if (!AllTags.AllBlockTags.TRACKS.matches(stack) || !stack.hasTag()) return; if (Minecraft.getInstance().options.keySprint.isDown()) AllPackets.channel diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java index 54130e673..dca2e8e1a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java @@ -8,8 +8,8 @@ import java.util.function.Consumer; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; +import com.simibubi.create.AllTags; import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; @@ -162,7 +162,7 @@ public class TrackBlockOutline { .rotateXRadians(angles.x) .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); ms.popPose(); } @@ -190,7 +190,7 @@ public class TrackBlockOutline { ms.pushPose(); 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); boolean isJunction = shape.isJunction(); walkShapes(shape, TransformStack.cast(ms), s -> { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java index 7bb371ede..37cb3b6e0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java @@ -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.GirderAngles; 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.Iterate; @@ -38,7 +39,7 @@ public class TrackInstance extends BlockEntityInstance { @Override public void update() { - if (blockEntity.connections.isEmpty()) + if (blockEntity.connections.isEmpty()) return; remove(); @@ -112,11 +113,13 @@ public class TrackInstance extends BlockEntityInstance { leftLightPos = new BlockPos[segCount]; rightLightPos = new BlockPos[segCount]; - mat.getModel(AllBlockPartials.TRACK_TIE) + TrackMaterial.TrackModelHolder modelHolder = bc.getMaterial().getModelHolder(); + + mat.getModel(modelHolder.tie()) .createInstances(ties); - mat.getModel(AllBlockPartials.TRACK_SEGMENT_LEFT) + mat.getModel(modelHolder.segment_left()) .createInstances(left); - mat.getModel(AllBlockPartials.TRACK_SEGMENT_RIGHT) + mat.getModel(modelHolder.segment_right()) .createInstances(right); SegmentAngles[] segments = bc.getBakedSegments(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java index a34fa562d..adf3e9707 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java @@ -7,12 +7,13 @@ import java.util.List; import java.util.Set; import com.jozufozu.flywheel.util.Color; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.AllTags; import com.simibubi.create.CreateClient; import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer; import com.simibubi.create.content.logistics.trains.BezierConnection; 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.block.ProperWaterloggedBlock; 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.entity.BlockEntity; 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.HitResult; import net.minecraft.world.phys.HitResult.Type; @@ -58,6 +60,11 @@ import net.minecraftforge.items.ItemHandlerHelper; public class TrackPlacement { public static class PlacementInfo { + + public PlacementInfo(TrackMaterial material) { + this.trackMaterial = material; + } + BezierConnection curve = null; boolean valid = false; int end1Extent = 0; @@ -69,6 +76,7 @@ public class TrackPlacement { public int requiredPavement = 0; public boolean hasRequiredPavement = false; + public final TrackMaterial trackMaterial; // for visualisation Vec3 end1; @@ -108,7 +116,7 @@ public class TrackPlacement { && hoveringMaxed == maximiseTurn && lookAngle == hoveringAngle) return cached; - PlacementInfo info = new PlacementInfo(); + PlacementInfo info = new PlacementInfo(TrackMaterial.fromItem(stack.getItem())); hoveringMaxed = maximiseTurn; hoveringAngle = lookAngle; hoveringPos = pos2; @@ -192,7 +200,7 @@ public class TrackPlacement { BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z); info.curve = new BezierConnection(Couple.create(targetPos1, targetPos2), 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 @@ -281,10 +289,10 @@ public class TrackPlacement { if (skipCurve && !Mth.equal(ascend, 0)) { int hDistance = info.end1Extent; if (axis1.y == 0 || !Mth.equal(absAscend + 1, dist / axis1.length())) { - + if (axis1.y != 0 && axis1.y == -axis2.y) return info.withMessage("ascending_s_curve"); - + info.end1Extent = 0; double minHDistance = Math.max(absAscend < 4 ? absAscend * 4 : absAscend * 3, 6) / axis1.length(); if (hDistance < minHDistance) @@ -352,7 +360,7 @@ public class TrackPlacement { info.curve = skipCurve ? null : new BezierConnection(Couple.create(targetPos1, targetPos2), 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; @@ -397,7 +405,7 @@ public class TrackPlacement { continue; 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())) continue; if (isTrack ? foundTracks >= tracks : foundPavement >= pavement) @@ -445,10 +453,10 @@ public class TrackPlacement { BlockItem paveItem = (BlockItem) offhandItem.getItem(); paveTracks(level, info, paveItem, false); } - + if (info.curve != null && info.curve.getLength() > 29) AllAdvancements.LONG_BEND.awardTo(player); - + 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); } + 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, BlockPos targetPos1, BlockPos targetPos2, boolean simulate) { info.requiredTracks = 0; @@ -501,7 +521,8 @@ public class TrackPlacement { Vec3 offset = axis.scale(i); BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z); 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() .isReplaceable(); @@ -524,15 +545,16 @@ public class TrackPlacement { return info; if (!simulate) { + BlockState onto = info.trackMaterial.getTrackBlock().get().defaultBlockState(); BlockState stateAtPos = level.getBlockState(targetPos1); level.setBlock(targetPos1, ProperWaterloggedBlock.withWater(level, - (stateAtPos.getBlock() == state1.getBlock() ? stateAtPos : state1).setValue(TrackBlock.HAS_TE, true), - targetPos1), 3); + (AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state1, onto)) + .setValue(TrackBlock.HAS_TE, true), targetPos1), 3); stateAtPos = level.getBlockState(targetPos2); level.setBlock(targetPos2, ProperWaterloggedBlock.withWater(level, - (stateAtPos.getBlock() == state2.getBlock() ? stateAtPos : state2).setValue(TrackBlock.HAS_TE, true), - targetPos2), 3); + (AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state2, onto)) + .setValue(TrackBlock.HAS_TE, true), targetPos2), 3); } BlockEntity te1 = level.getBlockEntity(targetPos1); @@ -579,10 +601,10 @@ public class TrackPlacement { return; InteractionHand hand = InteractionHand.MAIN_HAND; - if (!AllBlocks.TRACK.isIn(stack)) { + if (!AllTags.AllBlockTags.TRACKS.matches(stack)) { stack = player.getOffhandItem(); hand = InteractionHand.OFF_HAND; - if (!AllBlocks.TRACK.isIn(stack)) + if (!AllTags.AllBlockTags.TRACKS.matches(stack)) return; } @@ -621,7 +643,7 @@ public class TrackPlacement { if (bhr.getDirection() == Direction.UP) { Vec3 lookVec = player.getLookAngle(); int lookAngle = (int) (22.5 + AngleHelper.deg(Mth.atan2(lookVec.z, lookVec.x)) % 360) / 8; - + if (!pos.equals(hintPos) || lookAngle != hintAngle) { hints = Couple.create(ArrayList::new); hintAngle = lookAngle; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java index 1ee412ea0..fdb66a005 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java @@ -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_MIDDLE; 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.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.GirderAngles; 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.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; @@ -66,7 +64,9 @@ public class TrackRenderer extends SafeTileEntityRenderer { SegmentAngles segment = segments[i]; 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()) .mulNormal(segment.tieTransform.normal()) .light(light) @@ -74,7 +74,7 @@ public class TrackRenderer extends SafeTileEntityRenderer { for (boolean first : Iterate.trueAndFalse) { 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()) .mulNormal(transform.normal()) .light(light) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java index 05431e8fd..317ca94a6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java @@ -9,6 +9,7 @@ import java.util.Set; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; 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.StructureTransform; import com.simibubi.create.content.logistics.trains.BezierConnection; @@ -112,6 +113,9 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE } 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); level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); notifyUpdate(); @@ -287,7 +291,7 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE .getLevel(boundLocation.getFirst()); if (otherLevel == null) return; - if (AllBlocks.TRACK.has(otherLevel.getBlockState(boundLocation.getSecond()))) + if (AllTags.AllBlockTags.TRACKS.matches(otherLevel.getBlockState(boundLocation.getSecond()))) otherLevel.destroyBlock(boundLocation.getSecond(), false); } } diff --git a/src/main/java/com/simibubi/create/events/CommonEvents.java b/src/main/java/com/simibubi/create/events/CommonEvents.java index b9a3baa8b..14cf82e86 100644 --- a/src/main/java/com/simibubi/create/events/CommonEvents.java +++ b/src/main/java/com/simibubi/create/events/CommonEvents.java @@ -62,9 +62,11 @@ import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.forgespi.language.IModFileInfo; import net.minecraftforge.forgespi.locating.IModFile; +import net.minecraftforge.registries.NewRegistryEvent; @EventBusSubscriber public class CommonEvents { @@ -90,7 +92,7 @@ public class CommonEvents { ToolboxHandler.playerLogin(player); Create.RAILWAYS.playerLogin(player); } - + @SubscribeEvent public static void playerLoggedOut(PlayerLoggedOutEvent event) { Player player = event.getPlayer(); @@ -166,7 +168,7 @@ public class CommonEvents { public static void onEntityEnterSection(EntityEvent.EnteringSection event) { CarriageEntityHandler.onEntityEnterSection(event); } - + @SubscribeEvent public static void addReloadListeners(AddReloadListenerEvent event) { event.addListener(RecipeFinder.LISTENER); @@ -248,7 +250,5 @@ public class CommonEvents { }); } } - } - } diff --git a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java index 8664b0a5e..676a47d1f 100644 --- a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java +++ b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java @@ -60,6 +60,7 @@ public class AllCommands { .then(CameraDistanceCommand.register()) .then(CameraAngleCommand.register()) .then(FlySpeedCommand.register()) + //.then(DebugValueCommand.register()) //.then(KillTPSCommand.register()) .build(); diff --git a/src/main/java/com/simibubi/create/foundation/command/DebugValueCommand.java b/src/main/java/com/simibubi/create/foundation/command/DebugValueCommand.java new file mode 100644 index 000000000..5272bdc59 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/DebugValueCommand.java @@ -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 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; + })); + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/CClient.java b/src/main/java/com/simibubi/create/foundation/config/CClient.java index 4fffd25fe..449c10a3f 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CClient.java +++ b/src/main/java/com/simibubi/create/foundation/config/CClient.java @@ -77,6 +77,7 @@ public class CClient extends ConfigBase { public final ConfigGroup trains = group(1, "trains", Comments.trains); public final ConfigFloat mountedZoomMultiplier = f(3, 0, "mountedZoomMultiplier", Comments.mountedZoomMultiplier); public final ConfigBool showTrackGraphOnF3 = b(false, "showTrackGraphOnF3", Comments.showTrackGraphOnF3); + public final ConfigBool showExtendedTrackGraphOnF3 = b(false, "showExtendedTrackGraphOnF3", Comments.showExtendedTrackGraphOnF3); @Override public String getName() { @@ -147,6 +148,7 @@ public class CClient extends ConfigBase { static String trains = "Railway related settings"; 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 showExtendedTrackGraphOnF3 = "Additionally display materials of a Rail Network while f3 debug mode is active"; } } diff --git a/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java b/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java index acf1ce517..c9971fb76 100644 --- a/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java +++ b/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java @@ -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.Shape; 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.foundation.block.BlockStressDefaults; import com.simibubi.create.foundation.block.ItemUseOverrides; @@ -80,6 +80,7 @@ public class BuilderTransformers { .build(); } + @SuppressWarnings("deprecation") public static NonNullUnaryOperator> bogey() { return b -> b.initialProperties(SharedProperties::softMetal) .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) @@ -88,7 +89,7 @@ public class BuilderTransformers { .blockstate((c, p) -> BlockStateGen.horizontalAxisBlock(c, p, s -> p.models() .getExistingFile(p.modLoc("block/track/bogey/top")))) .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 NonNullUnaryOperator> trapdoor(boolean orientable) { diff --git a/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java b/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java index e0200c3b5..7a51ce75a 100644 --- a/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java +++ b/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java @@ -16,8 +16,10 @@ import com.simibubi.create.CreateClient; import com.simibubi.create.content.AllSections; import com.simibubi.create.content.contraptions.fluids.VirtualFluid; 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.ConnectedTextureBehaviour; +import com.simibubi.create.foundation.utility.CreateRegistry; import com.simibubi.create.foundation.utility.RegisteredObjects; import com.tterrag.registrate.AbstractRegistrate; import com.tterrag.registrate.builders.BlockBuilder; diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java index ed44673e8..e3905f033 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java @@ -3,6 +3,8 @@ package com.simibubi.create.foundation.ponder.content; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; 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.ponder.PonderRegistrationHelper; 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.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.level.block.Blocks; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; + +import java.util.stream.Collectors; public class PonderIndex { @@ -303,7 +312,12 @@ public class PonderIndex { .addStoryBoard("rose_quartz_lamp", RedstoneScenes2::roseQuartzLamp); // Trains - HELPER.forComponents(AllBlocks.TRACK) + HELPER.forComponents(TrackMaterial.allBlocks().stream() + .map((trackSupplier) -> new BlockEntry( + // 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/portal", TrackScenes::portal) .addStoryBoard("train_track/chunks", TrackScenes::chunks); diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instruction/AnimateTileEntityInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instruction/AnimateTileEntityInstruction.java index cd65b8a36..b11242d80 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/instruction/AnimateTileEntityInstruction.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/instruction/AnimateTileEntityInstruction.java @@ -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.structureMovement.bearing.IBearingTileEntity; 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.PonderWorld; @@ -34,7 +34,7 @@ public class AnimateTileEntityInstruction extends TickingInstruction { public static AnimateTileEntityInstruction bogey(BlockPos location, float totalDelta, int ticks) { float movedPerTick = 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)), (w) -> 0f); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/Iterate.java b/src/main/java/com/simibubi/create/foundation/utility/Iterate.java index e8e541aa1..0e072cf38 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Iterate.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Iterate.java @@ -45,4 +45,13 @@ public class Iterate { public static List hereBelowAndAbove(BlockPos pos) { return Arrays.asList(pos, pos.below(), pos.above()); } + + public static T cycleValue(List 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); + } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java b/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java index 267a343eb..7bd30cf28 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java @@ -13,6 +13,7 @@ import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.IntTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.AABB; @@ -108,4 +109,12 @@ public class NBTHelper { 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)); + } + } diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/ItemOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/ItemOutline.java new file mode 100644 index 000000000..7f974cabb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/ItemOutline.java @@ -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(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java index dfeeb7dce..15a21615e 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java @@ -14,6 +14,7 @@ import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.AABB; 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) { if (outlines.containsKey(slot)) outlines.get(slot).ticksTillRemoval = 1; diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index 86e0d8237..20b959087 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -920,8 +920,14 @@ "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", - + "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" }