Logistical enhancements and fixes

- Arms can no longer insert into powered brass funnels
- Slight ArmInteractionPoint refactor
- Arms can now interact with Millstones, Basins, Jukeboxes, Crushing Wheels and the Mechanical Saw
- Fixed crash when logging into a world with a running mixer
- Arms now start to dance when one of their in or outputs is a running jukebox
- Arms can now be mounted on the ceiling
- Arms now always prefer the interaction points that were selected first
- Fixed belt funnels not updating their blockstate properly when transitioning from other funnel types
- Vertical funnels next to the end of a belt will now stall the belt when unable to collect incoming items
- Minor model & texture touch ups
- Arm no longer cancels player interaction when its empty handed
- Fixed chutes not vertically interacting with andesite funnels
This commit is contained in:
simibubi 2020-07-10 19:48:04 +02:00
parent 3902569cbd
commit 367296e6c1
44 changed files with 574 additions and 139 deletions

View file

@ -179,7 +179,7 @@ b7506b862d13b3f915c60d38bb7a20afc935f70a assets\create\blockstates\limestone_pil
69790737767e06f000c7824749c46664a123160e assets\create\blockstates\linear_chassis.json 69790737767e06f000c7824749c46664a123160e assets\create\blockstates\linear_chassis.json
c793ab3aa6cf09d8d6d4136757629689f0365771 assets\create\blockstates\linked_extractor.json c793ab3aa6cf09d8d6d4136757629689f0365771 assets\create\blockstates\linked_extractor.json
c5422866667331f1d5cf6753c0889747ee02762b assets\create\blockstates\linked_transposer.json c5422866667331f1d5cf6753c0889747ee02762b assets\create\blockstates\linked_transposer.json
e82e69ae4c7a784ef89fc5d954b2b01946746d48 assets\create\blockstates\mechanical_arm.json 3b3250d6e209403a93d025604a8081087965016e assets\create\blockstates\mechanical_arm.json
ddcf4bb281e046fbb1026b8f46a2cf12448598df assets\create\blockstates\mechanical_bearing.json ddcf4bb281e046fbb1026b8f46a2cf12448598df assets\create\blockstates\mechanical_bearing.json
5586beef2d9183dc34d8e8d2723620c0569592ae assets\create\blockstates\mechanical_crafter.json 5586beef2d9183dc34d8e8d2723620c0569592ae assets\create\blockstates\mechanical_crafter.json
044db7d50e19008bae8bf3325eac2ed0eb1ea6d2 assets\create\blockstates\mechanical_drill.json 044db7d50e19008bae8bf3325eac2ed0eb1ea6d2 assets\create\blockstates\mechanical_drill.json
@ -338,16 +338,16 @@ c77b46d8b459e5c7cc495393546f3fcca8a1fa1d assets\create\blockstates\weathered_lim
7f39521b211441f5c3e06d60c5978cebe16cacfb assets\create\blockstates\zinc_block.json 7f39521b211441f5c3e06d60c5978cebe16cacfb assets\create\blockstates\zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets\create\blockstates\zinc_ore.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets\create\blockstates\zinc_ore.json
541831ab0cf2f0222f0b7e42ec6c4b0ae636168d assets\create\lang\en_ud.json 541831ab0cf2f0222f0b7e42ec6c4b0ae636168d assets\create\lang\en_ud.json
fe44adfde38a1084754fe46b632811f90dcfcd7f assets\create\lang\en_us.json fd57d2d8144286e26033a087a501f45f2df9ea34 assets\create\lang\en_us.json
143b76ed828949330ef0e338fb6709c28561ac2d assets\create\lang\unfinished\de_de.json 87c28254c2acb462fe6a994f688a19e31a4c7a9d assets\create\lang\unfinished\de_de.json
95bf7693b162141c2c76617ed4e04bec474e2def assets\create\lang\unfinished\fr_fr.json 6cd93a72126063c634f49db190d4da545e5a6c43 assets\create\lang\unfinished\fr_fr.json
b3bf60afc7d0dea72a9d7d01df36d34affd6a296 assets\create\lang\unfinished\it_it.json 401d0b295988cfa31af1a94f8c50d86eb54cad0d assets\create\lang\unfinished\it_it.json
ef336e01a8e3ed3f8c2713c66476bcc708e3e3b0 assets\create\lang\unfinished\ja_jp.json 30f1189e1963d0a87a9505bfdac9b663ff9d09d1 assets\create\lang\unfinished\ja_jp.json
66c84c388e552ee8259eca2ab1009493456fc4d3 assets\create\lang\unfinished\ko_kr.json a56d5b51d410821b7993bdbfd1b141e51be11b54 assets\create\lang\unfinished\ko_kr.json
66b3140ef158b51208a191e6a90473fba5bb1749 assets\create\lang\unfinished\nl_nl.json e8a39cb4afc7668f2690bcacda1f06afd9c82579 assets\create\lang\unfinished\nl_nl.json
775702e0f3fbdab7ef8b1714e3cff69da56bd500 assets\create\lang\unfinished\pt_br.json 3876e40fbc9c6e8561cc761949a6fb9565a03fce assets\create\lang\unfinished\pt_br.json
7c4c4e7a00456f893538a6baa35d726a8786bf93 assets\create\lang\unfinished\ru_ru.json cc2c01ee69a5a394c9d6dc87f77e08f05adf38a7 assets\create\lang\unfinished\ru_ru.json
ce16074d9dc5d504f2a91b164258f0059163260b assets\create\lang\unfinished\zh_cn.json 7a8b2739021d2e1d2b563f2bed3a201bd3f1b00f assets\create\lang\unfinished\zh_cn.json
846200eb548d3bfa2e77b41039de159b4b6cfb45 assets\create\models\block\acacia_window.json 846200eb548d3bfa2e77b41039de159b4b6cfb45 assets\create\models\block\acacia_window.json
1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets\create\models\block\acacia_window_pane_noside.json 1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets\create\models\block\acacia_window_pane_noside.json
1763ea2c9b981d187f5031ba608f3d5d3be3986a assets\create\models\block\acacia_window_pane_noside_alt.json 1763ea2c9b981d187f5031ba608f3d5d3be3986a assets\create\models\block\acacia_window_pane_noside_alt.json
@ -1365,10 +1365,12 @@ e4e3c1bd7ecf501b40cffc26d8ad145ab4e89118 data\create\advancements\deployer.json
62f3610188f7dbd3900ab305edc2d06282705a38 data\create\advancements\goggles.json 62f3610188f7dbd3900ab305edc2d06282705a38 data\create\advancements\goggles.json
7e12b7ccb198ef0db7964b8cbef152d8347e333c data\create\advancements\its_alive.json 7e12b7ccb198ef0db7964b8cbef152d8347e333c data\create\advancements\its_alive.json
3d0fc63191ef507a018ef996ebf9406a523f3976 data\create\advancements\lava_wheel.json 3d0fc63191ef507a018ef996ebf9406a523f3976 data\create\advancements\lava_wheel.json
90393cdb6b699c9c0fd4dd9400159c3aa6911a6b data\create\advancements\mechanical_arm.json
786c2058805ceca3cd3970cc6e918560b54747f5 data\create\advancements\mechanical_drill.json 786c2058805ceca3cd3970cc6e918560b54747f5 data\create\advancements\mechanical_drill.json
41444ae151ce90d2d68dcda0ed3565f98509c594 data\create\advancements\mechanical_saw.json 41444ae151ce90d2d68dcda0ed3565f98509c594 data\create\advancements\mechanical_saw.json
9c7f0c2484a84ccf42166704475fafcb1f232ce6 data\create\advancements\millstone.json 9c7f0c2484a84ccf42166704475fafcb1f232ce6 data\create\advancements\millstone.json
704c7fc0ed357b1a116ffdc0b6c64fe64e337a5a data\create\advancements\mixer.json 704c7fc0ed357b1a116ffdc0b6c64fe64e337a5a data\create\advancements\mixer.json
8085b46ca0dd8c511841cabd88e51bff4baceefd data\create\advancements\musical_arm.json
a135eec618e448f440d9f42cc7a3e6c63fc45a71 data\create\advancements\overstressed.json a135eec618e448f440d9f42cc7a3e6c63fc45a71 data\create\advancements\overstressed.json
72025d8bf73ab8096c29f12d0c8d9a346f09cd64 data\create\advancements\polished_rose_quartz.json 72025d8bf73ab8096c29f12d0c8d9a346f09cd64 data\create\advancements\polished_rose_quartz.json
1e3cd82e36fd4bcd053d652a0eead4458ed7f315 data\create\advancements\press.json 1e3cd82e36fd4bcd053d652a0eead4458ed7f315 data\create\advancements\press.json

View file

@ -1,7 +1,11 @@
{ {
"variants": { "variants": {
"": { "ceiling=false": {
"model": "create:block/mechanical_arm/block" "model": "create:block/mechanical_arm/block"
},
"ceiling=true": {
"model": "create:block/mechanical_arm/block",
"x": 180
} }
} }
} }

View file

@ -457,6 +457,10 @@
"advancement.create.crafter.desc": "Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "Place and power some Mechanical Crafters",
"advancement.create.deployer": "Poke, Place, and Attack", "advancement.create.deployer": "Poke, Place, and Attack",
"advancement.create.deployer.desc": "Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "Pound It, Bro!", "advancement.create.fist_bump": "Pound It, Bro!",
"advancement.create.fist_bump.desc": "Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "A Pair of Giants", "advancement.create.crushing_wheel": "A Pair of Giants",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 777", "_": "Missing Localizations: 781",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack", "advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 380", "_": "Missing Localizations: 384",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack", "advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 364", "_": "Missing Localizations: 368",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack", "advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 359", "_": "Missing Localizations: 363",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack", "advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 364", "_": "Missing Localizations: 368",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack", "advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 714", "_": "Missing Localizations: 718",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack", "advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 784", "_": "Missing Localizations: 788",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack", "advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 778", "_": "Missing Localizations: 782",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack", "advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 40", "_": "Missing Localizations: 44",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "放置一些机械合成台并且为其供能", "advancement.create.crafter.desc": "放置一些机械合成台并且为其供能",
"advancement.create.deployer": "我就指着你了咋地?", "advancement.create.deployer": "我就指着你了咋地?",
"advancement.create.deployer.desc": "放置并且功能一个机械手。这可是你右手的完美复制品", "advancement.create.deployer.desc": "放置并且功能一个机械手。这可是你右手的完美复制品",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "来碰个拳,哥们~", "advancement.create.fist_bump": "来碰个拳,哥们~",
"advancement.create.fist_bump.desc": "使两个机械臂互相碰拳", "advancement.create.fist_bump.desc": "使两个机械臂互相碰拳",
"advancement.create.crushing_wheel": "一对大家伙", "advancement.create.crushing_wheel": "一对大家伙",

View file

@ -0,0 +1,46 @@
{
"parent": "create:brass_casing",
"display": {
"icon": {
"item": "create:mechanical_arm"
},
"title": {
"translate": "advancement.create.mechanical_arm"
},
"description": {
"translate": "advancement.create.mechanical_arm.desc"
},
"frame": "goal",
"show_toast": true,
"announce_to_chat": true,
"hidden": false
},
"criteria": {
"0": {
"trigger": "minecraft:placed_block",
"conditions": {
"block": "create:mechanical_arm"
}
},
"1": {
"trigger": "create:kinetic_block",
"conditions": {
"block": "create:mechanical_arm"
}
},
"2": {
"trigger": "create:mechanical_arm"
}
},
"requirements": [
[
"0"
],
[
"1"
],
[
"2"
]
]
}

View file

@ -0,0 +1,46 @@
{
"parent": "create:mechanical_arm",
"display": {
"icon": {
"item": "minecraft:music_disc_13"
},
"title": {
"translate": "advancement.create.musical_arm"
},
"description": {
"translate": "advancement.create.musical_arm.desc"
},
"frame": "task",
"show_toast": true,
"announce_to_chat": true,
"hidden": false
},
"criteria": {
"0": {
"trigger": "minecraft:placed_block",
"conditions": {
"block": "create:mechanical_arm"
}
},
"1": {
"trigger": "create:kinetic_block",
"conditions": {
"block": "create:mechanical_arm"
}
},
"2": {
"trigger": "create:musical_arm"
}
},
"requirements": [
[
"0"
],
[
"1"
],
[
"2"
]
]
}

View file

@ -700,7 +700,11 @@ public class AllBlocks {
public static final BlockEntry<ArmBlock> MECHANICAL_ARM = REGISTRATE.block("mechanical_arm", ArmBlock::new) public static final BlockEntry<ArmBlock> MECHANICAL_ARM = REGISTRATE.block("mechanical_arm", ArmBlock::new)
.initialProperties(SharedProperties::softMetal) .initialProperties(SharedProperties::softMetal)
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p))) .blockstate((c, p) -> p.getVariantBuilder(c.get())
.forAllStates(s -> ConfiguredModel.builder()
.modelFile(AssetLookup.partialBaseModel(c, p))
.rotationX(s.get(ArmBlock.CEILING) ? 180 : 0)
.build()))
.transform(StressConfigDefaults.setImpact(8.0)) .transform(StressConfigDefaults.setImpact(8.0))
.item(ArmItem::new) .item(ArmItem::new)
.transform(customItemModel()) .transform(customItemModel())

View file

@ -135,6 +135,8 @@ public class AllShapes {
.build(), .build(),
MECHANICAL_ARM = shape(2, 0, 2, 14, 10, 14).add(3, 0, 3, 13, 14, 13) MECHANICAL_ARM = shape(2, 0, 2, 14, 10, 14).add(3, 0, 3, 13, 14, 13)
.build(), .build(),
MECHANICAL_ARM_CEILING = shape(2, 6, 2, 14, 16, 14).add(3, 2, 3, 13, 16, 13)
.build(),
CHUTE = shape(1, 8, 1, 15, 16, 15).add(2, 0, 2, 14, 8, 14) CHUTE = shape(1, 8, 1, 15, 16, 15).add(2, 0, 2, 14, 8, 14)
.build(), .build(),
TANK = shape(1, 0, 1, 15, 16, 15).build(), TANK_TOP = shape(TANK_TOP_LID).add(TANK) TANK = shape(1, 0, 1, 15, 16, 15).build(), TANK_TOP = shape(TANK_TOP_LID).add(TANK)

View file

@ -118,10 +118,17 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
return super.write(compound); return super.write(compound);
} }
@Override
public void lazyTick() {
super.lazyTick();
if (world.isRemote && running && !basinItemInv.isPresent())
updateBasin();
}
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
if (runningTicks >= 40) { if (runningTicks >= 40) {
running = false; running = false;
runningTicks = 0; runningTicks = 0;
@ -156,6 +163,8 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
public void renderParticles() { public void renderParticles() {
IItemHandler itemHandler = basinItemInv.orElse(null); IItemHandler itemHandler = basinItemInv.orElse(null);
BasinInventory inv = (BasinInventory) itemHandler; BasinInventory inv = (BasinInventory) itemHandler;
if (inv == null)
return;
for (int slot = 0; slot < inv.getInputHandler() for (int slot = 0; slot < inv.getInputHandler()
.getSlots(); slot++) { .getSlots(); slot++) {

View file

@ -1,6 +1,11 @@
package com.simibubi.create.content.contraptions.fluids; package com.simibubi.create.content.contraptions.fluids;
import net.minecraft.fluid.Fluid; import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.annotation.Nonnull;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.ListNBT;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -8,11 +13,6 @@ import net.minecraftforge.common.util.NonNullConsumer;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler;
import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class CombinedFluidHandler implements IFluidHandler { public class CombinedFluidHandler implements IFluidHandler {
private final int capacity; private final int capacity;
private final FluidStack[] tanks; private final FluidStack[] tanks;

View file

@ -147,8 +147,8 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
return false; return false;
BlockState stateBelow = world.getBlockState(pos.down()); BlockState stateBelow = world.getBlockState(pos.down());
if (AllBlocks.BRASS_FUNNEL.has(stateBelow)) { if (stateBelow.getBlock() instanceof FunnelBlock) {
if (stateBelow.get(BrassFunnelBlock.POWERED)) if (stateBelow.has(BrassFunnelBlock.POWERED) && stateBelow.get(BrassFunnelBlock.POWERED))
return false; return false;
if (stateBelow.get(BrassFunnelBlock.FACING) != Direction.UP) if (stateBelow.get(BrassFunnelBlock.FACING) != Direction.UP)
return false; return false;
@ -187,9 +187,9 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
private boolean handleUpwardOutput(boolean simulate) { private boolean handleUpwardOutput(boolean simulate) {
BlockState stateAbove = world.getBlockState(pos.up()); BlockState stateAbove = world.getBlockState(pos.up());
if (AllBlocks.BRASS_FUNNEL.has(stateAbove)) { if (stateAbove.getBlock() instanceof FunnelBlock) {
if (!stateAbove.get(BrassFunnelBlock.POWERED) boolean powered = stateAbove.has(BrassFunnelBlock.POWERED) && stateAbove.get(BrassFunnelBlock.POWERED);
&& stateAbove.get(BrassFunnelBlock.FACING) == Direction.DOWN) { if (!powered && stateAbove.get(BrassFunnelBlock.FACING) == Direction.DOWN) {
ItemStack remainder = FunnelBlock.tryInsert(world, pos.up(), item, simulate); ItemStack remainder = FunnelBlock.tryInsert(world, pos.up(), item, simulate);
if (remainder.isEmpty()) { if (remainder.isEmpty()) {
if (!simulate) if (!simulate)

View file

@ -4,6 +4,8 @@ import com.simibubi.create.AllBlocks;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
public class AndesiteFunnelBlock extends FunnelBlock { public class AndesiteFunnelBlock extends FunnelBlock {
@ -12,14 +14,14 @@ public class AndesiteFunnelBlock extends FunnelBlock {
} }
@Override @Override
public BlockState getEquivalentBeltFunnel(BlockState state) { public BlockState getEquivalentBeltFunnel(IBlockReader world, BlockPos pos, BlockState state) {
Direction facing = state.get(FACING); Direction facing = state.get(FACING);
return AllBlocks.ANDESITE_BELT_FUNNEL.getDefaultState() return AllBlocks.ANDESITE_BELT_FUNNEL.getDefaultState()
.with(BeltFunnelBlock.HORIZONTAL_FACING, facing); .with(BeltFunnelBlock.HORIZONTAL_FACING, facing);
} }
@Override @Override
public BlockState getEquivalentChuteFunnel(BlockState state) { public BlockState getEquivalentChuteFunnel(IBlockReader world, BlockPos pos, BlockState state) {
Direction facing = state.get(FACING); Direction facing = state.get(FACING);
return AllBlocks.ANDESITE_CHUTE_FUNNEL.getDefaultState() return AllBlocks.ANDESITE_CHUTE_FUNNEL.getDefaultState()
.with(ChuteFunnelBlock.HORIZONTAL_FACING, facing); .with(ChuteFunnelBlock.HORIZONTAL_FACING, facing);

View file

@ -23,7 +23,6 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.ILightReader;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader; import net.minecraft.world.IWorldReader;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -55,9 +54,12 @@ public abstract class BeltFunnelBlock extends HorizontalInteractionFunnelBlock {
@Override @Override
public BlockState getStateForPlacement(BlockItemUseContext ctx) { public BlockState getStateForPlacement(BlockItemUseContext ctx) {
BlockState state = super.getStateForPlacement(ctx); BlockState state = super.getStateForPlacement(ctx);
World world = ctx.getWorld(); return getStateForPosition(ctx.getWorld(), ctx.getPos(), state, ctx.getFace());
BlockPos posBelow = ctx.getPos() }
.down();
public BlockState getStateForPosition(World world, BlockPos pos, BlockState defaultState, Direction facing) {
BlockState state = defaultState.with(HORIZONTAL_FACING, facing);
BlockPos posBelow = pos.down();
BlockState stateBelow = world.getBlockState(posBelow); BlockState stateBelow = world.getBlockState(posBelow);
if (!AllBlocks.BELT.has(stateBelow)) if (!AllBlocks.BELT.has(stateBelow))
return state; return state;
@ -68,8 +70,7 @@ public abstract class BeltFunnelBlock extends HorizontalInteractionFunnelBlock {
if (beltTileEntity.getSpeed() == 0) if (beltTileEntity.getSpeed() == 0)
return state; return state;
Direction movementFacing = beltTileEntity.getMovementFacing(); Direction movementFacing = beltTileEntity.getMovementFacing();
Direction funnelFacing = ctx.getFace(); return state.with(PUSHING, movementFacing == facing);
return state.with(PUSHING, movementFacing == funnelFacing);
} }
@Override @Override
@ -107,7 +108,7 @@ public abstract class BeltFunnelBlock extends HorizontalInteractionFunnelBlock {
return true; return true;
} }
public static BlockState updateShape(BlockState state, ILightReader world, BlockPos pos) { public static BlockState updateShape(BlockState state, IBlockReader world, BlockPos pos) {
state = state.with(SHAPE, Shape.RETRACTED); state = state.with(SHAPE, Shape.RETRACTED);
BlockState neighbour = world.getBlockState(pos.offset(state.get(HORIZONTAL_FACING))); BlockState neighbour = world.getBlockState(pos.offset(state.get(HORIZONTAL_FACING)));
if (canConnectTo(state, neighbour)) if (canConnectTo(state, neighbour))

View file

@ -10,6 +10,7 @@ import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World; import net.minecraft.world.World;
public class BrassFunnelBlock extends FunnelBlock { public class BrassFunnelBlock extends FunnelBlock {
@ -48,7 +49,7 @@ public class BrassFunnelBlock extends FunnelBlock {
} }
@Override @Override
public BlockState getEquivalentBeltFunnel(BlockState state) { public BlockState getEquivalentBeltFunnel(IBlockReader world, BlockPos pos, BlockState state) {
Direction facing = state.get(FACING); Direction facing = state.get(FACING);
return AllBlocks.BRASS_BELT_FUNNEL.getDefaultState() return AllBlocks.BRASS_BELT_FUNNEL.getDefaultState()
.with(BeltFunnelBlock.HORIZONTAL_FACING, facing) .with(BeltFunnelBlock.HORIZONTAL_FACING, facing)
@ -56,7 +57,7 @@ public class BrassFunnelBlock extends FunnelBlock {
} }
@Override @Override
public BlockState getEquivalentChuteFunnel(BlockState state) { public BlockState getEquivalentChuteFunnel(IBlockReader world, BlockPos pos, BlockState state) {
Direction facing = state.get(FACING); Direction facing = state.get(FACING);
return AllBlocks.BRASS_CHUTE_FUNNEL.getDefaultState() return AllBlocks.BRASS_CHUTE_FUNNEL.getDefaultState()
.with(ChuteFunnelBlock.HORIZONTAL_FACING, facing) .with(ChuteFunnelBlock.HORIZONTAL_FACING, facing)

View file

@ -61,8 +61,8 @@ public abstract class FunnelBlock extends ProperDirectionalBlock implements ITE<
BlockRayTraceResult hit) { BlockRayTraceResult hit) {
ItemStack heldItem = player.getHeldItem(handIn); ItemStack heldItem = player.getHeldItem(handIn);
boolean shouldntInsertItem = AllBlocks.MECHANICAL_ARM.isIn(heldItem); boolean shouldntInsertItem = AllBlocks.MECHANICAL_ARM.isIn(heldItem) || !canInsertIntoFunnel(state);
if (hit.getFace() == getFunnelFacing(state) && !shouldntInsertItem) { if (hit.getFace() == getFunnelFacing(state) && !shouldntInsertItem) {
if (!worldIn.isRemote) if (!worldIn.isRemote)
withTileEntityDo(worldIn, pos, te -> { withTileEntityDo(worldIn, pos, te -> {
@ -144,17 +144,17 @@ public abstract class FunnelBlock extends ProperDirectionalBlock implements ITE<
if (facing.getAxis() if (facing.getAxis()
.isHorizontal()) { .isHorizontal()) {
if (direction == Direction.DOWN) { if (direction == Direction.DOWN) {
BlockState equivalentFunnel = getEquivalentBeltFunnel(state); BlockState equivalentFunnel = getEquivalentBeltFunnel(null, null, state);
if (BeltFunnelBlock.isOnValidBelt(equivalentFunnel, world, pos)) if (BeltFunnelBlock.isOnValidBelt(equivalentFunnel, world, pos))
return equivalentFunnel; return BeltFunnelBlock.updateShape(equivalentFunnel, world, pos);
} }
if (direction == facing) { if (direction == facing) {
BlockState equivalentFunnel = getEquivalentChuteFunnel(state); BlockState equivalentFunnel = getEquivalentChuteFunnel(null, null, state);
if (ChuteFunnelBlock.isOnValidChute(equivalentFunnel, world, pos)) if (ChuteFunnelBlock.isOnValidChute(equivalentFunnel, world, pos))
return equivalentFunnel; return equivalentFunnel;
} }
if (direction == facing.getOpposite()) { if (direction == facing.getOpposite()) {
BlockState equivalentFunnel = getEquivalentChuteFunnel(state); BlockState equivalentFunnel = getEquivalentChuteFunnel(null, null, state);
if (ChuteFunnelBlock.isOnValidChute(equivalentFunnel, world, pos)) if (ChuteFunnelBlock.isOnValidChute(equivalentFunnel, world, pos))
return equivalentFunnel; return equivalentFunnel;
} }
@ -162,9 +162,9 @@ public abstract class FunnelBlock extends ProperDirectionalBlock implements ITE<
return state; return state;
} }
public abstract BlockState getEquivalentChuteFunnel(BlockState state); public abstract BlockState getEquivalentChuteFunnel(IBlockReader world, BlockPos pos, BlockState state);
public abstract BlockState getEquivalentBeltFunnel(BlockState state); public abstract BlockState getEquivalentBeltFunnel(IBlockReader world, BlockPos pos, BlockState state);
@Override @Override
public boolean isValidPosition(BlockState state, IWorldReader world, BlockPos pos) { public boolean isValidPosition(BlockState state, IWorldReader world, BlockPos pos) {

View file

@ -29,6 +29,8 @@ public class FunnelItem extends BlockItem {
@Override @Override
protected BlockState getStateForPlacement(BlockItemUseContext ctx) { protected BlockState getStateForPlacement(BlockItemUseContext ctx) {
World world = ctx.getWorld();
BlockPos pos = ctx.getPos();
BlockState state = super.getStateForPlacement(ctx); BlockState state = super.getStateForPlacement(ctx);
if (state == null) if (state == null)
return state; return state;
@ -40,9 +42,9 @@ public class FunnelItem extends BlockItem {
return state; return state;
FunnelBlock block = (FunnelBlock) getBlock(); FunnelBlock block = (FunnelBlock) getBlock();
Block beltFunnelBlock = block.getEquivalentBeltFunnel(state) Block beltFunnelBlock = block.getEquivalentBeltFunnel(world, pos, state)
.getBlock(); .getBlock();
Block chuteFunnelBlock = block.getEquivalentChuteFunnel(state) Block chuteFunnelBlock = block.getEquivalentChuteFunnel(world, pos, state)
.getBlock(); .getBlock();
BlockState equivalentBeltFunnel = beltFunnelBlock.getStateForPlacement(ctx) BlockState equivalentBeltFunnel = beltFunnelBlock.getStateForPlacement(ctx)
@ -52,8 +54,6 @@ public class FunnelItem extends BlockItem {
BlockState reversedChuteFunnel = equivalentChuteFunnel.rotate(Rotation.CLOCKWISE_180) BlockState reversedChuteFunnel = equivalentChuteFunnel.rotate(Rotation.CLOCKWISE_180)
.cycle(ChuteFunnelBlock.PUSHING); .cycle(ChuteFunnelBlock.PUSHING);
World world = ctx.getWorld();
BlockPos pos = ctx.getPos();
if (BeltFunnelBlock.isOnValidBelt(equivalentBeltFunnel, world, pos)) if (BeltFunnelBlock.isOnValidBelt(equivalentBeltFunnel, world, pos))
return BeltFunnelBlock.updateShape(equivalentBeltFunnel, world, pos); return BeltFunnelBlock.updateShape(equivalentBeltFunnel, world, pos);
if (ChuteFunnelBlock.isOnValidChute(equivalentChuteFunnel, world, pos)) if (ChuteFunnelBlock.isOnValidChute(equivalentChuteFunnel, world, pos))

View file

@ -34,6 +34,7 @@ public class FunnelTileEntity extends SmartTileEntity {
private FilteringBehaviour filtering; private FilteringBehaviour filtering;
private InsertingBehaviour inserting; private InsertingBehaviour inserting;
private ExtractingBehaviour extracting; private ExtractingBehaviour extracting;
private DirectBeltInputBehaviour beltInputBehaviour;
int sendFlap; int sendFlap;
InterpolatedChasingValue flap; InterpolatedChasingValue flap;
@ -183,6 +184,15 @@ public class FunnelTileEntity extends SmartTileEntity {
filtering.onlyActiveWhen(this::supportsFiltering); filtering.onlyActiveWhen(this::supportsFiltering);
behaviours.add(filtering); behaviours.add(filtering);
beltInputBehaviour = new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput)
.setInsertionHandler(this::handleDirectBeltInput);
behaviours.add(beltInputBehaviour);
}
private boolean supportsDirectBeltInput(Direction side) {
BlockState blockState = getBlockState();
return blockState != null && blockState.getBlock() instanceof FunnelBlock
&& blockState.get(FunnelBlock.FACING) == Direction.UP;
} }
private boolean supportsFiltering() { private boolean supportsFiltering() {
@ -190,6 +200,15 @@ public class FunnelTileEntity extends SmartTileEntity {
return blockState != null && blockState.has(BlockStateProperties.POWERED); return blockState != null && blockState.has(BlockStateProperties.POWERED);
} }
private ItemStack handleDirectBeltInput(TransportedItemStack stack, Direction side, boolean simulate) {
ItemStack inserted = stack.stack;
if (!filtering.test(inserted))
return inserted;
if (determineCurrentMode() == Mode.PAUSED)
return inserted;
return inserting.insert(inserted, simulate);
}
public void flap(boolean inward) { public void flap(boolean inward) {
sendFlap = inward ? 1 : -1; sendFlap = inward ? 1 : -1;
sendData(); sendData();

View file

@ -86,9 +86,12 @@ public abstract class HorizontalInteractionFunnelBlock extends HorizontalBlock i
@Override @Override
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbour, IWorld world, public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbour, IWorld world,
BlockPos pos, BlockPos p_196271_6_) { BlockPos pos, BlockPos p_196271_6_) {
if (!canStillInteract(state, world, pos)) if (!canStillInteract(state, world, pos)) {
return parent.getDefaultState() BlockState parentState = parent.getDefaultState();
.with(FunnelBlock.FACING, state.get(HORIZONTAL_FACING)); if (state.has(POWERED) && state.get(POWERED))
parentState = parentState.with(POWERED, true);
return parentState.with(FunnelBlock.FACING, state.get(HORIZONTAL_FACING));
}
return state; return state;
} }

View file

@ -35,7 +35,7 @@ public class CreativeCrateInventory implements IItemHandler {
public ItemStack extractItem(int slot, int amount, boolean simulate) { public ItemStack extractItem(int slot, int amount, boolean simulate) {
ItemStack filter = te.filter.getFilter().copy(); ItemStack filter = te.filter.getFilter().copy();
if (!filter.isEmpty()) if (!filter.isEmpty())
filter.setCount(amount); filter.setCount(Math.min(filter.getMaxStackSize(), amount));
return filter; return filter;
} }

View file

@ -12,7 +12,7 @@ import net.minecraft.util.math.Vec3d;
public class ArmAngleTarget { public class ArmAngleTarget {
static ArmAngleTarget NO_TARGET = new ArmAngleTarget(); static ArmAngleTarget NO_TARGET = new ArmAngleTarget();
float baseAngle; float baseAngle;
float lowerArmAngle; float lowerArmAngle;
float upperArmAngle; float upperArmAngle;
@ -24,10 +24,13 @@ public class ArmAngleTarget {
headAngle = -15; headAngle = -15;
} }
public ArmAngleTarget(BlockPos armPos, Vec3d pointTarget, Direction clawFacing) { public ArmAngleTarget(BlockPos armPos, Vec3d pointTarget, Direction clawFacing, boolean ceiling) {
// if (ceiling)
// clawFacing = clawFacing.getOpposite();
Vec3d target = pointTarget; Vec3d target = pointTarget;
Vec3d origin = VecHelper.getCenterOf(armPos) Vec3d origin = VecHelper.getCenterOf(armPos)
.add(0, 4 / 16f, 0); .add(0, ceiling ? -4 / 16f : 4 / 16f, 0);
Vec3d clawTarget = target; Vec3d clawTarget = target;
target = target.add(new Vec3d(clawFacing.getOpposite() target = target.add(new Vec3d(clawFacing.getOpposite()
.getDirectionVec()).scale(.5f)); .getDirectionVec()).scale(.5f));
@ -37,6 +40,11 @@ public class ArmAngleTarget {
.length(); .length();
float baseAngle = AngleHelper.deg(MathHelper.atan2(diff.x, diff.z)) + 180; float baseAngle = AngleHelper.deg(MathHelper.atan2(diff.x, diff.z)) + 180;
if (ceiling) {
diff = diff.mul(1, -1, 1);
baseAngle = 180 - baseAngle;
}
float alphaOffset = AngleHelper.deg(MathHelper.atan2(diff.y, horizontalDistance)); float alphaOffset = AngleHelper.deg(MathHelper.atan2(diff.y, horizontalDistance));
float a = 18 / 16f; // lower arm length float a = 18 / 16f; // lower arm length
@ -61,8 +69,13 @@ public class ArmAngleTarget {
headPos = VecHelper.rotate(headPos.add(0, b, 0), beta + 180, Axis.X); headPos = VecHelper.rotate(headPos.add(0, b, 0), beta + 180, Axis.X);
headPos = VecHelper.rotate(headPos.add(0, a, 0), alpha - 90, Axis.X); headPos = VecHelper.rotate(headPos.add(0, a, 0), alpha - 90, Axis.X);
headPos = VecHelper.rotate(headPos, baseAngle, Axis.Y); headPos = VecHelper.rotate(headPos, baseAngle, Axis.Y);
headPos = VecHelper.rotate(headPos, ceiling ? 180 : 0, Axis.X);
headPos = headPos.add(origin); headPos = headPos.add(origin);
Vec3d headDiff = clawTarget.subtract(headPos); Vec3d headDiff = clawTarget.subtract(headPos);
if (ceiling)
headDiff = headDiff.mul(1, -1, 1);
float horizontalHeadDistance = (float) headDiff.mul(1, 0, 1) float horizontalHeadDistance = (float) headDiff.mul(1, 0, 1)
.length(); .length();
float headAngle = float headAngle =

View file

@ -1,17 +1,24 @@
package com.simibubi.create.content.logistics.block.mechanicalArm; package com.simibubi.create.content.logistics.block.mechanicalArm;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.simibubi.create.AllShapes; import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.KineticBlock; import com.simibubi.create.content.contraptions.base.KineticBlock;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase;
import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.block.ITE;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.InventoryHelper; import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType; import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -24,8 +31,21 @@ import net.minecraft.world.World;
public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> { public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
public static final BooleanProperty CEILING = BooleanProperty.create("ceiling");
public ArmBlock(Properties properties) { public ArmBlock(Properties properties) {
super(properties); super(properties);
setDefaultState(getDefaultState().with(CEILING, false));
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> p_206840_1_) {
super.fillStateContainer(p_206840_1_.add(CEILING));
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext ctx) {
return getDefaultState().with(CEILING, ctx.getFace() == Direction.DOWN);
} }
@Override @Override
@ -34,9 +54,9 @@ public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
} }
@Override @Override
public VoxelShape getShape(BlockState p_220053_1_, IBlockReader p_220053_2_, BlockPos p_220053_3_, public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
ISelectionContext p_220053_4_) { ISelectionContext p_220053_4_) {
return AllShapes.MECHANICAL_ARM; return state.get(CEILING) ? AllShapes.MECHANICAL_ARM_CEILING : AllShapes.MECHANICAL_ARM;
} }
@Override @Override
@ -70,18 +90,21 @@ public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
@Override @Override
public ActionResultType onUse(BlockState p_225533_1_, World world, BlockPos pos, PlayerEntity player, public ActionResultType onUse(BlockState p_225533_1_, World world, BlockPos pos, PlayerEntity player,
Hand p_225533_5_, BlockRayTraceResult p_225533_6_) { Hand p_225533_5_, BlockRayTraceResult p_225533_6_) {
if (world.isRemote) MutableBoolean success = new MutableBoolean(false);
return ActionResultType.SUCCESS;
withTileEntityDo(world, pos, te -> { withTileEntityDo(world, pos, te -> {
if (te.heldItem.isEmpty()) if (te.heldItem.isEmpty())
return; return;
success.setTrue();
if (world.isRemote)
return;
player.inventory.placeItemBackInInventory(world, te.heldItem); player.inventory.placeItemBackInInventory(world, te.heldItem);
te.heldItem = ItemStack.EMPTY; te.heldItem = ItemStack.EMPTY;
te.phase = Phase.SEARCH_INPUTS; te.phase = Phase.SEARCH_INPUTS;
te.markDirty(); te.markDirty();
te.sendData(); te.sendData();
}); });
return ActionResultType.SUCCESS;
return success.booleanValue() ? ActionResultType.SUCCESS : ActionResultType.PASS;
} }
} }

View file

@ -1,12 +1,17 @@
package com.simibubi.create.content.logistics.block.mechanicalArm; package com.simibubi.create.content.logistics.block.mechanicalArm;
import java.util.function.Supplier;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.saw.SawBlock;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; import com.simibubi.create.content.logistics.block.funnel.FunnelBlock;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InsertingBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InsertingBehaviour;
@ -14,9 +19,14 @@ import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.JukeboxBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.JukeboxTileEntity;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -43,6 +53,19 @@ public abstract class ArmInteractionPoint {
private LazyOptional<IItemHandler> cachedHandler; private LazyOptional<IItemHandler> cachedHandler;
private ArmAngleTarget cachedAngles; private ArmAngleTarget cachedAngles;
private static ImmutableMap<ArmInteractionPoint, Supplier<ArmInteractionPoint>> POINTS =
ImmutableMap.<ArmInteractionPoint, Supplier<ArmInteractionPoint>>builder()
.put(new Belt(), Belt::new)
.put(new Depot(), Depot::new)
.put(new Saw(), Saw::new)
.put(new Chute(), Chute::new)
.put(new Jukebox(), Jukebox::new)
.put(new Basin(), Basin::new)
.put(new Millstone(), Millstone::new)
.put(new Funnel(), Funnel::new)
.put(new CrushingWheels(), CrushingWheels::new)
.build();
public ArmInteractionPoint() { public ArmInteractionPoint() {
cachedHandler = LazyOptional.empty(); cachedHandler = LazyOptional.empty();
} }
@ -66,16 +89,19 @@ public abstract class ArmInteractionPoint {
return Direction.DOWN; return Direction.DOWN;
} }
abstract boolean isValid(BlockState state); abstract boolean isValid(IBlockReader reader, BlockPos pos, BlockState state);
static boolean isInteractable(BlockState state) { static boolean isInteractable(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.DEPOT.has(state) || AllBlocks.BELT.has(state) || AllBlocks.CHUTE.has(state) for (ArmInteractionPoint armInteractionPoint : POINTS.keySet())
|| state.getBlock() instanceof FunnelBlock; if (armInteractionPoint.isValid(reader, pos, state))
return true;
return false;
} }
ArmAngleTarget getTargetAngles(BlockPos armPos) { ArmAngleTarget getTargetAngles(BlockPos armPos, boolean ceiling) {
if (cachedAngles == null) if (cachedAngles == null)
cachedAngles = new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection()); cachedAngles =
new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection(), ceiling);
return cachedAngles; return cachedAngles;
} }
@ -120,15 +146,10 @@ public abstract class ArmInteractionPoint {
BlockState state = world.getBlockState(pos); BlockState state = world.getBlockState(pos);
ArmInteractionPoint point = null; ArmInteractionPoint point = null;
if (AllBlocks.DEPOT.has(state)) for (ArmInteractionPoint armInteractionPoint : POINTS.keySet())
point = new Depot(); if (armInteractionPoint.isValid(world, pos, state))
if (AllBlocks.BELT.has(state) && !(world.getBlockState(pos.up()) point = POINTS.get(armInteractionPoint)
.getBlock() instanceof BeltTunnelBlock)) .get();
point = new Belt();
if (AllBlocks.CHUTE.has(state))
point = new Chute();
if (state.getBlock() instanceof FunnelBlock)
point = new Funnel();
if (point != null) { if (point != null) {
point.state = state; point.state = state;
@ -155,6 +176,15 @@ public abstract class ArmInteractionPoint {
return interactionPoint; return interactionPoint;
} }
static abstract class TopFaceArmInteractionPoint extends ArmInteractionPoint {
@Override
Vec3d getInteractionPositionVector() {
return new Vec3d(pos).add(.5f, 1, .5f);
}
}
static class Depot extends ArmInteractionPoint { static class Depot extends ArmInteractionPoint {
@Override @Override
@ -163,29 +193,117 @@ public abstract class ArmInteractionPoint {
} }
@Override @Override
boolean isValid(BlockState state) { boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.DEPOT.has(state); return AllBlocks.DEPOT.has(state);
} }
} }
static class Saw extends Depot {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.MECHANICAL_SAW.has(state) && state.get(SawBlock.RUNNING)
&& state.get(SawBlock.FACING) == Direction.UP;
}
}
static class Millstone extends ArmInteractionPoint {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.MILLSTONE.has(state);
}
}
static class CrushingWheels extends TopFaceArmInteractionPoint {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.CRUSHING_WHEEL_CONTROLLER.has(state);
}
}
static class Basin extends ArmInteractionPoint {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.BASIN.has(state);
}
}
static class Jukebox extends TopFaceArmInteractionPoint {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return state.getBlock() instanceof JukeboxBlock;
}
@Override
int getSlotCount(World world) {
return 1;
}
@Override
ItemStack insert(World world, ItemStack stack, boolean simulate) {
TileEntity tileEntity = world.getTileEntity(pos);
if (!(tileEntity instanceof JukeboxTileEntity))
return stack;
if (!(state.getBlock() instanceof JukeboxBlock))
return stack;
JukeboxBlock jukeboxBlock = (JukeboxBlock) state.getBlock();
JukeboxTileEntity jukeboxTE = (JukeboxTileEntity) tileEntity;
if (!jukeboxTE.getRecord()
.isEmpty())
return stack;
ItemStack remainder = stack.copy();
ItemStack toInsert = remainder.split(1);
if (!simulate && !world.isRemote) {
jukeboxBlock.insertRecord(world, pos, state, toInsert);
world.playEvent((PlayerEntity) null, 1010, pos, Item.getIdFromItem(toInsert.getItem()));
AllTriggers.triggerForNearbyPlayers(AllTriggers.MUSICAL_ARM, world, pos, 10);
}
return remainder;
}
@Override
ItemStack extract(World world, int slot, int amount, boolean simulate) {
TileEntity tileEntity = world.getTileEntity(pos);
if (!(tileEntity instanceof JukeboxTileEntity))
return ItemStack.EMPTY;
if (!(state.getBlock() instanceof JukeboxBlock))
return ItemStack.EMPTY;
JukeboxTileEntity jukeboxTE = (JukeboxTileEntity) tileEntity;
ItemStack itemstack = jukeboxTE.getRecord();
if (itemstack.isEmpty())
return ItemStack.EMPTY;
if (!simulate && !world.isRemote) {
world.playEvent(1010, pos, 0);
jukeboxTE.clear();
world.setBlockState(pos, state.with(JukeboxBlock.HAS_RECORD, false), 2);
}
return itemstack;
}
}
static class Belt extends Depot { static class Belt extends Depot {
@Override @Override
boolean isValid(BlockState state) { boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.BELT.has(state); return AllBlocks.BELT.has(state) && !(reader.getBlockState(pos.up())
.getBlock() instanceof BeltTunnelBlock);
} }
} }
static class Chute extends ArmInteractionPoint { static class Chute extends TopFaceArmInteractionPoint {
@Override @Override
Vec3d getInteractionPositionVector() { boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return new Vec3d(pos).add(.5f, 1, .5f);
}
@Override
boolean isValid(BlockState state) {
return AllBlocks.CHUTE.has(state); return AllBlocks.CHUTE.has(state);
} }
} }
@ -219,6 +337,9 @@ public abstract class ArmInteractionPoint {
ItemStack insert(World world, ItemStack stack, boolean simulate) { ItemStack insert(World world, ItemStack stack, boolean simulate) {
FilteringBehaviour filtering = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE); FilteringBehaviour filtering = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE);
InsertingBehaviour inserter = TileEntityBehaviour.get(world, pos, InsertingBehaviour.TYPE); InsertingBehaviour inserter = TileEntityBehaviour.get(world, pos, InsertingBehaviour.TYPE);
BlockState state = world.getBlockState(pos);
if (state.has(BlockStateProperties.POWERED) && state.get(BlockStateProperties.POWERED))
return stack;
if (inserter == null) if (inserter == null)
return stack; return stack;
if (filtering != null && !filtering.test(stack)) if (filtering != null && !filtering.test(stack))
@ -227,7 +348,7 @@ public abstract class ArmInteractionPoint {
} }
@Override @Override
boolean isValid(BlockState state) { boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return state.getBlock() instanceof FunnelBlock; return state.getBlock() instanceof FunnelBlock;
} }

View file

@ -1,9 +1,9 @@
package com.simibubi.create.content.logistics.block.mechanicalArm; package com.simibubi.create.content.logistics.block.mechanicalArm;
import java.util.HashMap; import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.List;
import java.util.Map.Entry;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
@ -30,7 +30,7 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@EventBusSubscriber(value = Dist.CLIENT) @EventBusSubscriber(value = Dist.CLIENT)
public class ArmInteractionPointHandler { public class ArmInteractionPointHandler {
static Map<BlockPos, ArmInteractionPoint> currentSelection = new HashMap<>(); static List<ArmInteractionPoint> currentSelection = new ArrayList<>();
static ItemStack currentItem; static ItemStack currentItem;
static long lastBlockPos = -1; static long lastBlockPos = -1;
@ -44,15 +44,17 @@ public class ArmInteractionPointHandler {
if (!world.isRemote) if (!world.isRemote)
return; return;
if (!currentSelection.containsKey(pos)) { ArmInteractionPoint selected = getSelected(pos);
if (selected == null) {
ArmInteractionPoint point = ArmInteractionPoint.createAt(world, pos); ArmInteractionPoint point = ArmInteractionPoint.createAt(world, pos);
if (point == null) if (point == null)
return; return;
currentSelection.put(pos, point); selected = point;
put(point);
} }
currentSelection.get(pos) selected.cycleMode();
.cycleMode();
event.setCanceled(true); event.setCanceled(true);
event.setCancellationResult(ActionResultType.SUCCESS); event.setCancellationResult(ActionResultType.SUCCESS);
} }
@ -64,7 +66,7 @@ public class ArmInteractionPointHandler {
if (!event.getWorld().isRemote) if (!event.getWorld().isRemote)
return; return;
BlockPos pos = event.getPos(); BlockPos pos = event.getPos();
if (currentSelection.remove(pos) != null) { if (remove(pos) != null) {
event.setCanceled(true); event.setCanceled(true);
event.setCancellationResult(ActionResultType.SUCCESS); event.setCancellationResult(ActionResultType.SUCCESS);
} }
@ -73,7 +75,7 @@ public class ArmInteractionPointHandler {
public static void flushSettings(BlockPos pos) { public static void flushSettings(BlockPos pos) {
if (currentItem == null) if (currentItem == null)
return; return;
AllPackets.channel.sendToServer(new ArmPlacementPacket(currentSelection.values(), pos)); AllPackets.channel.sendToServer(new ArmPlacementPacket(currentSelection, pos));
currentSelection.clear(); currentSelection.clear();
currentItem = null; currentItem = null;
} }
@ -100,7 +102,7 @@ public class ArmInteractionPointHandler {
} }
private static void checkForWrench(ItemStack heldItem) { private static void checkForWrench(ItemStack heldItem) {
if(!AllItems.WRENCH.isIn(heldItem)) { if (!AllItems.WRENCH.isIn(heldItem)) {
return; return;
} }
@ -122,8 +124,8 @@ public class ArmInteractionPointHandler {
if (lastBlockPos == -1 || lastBlockPos != pos.toLong()) { if (lastBlockPos == -1 || lastBlockPos != pos.toLong()) {
currentSelection.clear(); currentSelection.clear();
ArmTileEntity arm = (ArmTileEntity) te; ArmTileEntity arm = (ArmTileEntity) te;
arm.inputs.forEach(point -> currentSelection.put(point.pos, point)); arm.inputs.forEach(ArmInteractionPointHandler::put);
arm.outputs.forEach(point -> currentSelection.put(point.pos, point)); arm.outputs.forEach(ArmInteractionPointHandler::put);
lastBlockPos = pos.toLong(); lastBlockPos = pos.toLong();
} }
@ -132,16 +134,14 @@ public class ArmInteractionPointHandler {
} }
} }
private static void drawOutlines(Map<BlockPos, ArmInteractionPoint> selection) { private static void drawOutlines(Collection<ArmInteractionPoint> selection) {
World world = Minecraft.getInstance().world; World world = Minecraft.getInstance().world;
for (Iterator<Entry<BlockPos, ArmInteractionPoint>> iterator = selection.entrySet() for (Iterator<ArmInteractionPoint> iterator = selection.iterator(); iterator.hasNext();) {
.iterator(); iterator.hasNext();) { ArmInteractionPoint point = iterator.next();
Entry<BlockPos, ArmInteractionPoint> entry = iterator.next(); BlockPos pos = point.pos;
BlockPos pos = entry.getKey();
BlockState state = world.getBlockState(pos); BlockState state = world.getBlockState(pos);
ArmInteractionPoint point = entry.getValue();
if (!point.isValid(state)) { if (!point.isValid(world, pos, state)) {
iterator.remove(); iterator.remove();
continue; continue;
} }
@ -158,4 +158,23 @@ public class ArmInteractionPointHandler {
} }
} }
private static void put(ArmInteractionPoint point) {
currentSelection.add(point);
}
private static ArmInteractionPoint remove(BlockPos pos) {
ArmInteractionPoint result = getSelected(pos);
if (result != null)
currentSelection.remove(result);
return result;
}
private static ArmInteractionPoint getSelected(BlockPos pos) {
for (ArmInteractionPoint point : currentSelection) {
if (point.pos.equals(pos))
return point;
}
return null;
}
} }

View file

@ -22,8 +22,9 @@ public class ArmItem extends BlockItem {
@Override @Override
public ActionResultType onItemUse(ItemUseContext ctx) { public ActionResultType onItemUse(ItemUseContext ctx) {
if (ArmInteractionPoint.isInteractable(ctx.getWorld() World world = ctx.getWorld();
.getBlockState(ctx.getPos()))) BlockPos pos = ctx.getPos();
if (ArmInteractionPoint.isInteractable(world, pos, world.getBlockState(pos)))
return ActionResultType.SUCCESS; return ActionResultType.SUCCESS;
return super.onItemUse(ctx); return super.onItemUse(ctx);
} }
@ -37,9 +38,9 @@ public class ArmItem extends BlockItem {
} }
@Override @Override
public boolean canPlayerBreakBlockWhileHolding(BlockState state, World p_195938_2_, BlockPos p_195938_3_, public boolean canPlayerBreakBlockWhileHolding(BlockState state, World world, BlockPos pos,
PlayerEntity p_195938_4_) { PlayerEntity p_195938_4_) {
return !ArmInteractionPoint.isInteractable(state); return !ArmInteractionPoint.isInteractable(world, pos, state);
} }
} }

View file

@ -5,6 +5,9 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.ColorHelper;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
@ -18,6 +21,7 @@ import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.MathHelper;
public class ArmRenderer extends KineticTileEntityRenderer { public class ArmRenderer extends KineticTileEntityRenderer {
@ -35,6 +39,21 @@ public class ArmRenderer extends KineticTileEntityRenderer {
MatrixStacker msr = MatrixStacker.of(ms); MatrixStacker msr = MatrixStacker.of(ms);
int color = 0xFFFFFF; int color = 0xFFFFFF;
float baseAngle = arm.baseAngle.get(pt);
float lowerArmAngle = arm.lowerArmAngle.get(pt) - 135;
float upperArmAngle = arm.upperArmAngle.get(pt) - 90;
float headAngle = arm.headAngle.get(pt);
boolean rave = te instanceof ArmTileEntity && ((ArmTileEntity) te).phase == Phase.DANCING;
float renderTick = AnimationTickHolder.getRenderTick() + (te.hashCode() % 64);
if (rave) {
baseAngle = (renderTick * 10) % 360;
lowerArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 4) + 1) / 2, -45, 15);
upperArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 8) + 1) / 4, -45, 95);
headAngle = -lowerArmAngle;
color = ColorHelper.rainbowColor(AnimationTickHolder.ticks * 100);
}
ms.push(); ms.push();
SuperByteBuffer base = AllBlockPartials.ARM_BASE.renderOn(blockState).light(light); SuperByteBuffer base = AllBlockPartials.ARM_BASE.renderOn(blockState).light(light);
@ -45,24 +64,27 @@ public class ArmRenderer extends KineticTileEntityRenderer {
SuperByteBuffer clawGrip = AllBlockPartials.ARM_CLAW_GRIP.renderOn(blockState).light(light); SuperByteBuffer clawGrip = AllBlockPartials.ARM_CLAW_GRIP.renderOn(blockState).light(light);
msr.centre(); msr.centre();
if (blockState.get(ArmBlock.CEILING))
msr.rotateX(180);
ms.translate(0, 4 / 16d, 0); ms.translate(0, 4 / 16d, 0);
msr.rotateY(arm.baseAngle.get(pt)); msr.rotateY(baseAngle);
base.renderInto(ms, builder); base.renderInto(ms, builder);
ms.translate(0, 1 / 16d, -2 / 16d); ms.translate(0, 1 / 16d, -2 / 16d);
msr.rotateX(arm.lowerArmAngle.get(pt) - 135); msr.rotateX(lowerArmAngle);
ms.translate(0, -1 / 16d, 0); ms.translate(0, -1 / 16d, 0);
lowerBody.color(color) lowerBody.color(color)
.renderInto(ms, builder); .renderInto(ms, builder);
ms.translate(0, 12 / 16d, 12 / 16d); ms.translate(0, 12 / 16d, 12 / 16d);
msr.rotateX(arm.upperArmAngle.get(pt) - 90); msr.rotateX(upperArmAngle);
upperBody.color(color) upperBody.color(color)
.renderInto(ms, builder); .renderInto(ms, builder);
ms.translate(0, 11 / 16d, -11 / 16d); ms.translate(0, 11 / 16d, -11 / 16d);
msr.rotateX(arm.headAngle.get(pt)); msr.rotateX(headAngle);
head.renderInto(ms, builder); head.renderInto(ms, builder);
ms.translate(0, 0, -4 / 16d); ms.translate(0, 0, -4 / 16d);

View file

@ -6,11 +6,15 @@ import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Jukebox;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.gui.widgets.InterpolatedAngle; import com.simibubi.create.foundation.gui.widgets.InterpolatedAngle;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.block.BlockState;
import net.minecraft.block.JukeboxBlock;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT; import net.minecraft.nbt.INBT;
@ -43,7 +47,7 @@ public class ArmTileEntity extends KineticTileEntity {
boolean updateInteractionPoints; boolean updateInteractionPoints;
enum Phase { enum Phase {
SEARCH_INPUTS, MOVE_TO_INPUT, SEARCH_OUTPUTS, MOVE_TO_OUTPUT, IDLE SEARCH_INPUTS, MOVE_TO_INPUT, SEARCH_OUTPUTS, MOVE_TO_OUTPUT, DANCING
} }
public ArmTileEntity(TileEntityType<?> typeIn) { public ArmTileEntity(TileEntityType<?> typeIn) {
@ -86,12 +90,34 @@ public class ArmTileEntity extends KineticTileEntity {
return; return;
if (chasedPointProgress < .5f) if (chasedPointProgress < .5f)
return; return;
if (phase == Phase.SEARCH_INPUTS) if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) {
checkForMusic();
searchForItem(); searchForItem();
}
if (phase == Phase.SEARCH_OUTPUTS) if (phase == Phase.SEARCH_OUTPUTS)
searchForDestination(); searchForDestination();
} }
private void checkForMusic() {
boolean hasMusic = checkForMusicAmong(inputs) || checkForMusicAmong(outputs);
if (hasMusic != (phase == Phase.DANCING)) {
phase = hasMusic ? Phase.DANCING : Phase.SEARCH_INPUTS;
markDirty();
sendData();
}
}
private boolean checkForMusicAmong(List<ArmInteractionPoint> list) {
for (ArmInteractionPoint armInteractionPoint : list) {
if (!(armInteractionPoint instanceof Jukebox))
continue;
BlockState state = world.getBlockState(armInteractionPoint.pos);
if (state.has(JukeboxBlock.HAS_RECORD) && state.get(JukeboxBlock.HAS_RECORD))
return true;
}
return false;
}
private void tickMovementProgress() { private void tickMovementProgress() {
chasedPointProgress += Math.min(256, Math.abs(getSpeed())) / 1024f; chasedPointProgress += Math.min(256, Math.abs(getSpeed())) / 1024f;
if (chasedPointProgress > 1) if (chasedPointProgress > 1)
@ -101,8 +127,8 @@ public class ArmTileEntity extends KineticTileEntity {
ArmInteractionPoint targetedInteractionPoint = getTargetedInteractionPoint(); ArmInteractionPoint targetedInteractionPoint = getTargetedInteractionPoint();
ArmAngleTarget previousTarget = this.previousTarget; ArmAngleTarget previousTarget = this.previousTarget;
ArmAngleTarget target = ArmAngleTarget target = targetedInteractionPoint == null ? ArmAngleTarget.NO_TARGET
targetedInteractionPoint == null ? ArmAngleTarget.NO_TARGET : targetedInteractionPoint.getTargetAngles(pos); : targetedInteractionPoint.getTargetAngles(pos, isOnCeiling());
baseAngle.set(AngleHelper.angleLerp(chasedPointProgress, previousBaseAngle, baseAngle.set(AngleHelper.angleLerp(chasedPointProgress, previousBaseAngle,
target == ArmAngleTarget.NO_TARGET ? previousBaseAngle : target.baseAngle)); target == ArmAngleTarget.NO_TARGET ? previousBaseAngle : target.baseAngle));
@ -116,7 +142,13 @@ public class ArmTileEntity extends KineticTileEntity {
lowerArmAngle.set(MathHelper.lerp(progress, previousTarget.lowerArmAngle, target.lowerArmAngle)); lowerArmAngle.set(MathHelper.lerp(progress, previousTarget.lowerArmAngle, target.lowerArmAngle));
upperArmAngle.set(MathHelper.lerp(progress, previousTarget.upperArmAngle, target.upperArmAngle)); upperArmAngle.set(MathHelper.lerp(progress, previousTarget.upperArmAngle, target.upperArmAngle));
headAngle.set(AngleHelper.angleLerp(progress, previousTarget.headAngle, target.headAngle));
headAngle.set(AngleHelper.angleLerp(progress, previousTarget.headAngle % 360, target.headAngle % 360));
}
protected boolean isOnCeiling() {
BlockState state = getBlockState();
return hasWorld() && state != null && state.has(ArmBlock.CEILING) && state.get(ArmBlock.CEILING);
} }
@Nullable @Nullable
@ -182,6 +214,9 @@ public class ArmTileEntity extends KineticTileEntity {
chasedPointIndex = -1; chasedPointIndex = -1;
sendData(); sendData();
markDirty(); markDirty();
if (!world.isRemote)
AllTriggers.triggerForNearbyPlayers(AllTriggers.MECHANICAL_ARM, world, pos, 10);
} }
protected void collectItem() { protected void collectItem() {
@ -277,9 +312,9 @@ public class ArmTileEntity extends KineticTileEntity {
int previousIndex = chasedPointIndex; int previousIndex = chasedPointIndex;
Phase previousPhase = phase; Phase previousPhase = phase;
ListNBT interactionPointTagBefore = interactionPointTag; ListNBT interactionPointTagBefore = interactionPointTag;
super.readClientUpdate(tag); super.readClientUpdate(tag);
boolean ceiling = isOnCeiling();
if (interactionPointTagBefore == null || interactionPointTagBefore.size() != interactionPointTag.size()) if (interactionPointTagBefore == null || interactionPointTagBefore.size() != interactionPointTag.size())
updateInteractionPoints = true; updateInteractionPoints = true;
if (previousIndex != chasedPointIndex || (previousPhase != phase)) { if (previousIndex != chasedPointIndex || (previousPhase != phase)) {
@ -288,9 +323,10 @@ public class ArmTileEntity extends KineticTileEntity {
previousPoint = inputs.get(previousIndex); previousPoint = inputs.get(previousIndex);
if (previousPhase == Phase.MOVE_TO_OUTPUT && previousIndex < outputs.size()) if (previousPhase == Phase.MOVE_TO_OUTPUT && previousIndex < outputs.size())
previousPoint = outputs.get(previousIndex); previousPoint = outputs.get(previousIndex);
previousTarget = previousPoint == null ? ArmAngleTarget.NO_TARGET : previousPoint.getTargetAngles(pos); previousTarget =
previousPoint == null ? ArmAngleTarget.NO_TARGET : previousPoint.getTargetAngles(pos, ceiling);
if (previousPoint != null) if (previousPoint != null)
previousBaseAngle = previousPoint.getTargetAngles(pos).baseAngle; previousBaseAngle = previousPoint.getTargetAngles(pos, ceiling).baseAngle;
} }
} }

View file

@ -80,9 +80,9 @@ public class AllAdvancements implements IDataProvider {
andesiteExpertLane(t, andesite_casing); andesiteExpertLane(t, andesite_casing);
Advancement drill = Advancement drill = kinecticAdvancement("mechanical_drill", AllBlocks.MECHANICAL_DRILL.get(), TaskType.NORMAL)
kinecticAdvancement("mechanical_drill", AllBlocks.MECHANICAL_DRILL.get(), TaskType.NORMAL).withParent(andesite_casing) .withParent(andesite_casing)
.register(t, id + ":mechanical_drill"); .register(t, id + ":mechanical_drill");
Advancement press = Advancement press =
advancement("press", AllBlocks.MECHANICAL_PRESS.get(), TaskType.MILESTONE).withParent(andesite_casing) advancement("press", AllBlocks.MECHANICAL_PRESS.get(), TaskType.MILESTONE).withParent(andesite_casing)
@ -98,8 +98,9 @@ public class AllAdvancements implements IDataProvider {
itemAdvancement("electron_tube", AllItems.ELECTRON_TUBE, TaskType.NORMAL).withParent(rose_quartz) itemAdvancement("electron_tube", AllItems.ELECTRON_TUBE, TaskType.NORMAL).withParent(rose_quartz)
.register(t, id + ":electron_tube"); .register(t, id + ":electron_tube");
Advancement saw = kinecticAdvancement("mechanical_saw", AllBlocks.MECHANICAL_SAW.get(), TaskType.NORMAL).withParent(press) Advancement saw =
.register(t, id + ":mechanical_saw"); kinecticAdvancement("mechanical_saw", AllBlocks.MECHANICAL_SAW.get(), TaskType.NORMAL).withParent(press)
.register(t, id + ":mechanical_saw");
Advancement basin = advancement("basin", AllBlocks.BASIN.get(), TaskType.NORMAL).withParent(press) Advancement basin = advancement("basin", AllBlocks.BASIN.get(), TaskType.NORMAL).withParent(press)
.withCriterion("0", placeBlock(AllBlocks.BASIN.get())) .withCriterion("0", placeBlock(AllBlocks.BASIN.get()))
@ -196,6 +197,20 @@ public class AllAdvancements implements IDataProvider {
.withCriterion("0", AllTriggers.GIGA_EXTENDO.instance()) .withCriterion("0", AllTriggers.GIGA_EXTENDO.instance())
.register(t, id + ":dual_extendo_grip"); .register(t, id + ":dual_extendo_grip");
Advancement mechanical_arm = advancement("mechanical_arm", AllBlocks.MECHANICAL_ARM.get(), TaskType.GOAL)
.withCriterion("0", placeBlock(AllBlocks.MECHANICAL_ARM.get()))
.withCriterion("1", isPowered(AllBlocks.MECHANICAL_ARM.get()))
.withCriterion("2", AllTriggers.MECHANICAL_ARM.instance())
.withParent(brass_casing)
.register(t, id + ":mechanical_arm");
Advancement musical_arm = advancement("musical_arm", Items.MUSIC_DISC_13, TaskType.MILESTONE)
.withCriterion("0", placeBlock(AllBlocks.MECHANICAL_ARM.get()))
.withCriterion("1", isPowered(AllBlocks.MECHANICAL_ARM.get()))
.withCriterion("2", AllTriggers.MUSICAL_ARM.instance())
.withParent(mechanical_arm)
.register(t, id + ":musical_arm");
Advancement deployer = Advancement deployer =
kinecticAdvancement("deployer", AllBlocks.DEPLOYER.get(), TaskType.GOAL).withParent(brass_casing) kinecticAdvancement("deployer", AllBlocks.DEPLOYER.get(), TaskType.GOAL).withParent(brass_casing)
.register(t, id + ":deployer"); .register(t, id + ":deployer");

View file

@ -33,6 +33,8 @@ public class AllTriggers {
UPGRADED_ZAPPER = simple("upgraded_zapper"), UPGRADED_ZAPPER = simple("upgraded_zapper"),
EXTENDO = simple("extendo"), EXTENDO = simple("extendo"),
GIGA_EXTENDO = simple("giga_extendo"), GIGA_EXTENDO = simple("giga_extendo"),
MECHANICAL_ARM = simple("mechanical_arm"),
MUSICAL_ARM = simple("musical_arm"),
MIXER_MIX = simple("mixer"); MIXER_MIX = simple("mixer");
private static SimpleTrigger simple(String id) { private static SimpleTrigger simple(String id) {

View file

@ -61,6 +61,10 @@
"advancement.create.crafter.desc": "Place and power some Mechanical Crafters", "advancement.create.crafter.desc": "Place and power some Mechanical Crafters",
"advancement.create.deployer": "Poke, Place, and Attack", "advancement.create.deployer": "Poke, Place, and Attack",
"advancement.create.deployer.desc": "Place and power a Deployer, the perfect reflection of yourself.", "advancement.create.deployer.desc": "Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "Pound It, Bro!", "advancement.create.fist_bump": "Pound It, Bro!",
"advancement.create.fist_bump.desc": "Make two Deployers fist-bump.", "advancement.create.fist_bump.desc": "Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "A Pair of Giants", "advancement.create.crushing_wheel": "A Pair of Giants",

View file

@ -121,8 +121,8 @@
}, },
{ {
"name": "Back", "name": "Back",
"from": [3, -2, 3], "from": [3.1, -1.9, 3.1],
"to": [13, 2, 13], "to": [12.9, 2, 12.9],
"faces": { "faces": {
"north": {"uv": [9.5, 9, 14.5, 11], "texture": "#4"}, "north": {"uv": [9.5, 9, 14.5, 11], "texture": "#4"},
"east": {"uv": [9.5, 9, 14.5, 11], "texture": "#4"}, "east": {"uv": [9.5, 9, 14.5, 11], "texture": "#4"},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

After

Width:  |  Height:  |  Size: 984 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 948 B

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB