diff --git a/build.gradle b/build.gradle index 463f03b58..b94ff4fac 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { maven { url = 'https://files.minecraftforge.net/maven' } jcenter() mavenCentral() - maven { url='https://dist.creeper.host/Sponge/maven' } + maven { url='https://repo.spongepowered.org/repository/maven-public/' } } dependencies { classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true @@ -39,7 +39,7 @@ minecraft { workingDirectory project.file('run') // property 'mixin.env.disableRefMap', 'true' arg '-mixin.config=create.mixins.json' -// jvmArgs '-XX:+UnlockCommercialFeatures' + jvmArgs '-XX:+UnlockCommercialFeatures' property 'forge.logging.console.level', 'info' property 'fml.earlyprogresswindow', 'false' mods { diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 36a9c8907..4c93571f0 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -9,14 +9,14 @@ dd468657a73fc2ad6e1ac08ace2996b6997d33e0 assets/create/blockstates/andesite_belt 585481e97c5066af63ea12fa5dd658798844d64c assets/create/blockstates/andesite_bricks.json 4e8d61aa2c8490301317ef747f67f0169ebfc2ed assets/create/blockstates/andesite_bricks_slab.json da63a8be3191d6d72afef6c79e3aea3f607631f9 assets/create/blockstates/andesite_bricks_stairs.json -57be934c5bc9b3a693e4eab018d8775681d8f0fa assets/create/blockstates/andesite_bricks_wall.json +a579c40c43dc2174afb66f42d00d0c4a0efaaeee assets/create/blockstates/andesite_bricks_wall.json 9999a75c7766781eadb12510a09264600bc846e4 assets/create/blockstates/andesite_casing.json 3af4ea3c44b5ebc7e1e3fb73fb8356faf067a613 assets/create/blockstates/andesite_cobblestone.json 97adf53a7cb99d7652fb39adc957e9e34cbaca47 assets/create/blockstates/andesite_cobblestone_slab.json 96b5284693da168ab8e0809d86515b5f1a7e763f assets/create/blockstates/andesite_cobblestone_stairs.json -a92c395c57209141d4cf78ad62facbaf3878a120 assets/create/blockstates/andesite_cobblestone_wall.json +82bd82270aff7d51e9239680ef4dd7b5c899ceb0 assets/create/blockstates/andesite_cobblestone_wall.json 9639b901ffdd2ecccab5575c5c9e6c7b5c901e02 assets/create/blockstates/andesite_encased_shaft.json -1ecbef2322e05c8f3e0fb9842edf3abfbf4bff78 assets/create/blockstates/andesite_funnel.json +ca9a629472625abf741f02b94ce4578292fb14a7 assets/create/blockstates/andesite_funnel.json 398922758a6219544e5b85c91c9cf8a543b437e5 assets/create/blockstates/andesite_pillar.json 1d2d8081581e07d9be4b382aede4f2de4401cc6b assets/create/blockstates/andesite_tunnel.json e555e3c2b2d3f01440e48db4ba88f7e00fd99b6f assets/create/blockstates/basin.json @@ -34,7 +34,7 @@ ee1299a15fca849eb42bf81507f85a54c167bbfe assets/create/blockstates/brass_belt_fu 8b1dd00adcc7e74c5a9feed069e2610b15a338cb assets/create/blockstates/brass_block.json b8dd6e505943e06706d0718ece620ab3cf943650 assets/create/blockstates/brass_casing.json 288bad07593a8a2c8efaf44bba0ffb0011d36cd3 assets/create/blockstates/brass_encased_shaft.json -94ffc190ae017e9401f7966e8b2f6a643406af9d assets/create/blockstates/brass_funnel.json +adfbd6cc5e44a0f431180aedbe65a19428299d8e assets/create/blockstates/brass_funnel.json 672eedcd3520c6d39603449165a23be9c612c620 assets/create/blockstates/brass_tunnel.json 11ebdd9bd0815833e62ec1bea03a4cdd86ce00f3 assets/create/blockstates/brown_sail.json e81608346d43406ee72cae0f78b8bcfb37ba2d75 assets/create/blockstates/brown_seat.json @@ -62,8 +62,6 @@ ecf4a72411870bfdbf8a59469b114cd77621c343 assets/create/blockstates/copper_tiles. 3df0d5d5170a2f6cbab0f8a9bc8f2d64229589af assets/create/blockstates/creative_crate.json da3f1203dd0b0096ce19e09705060a0ed0478bee assets/create/blockstates/creative_fluid_tank.json f0031f5e970b3d5695472ed384950b8631b015ed assets/create/blockstates/creative_motor.json -24ee16e3dadb3e0221afce7af37643494f471fb0 assets/create/blockstates/crimson_window.json -3e6cd0945390b390b963474f7cf708e2dcba631c assets/create/blockstates/crimson_window_pane.json fe2f78b94c20944399101e7369e2d43324297fb6 assets/create/blockstates/crushing_wheel.json a1dd6cb3daa97ea871290ef7b178d28b564ee2a2 assets/create/blockstates/crushing_wheel_controller.json b1126c191877cff86b4e2de83e1fcbd151451cb7 assets/create/blockstates/cuckoo_clock.json @@ -76,32 +74,32 @@ b496452f2f7dbbba385e1fc10b560ec266e4b5e7 assets/create/blockstates/cyan_sail.jso bfab7d9b2e01183d47a828f2827125771efa97fc assets/create/blockstates/dark_scoria_bricks.json 831fb03aab9223da39dd1d16e9a7e9233dc16871 assets/create/blockstates/dark_scoria_bricks_slab.json 15c4f7b5d64a8d6467a2a18c12649ddb8fdb5805 assets/create/blockstates/dark_scoria_bricks_stairs.json -7b71efe303ae68f7ec69cba5d1209b7a928157a8 assets/create/blockstates/dark_scoria_bricks_wall.json +2f8971e81ea2347e1814812b15119b9662dd64e7 assets/create/blockstates/dark_scoria_bricks_wall.json 3e7a5f7f38490d91902088f9dabe4fbaa57132fd assets/create/blockstates/dark_scoria_cobblestone.json 1ca115df6d2b5a63a1c505bc94d62543f1c0e26a assets/create/blockstates/dark_scoria_cobblestone_slab.json f86eea3f7df0988fffbe90e29b74141a7203cd15 assets/create/blockstates/dark_scoria_cobblestone_stairs.json -d642fe3bc6c062ace9c26056b26f83adf5eaf3ab assets/create/blockstates/dark_scoria_cobblestone_wall.json +f1020a33fcb1a362b6c55b5aa8ce093e47ebde09 assets/create/blockstates/dark_scoria_cobblestone_wall.json 902778a0f16b7ad009ee7b123bb583eaea32467a assets/create/blockstates/dark_scoria_pillar.json ac85f55d82d96fc15750e6b954297cfd1e00d04d assets/create/blockstates/deployer.json 3660f44309279a0347347f23ce7444c6ed98cafd assets/create/blockstates/depot.json c890ec9b3778aebb16c6b2eb2ca79bfbe7bf7435 assets/create/blockstates/diorite_bricks.json 894d5ca00c3765553deaac44b83257983acf502d assets/create/blockstates/diorite_bricks_slab.json e42f2ebe5a2fdaeed62b9bc289252664a1e8705b assets/create/blockstates/diorite_bricks_stairs.json -a4dd768993186a0f6d8e6aa9f5b789560686cf7e assets/create/blockstates/diorite_bricks_wall.json +22f1c5fa41fa03a515c6aeafe0910c42dc60f22c assets/create/blockstates/diorite_bricks_wall.json 456d4a31a71acd46f2496ad5a17003ce6e33c5b2 assets/create/blockstates/diorite_cobblestone.json a886ed9f02e54d3cf0bc55710c61f52737953ede assets/create/blockstates/diorite_cobblestone_slab.json 328e6ffb0b0124f497b2e227c814fa2bcccfeb0e assets/create/blockstates/diorite_cobblestone_stairs.json -3852014415198355f19fe65e32fa338fc3d98488 assets/create/blockstates/diorite_cobblestone_wall.json +110cddbea434aa650eac919908880a0296b38a2f assets/create/blockstates/diorite_cobblestone_wall.json bd24921c0c66deaabbdbf557b7ff9a507402c1e5 assets/create/blockstates/diorite_pillar.json 610435897262bc9a1d98d85ce470a5030411a1d7 assets/create/blockstates/dolomite.json 710f354ec7b11b545bac9c5cb6f181229aa84be9 assets/create/blockstates/dolomite_bricks.json c681864890ec8c8c9f5ab275957979337539f782 assets/create/blockstates/dolomite_bricks_slab.json 23930bcbda625107810fbd0b32a8a94ba65940eb assets/create/blockstates/dolomite_bricks_stairs.json -09dca209759a430b6ef9fad19fe89f10e7d143ca assets/create/blockstates/dolomite_bricks_wall.json +a9c4a1a2ba785289f450487b3317012f9b31fa2b assets/create/blockstates/dolomite_bricks_wall.json a2b7259dacf7b582e3b819e12015b5e18a1768e5 assets/create/blockstates/dolomite_cobblestone.json 5cf01ea02b50229fce2296206b9f0ce1c1b2c9f6 assets/create/blockstates/dolomite_cobblestone_slab.json e7c1db7226df5858f1884f0cf328a733fec22c3d assets/create/blockstates/dolomite_cobblestone_stairs.json -af19f2d229bb50da787c7d083a79a57cf9a8037c assets/create/blockstates/dolomite_cobblestone_wall.json +f63a5816d4bfe643aa098d03c3b54462dd06fe19 assets/create/blockstates/dolomite_cobblestone_wall.json f179202e59e449157f89efc37229b03bbfd391d7 assets/create/blockstates/dolomite_pillar.json 35fc68eb1d031d28ad09b7b603e64ae459634179 assets/create/blockstates/encased_chain_drive.json 7b2b836649e729feafa60972bf95e3afb2143131 assets/create/blockstates/encased_fan.json @@ -109,40 +107,40 @@ d13940ed213d7acbc6ebe3bdd21175ef89e4d613 assets/create/blockstates/encased_fluid a774e815376a67e2a2de44e39af0a1a0b4406932 assets/create/blockstates/fancy_andesite_bricks.json 180be26a75834cf9cdb881f969f77906e91cc36a assets/create/blockstates/fancy_andesite_bricks_slab.json d5d7762b80952052d0a7adf3081967cac3f3ba6c assets/create/blockstates/fancy_andesite_bricks_stairs.json -c8f23c08b83862725f352800c6c350ed56e8899b assets/create/blockstates/fancy_andesite_bricks_wall.json +77da6346a42eaef0796b5032de4110e0d49aa388 assets/create/blockstates/fancy_andesite_bricks_wall.json 0212696f17a7758a448b168bc20264757fbde9fe assets/create/blockstates/fancy_dark_scoria_bricks.json f4dd92847d13d6ceeadc05ab63563490fdcd5f51 assets/create/blockstates/fancy_dark_scoria_bricks_slab.json 09ee11aba5b684608ce7ffcf57ed1bd2ec26c774 assets/create/blockstates/fancy_dark_scoria_bricks_stairs.json -9c2ea73d8f5f9030267f88cd6569c4f68399bc61 assets/create/blockstates/fancy_dark_scoria_bricks_wall.json +4c48c9692e79a6050f6336d25a3cebbf3b4a4fe9 assets/create/blockstates/fancy_dark_scoria_bricks_wall.json 5a4c65373ccd1ef6cd33cbb35e16c844af5ac8bf assets/create/blockstates/fancy_diorite_bricks.json 36575b9debabb8b9dbe9d6d3c2d124472dfa77e3 assets/create/blockstates/fancy_diorite_bricks_slab.json aeaa188516efbd5fd7477e0da5dc6dc3bc95dc8b assets/create/blockstates/fancy_diorite_bricks_stairs.json -dba57141fea3be3649254ea29492b695711c849d assets/create/blockstates/fancy_diorite_bricks_wall.json +1af3234a64bd52a18ebe7ed3ea1fae2d8d5ec727 assets/create/blockstates/fancy_diorite_bricks_wall.json e72c26b8546245499d78620f1ad4eaf6092fc871 assets/create/blockstates/fancy_dolomite_bricks.json 46bd9c9bfcc9de5fad6d33aab2adbc1ac7493802 assets/create/blockstates/fancy_dolomite_bricks_slab.json d8fc5f08a5c2f215f95b09b32913672535859920 assets/create/blockstates/fancy_dolomite_bricks_stairs.json -47fd48996ecf8b8ca3381716495d527222d26ffa assets/create/blockstates/fancy_dolomite_bricks_wall.json +7fb5eb31010950290203d4b7012f3b3b963da574 assets/create/blockstates/fancy_dolomite_bricks_wall.json ac1b22a13434a580f2213c78001590bb4e9793ec assets/create/blockstates/fancy_gabbro_bricks.json 5e74f21623c749ea863d64ebce568da314e0e71b assets/create/blockstates/fancy_gabbro_bricks_slab.json 70eb799df2529c7df6061a6793eabbbea76db77c assets/create/blockstates/fancy_gabbro_bricks_stairs.json -5f6bc7bf2f744f775b1ae968bd746444fc8f6fce assets/create/blockstates/fancy_gabbro_bricks_wall.json +16770e9d377f801cb05a0a404f3888eb1009b6cb assets/create/blockstates/fancy_gabbro_bricks_wall.json 691c985a817ffa6733ea8901b329826da8f94017 assets/create/blockstates/fancy_granite_bricks.json 5f50be00c3b407a46f429776950d82f53df87ba4 assets/create/blockstates/fancy_granite_bricks_slab.json 4e0e1c1186c26e7d345dc8bd006be9f283349813 assets/create/blockstates/fancy_granite_bricks_stairs.json -9860dbcb6016a19f544332a21dbb204703a88f8b assets/create/blockstates/fancy_granite_bricks_wall.json +0fbac68366751b45ff4455039c9630c309153095 assets/create/blockstates/fancy_granite_bricks_wall.json 143d5cb3a6f149da0d11545297d9495b9173d7a0 assets/create/blockstates/fancy_limestone_bricks.json b4bff88215fa1206ac461e199cc784c916b85479 assets/create/blockstates/fancy_limestone_bricks_slab.json 23f0d926e69b798ea561c0ccd13b4620f9699dda assets/create/blockstates/fancy_limestone_bricks_stairs.json -6dae27115433e128738da6eccefc7db1e0f34700 assets/create/blockstates/fancy_limestone_bricks_wall.json +d704b7e1ef8f5b1d62058044846bace06464aea7 assets/create/blockstates/fancy_limestone_bricks_wall.json 8e5b65b12e46ebc0aace1155d1902780efacecd9 assets/create/blockstates/fancy_scoria_bricks.json d8dd7ba8280b63f2a1f4c50db1d9b7a6ac7bf80a assets/create/blockstates/fancy_scoria_bricks_slab.json fc652317e03b57c76e23a805da16a28d15254029 assets/create/blockstates/fancy_scoria_bricks_stairs.json -6d6b85c0ad9b04520cd3b6b0da71f3979dcbdb63 assets/create/blockstates/fancy_scoria_bricks_wall.json +de8a40b7daf1497d5aecee47a43b3e0b1d030b00 assets/create/blockstates/fancy_scoria_bricks_wall.json 5864daf839e54789a0dc8a44505f070bf3e184bc assets/create/blockstates/fancy_weathered_limestone_bricks.json fc9ac0a7e7191b93516719455a17177fa6524ecc assets/create/blockstates/fancy_weathered_limestone_bricks_slab.json b2a7c321b1795f20e7433f81a55ce4683de081b8 assets/create/blockstates/fancy_weathered_limestone_bricks_stairs.json -8e532856c3c2b4e4e59c65a2a81a694e35d14658 assets/create/blockstates/fancy_weathered_limestone_bricks_wall.json -65f5fa4b779af5150993b20174404ec93bfc4303 assets/create/blockstates/fluid_pipe.json +6372fe02ba0065acb0758121c45a15a1a8fdc5de assets/create/blockstates/fancy_weathered_limestone_bricks_wall.json +48086bf71a824faf14841b698050cc8544b09a9b assets/create/blockstates/fluid_pipe.json f0eaab18e16c4f3f65ebf3b55b08f0dc445720fe assets/create/blockstates/fluid_tank.json 5408d92ab02af86539ac42971d4033545970bb3a assets/create/blockstates/fluid_valve.json e9da1794b6ece7f9aa8bcb43d42c23a55446133b assets/create/blockstates/flywheel.json @@ -153,13 +151,13 @@ f512b70d7fd0ca10184f21f5bfb71c83ab11f8ef assets/create/blockstates/gabbro.json d2358eb3d9337741f55339f0b94b2e81d73965c8 assets/create/blockstates/gabbro_bricks.json a5c87f9f5b8dd1573c1f2f770a5558f3dc244f96 assets/create/blockstates/gabbro_bricks_slab.json 66b9fa3d2c82e9c4d2a7e2b9b3e73dc45c0dd962 assets/create/blockstates/gabbro_bricks_stairs.json -3648aa5fa1888529fe1934ca8d52709f0ec57ee4 assets/create/blockstates/gabbro_bricks_wall.json +c8f27bfd301a642cdd101f826bc6ba8151588b38 assets/create/blockstates/gabbro_bricks_wall.json afff479c0e5284771afa9e7ce513595fe65860ee assets/create/blockstates/gabbro_cobblestone.json 85151aa7583e4752424b2efc1b35d8c9cceb66a7 assets/create/blockstates/gabbro_cobblestone_slab.json a1f31a194129cfb65e335b3b96490f9275f9c564 assets/create/blockstates/gabbro_cobblestone_stairs.json -59bfa369af6df2c9363245addda86937daa339ee assets/create/blockstates/gabbro_cobblestone_wall.json +a64d8d0924c0b5b192f355343dd9b3a440875f6a assets/create/blockstates/gabbro_cobblestone_wall.json a6b44e8a1c4ce0c7442b2384b41ad36dd133f19b assets/create/blockstates/gabbro_pillar.json -2d7ffcb339b0a38b98935a382ac2a164866255b1 assets/create/blockstates/gantry_pinion.json +23744450886af88ed468aecbbd7b8d7babcbbd6f assets/create/blockstates/gantry_carriage.json 9fa39a44bba30c5ae8fa245b122a837c705462b4 assets/create/blockstates/gantry_shaft.json eca1f0e56efdadb241f42dc6ebb036f1d52213a9 assets/create/blockstates/gearbox.json f34814b17cde3231a1dfb271f3dabf8d6de4fbf6 assets/create/blockstates/gearshift.json @@ -167,11 +165,11 @@ f34814b17cde3231a1dfb271f3dabf8d6de4fbf6 assets/create/blockstates/gearshift.jso 87661d61e1645ef5ad4ea34f1c0fa31f139ea431 assets/create/blockstates/granite_bricks.json d7f4cf7be7e9a3895840d9288245c52cbe25f0bd assets/create/blockstates/granite_bricks_slab.json ec51efc72eb6b16c5f99399b4cb6284665d5be99 assets/create/blockstates/granite_bricks_stairs.json -7751b730365e3ef7d41d457cdb0a3344927710cc assets/create/blockstates/granite_bricks_wall.json +9211777c912837af9d328a525248a31608a82bd1 assets/create/blockstates/granite_bricks_wall.json 0d19d78cf035d0183b5268f646bacff2f40e7f7e assets/create/blockstates/granite_cobblestone.json a4b0337149cb0617cc60061477c7178d37dbb831 assets/create/blockstates/granite_cobblestone_slab.json d97fdea02187e63f6b63913357c79a18660d676d assets/create/blockstates/granite_cobblestone_stairs.json -2f29568407970ea0e3807e0553e0584d127a9014 assets/create/blockstates/granite_cobblestone_wall.json +9ce66b5a61c3aad398756d26e4efee2b9e12a275 assets/create/blockstates/granite_cobblestone_wall.json f8659e81cd2a623475a6a9aca59149e82de56b1c assets/create/blockstates/granite_pillar.json 5c40c4a27e1dec747a467dd251700c72a6ceb07d assets/create/blockstates/gray_sail.json a5ec5401ba9f3e102a2e1b35837f643847afbca4 assets/create/blockstates/gray_seat.json @@ -211,11 +209,11 @@ e7cb0b25e511610b46dfd219e0cc5ea60a79d56b assets/create/blockstates/limestone.jso e7c7b952137c4cb615988ea59b9f14303c9a4dfe assets/create/blockstates/limestone_bricks.json 4048ef9e001a4036a4c806053b15ed80261c0a2b assets/create/blockstates/limestone_bricks_slab.json 936d0daa91eb725548e634cb3855cee36b7d66dd assets/create/blockstates/limestone_bricks_stairs.json -72e7851f7d8517bebcc49d7809b403ec8205463a assets/create/blockstates/limestone_bricks_wall.json +9dd473902238cb10f0f6eef375dee11a1df46d4b assets/create/blockstates/limestone_bricks_wall.json 728b5b373f3b731f4f7782b68da9a8e572367df3 assets/create/blockstates/limestone_cobblestone.json 19b6a403a126196144d13eafb81e172b87061019 assets/create/blockstates/limestone_cobblestone_slab.json 43532aec1893f7d2f37798d5dbb11ecde0a3bfab assets/create/blockstates/limestone_cobblestone_stairs.json -10513d55f7c621162a13d474d8f4eb54305d0f60 assets/create/blockstates/limestone_cobblestone_wall.json +17c5a6c1dd094c9201ed90fdcebde620a8a39900 assets/create/blockstates/limestone_cobblestone_wall.json b7506b862d13b3f915c60d38bb7a20afc935f70a assets/create/blockstates/limestone_pillar.json 69790737767e06f000c7824749c46664a123160e assets/create/blockstates/linear_chassis.json 07bae932a163b81f8749f98287b4fb4949fe0b8b assets/create/blockstates/lit_blaze_burner.json @@ -269,39 +267,39 @@ fbb651b8e4a72bf0a17a6bfdbf4eef680e9d4a5c assets/create/blockstates/overgrown_sco ab93ff18b747607dbc1d8d7311a2737e302b92d1 assets/create/blockstates/paved_andesite.json 89e88a0d2e7df66bac7ab11ac2c7b14812d8675f assets/create/blockstates/paved_andesite_slab.json f43d947077b3f4a11a9729c58709c56f09859da0 assets/create/blockstates/paved_andesite_stairs.json -995c695368d1cd98cad4e71fc5c4d92368cb80fd assets/create/blockstates/paved_andesite_wall.json +71368afa5b2bb1bcda81935b4e5ea52babf2f89d assets/create/blockstates/paved_andesite_wall.json 4c3f3b1083d5ed7dc882ff0c5a8e99fa4e114810 assets/create/blockstates/paved_dark_scoria.json 373ae114d505e64fc1a1101f1c738d690098f4e4 assets/create/blockstates/paved_dark_scoria_slab.json 609ca3c0f01f82b07afddd12399019ea4e83ff0c assets/create/blockstates/paved_dark_scoria_stairs.json -75b1136023ba7e0db83b6ca4fcca1c945b520016 assets/create/blockstates/paved_dark_scoria_wall.json +ee62f4da5831042eeb00cec1de5f04d9513c2878 assets/create/blockstates/paved_dark_scoria_wall.json 16e6d4110af2a9ac5a27c1416fa333d125a0c212 assets/create/blockstates/paved_diorite.json 5088c7c493386509739cf78eb043f79a36cc49a2 assets/create/blockstates/paved_diorite_slab.json 7c88703a29614886c193a3e1b7fa1aedc2901626 assets/create/blockstates/paved_diorite_stairs.json -d1bf30633df01e292979276ea57d7c2d06242459 assets/create/blockstates/paved_diorite_wall.json +ff683aa224095aa1fddcffbc94e767bf5ed396f8 assets/create/blockstates/paved_diorite_wall.json 7df5d644f113bd7988fc958d1018766ea41e16a5 assets/create/blockstates/paved_dolomite.json 0f007adfc85b2c11600adf457060f3a9a3b0b354 assets/create/blockstates/paved_dolomite_slab.json 77362a0dc9e7dc850a40359580122314c0d48edf assets/create/blockstates/paved_dolomite_stairs.json -ba1156ac5eb0323b700bb5d125f608f17999375b assets/create/blockstates/paved_dolomite_wall.json +161b19cfff4f8fba467d3913b7bde86149f88c45 assets/create/blockstates/paved_dolomite_wall.json 6b408845d667c7ed1490d03ea38db15cf4bdeb0d assets/create/blockstates/paved_gabbro.json 192412bf95174f6c635a5c10e9cb6f26ed9732fa assets/create/blockstates/paved_gabbro_slab.json 2bb34163e982218d0e8734a140445d25ad135afc assets/create/blockstates/paved_gabbro_stairs.json -92eefb99b6395ce39e1de391cea985128db31ec5 assets/create/blockstates/paved_gabbro_wall.json +bf3cbd3f694a01e072524ab398ed4097b6babba8 assets/create/blockstates/paved_gabbro_wall.json b4c21fbcbfc21ba2aaaa468ddcac322fc3ed4cdf assets/create/blockstates/paved_granite.json e273711b7e510c1553023c9962c7b66073fa77a8 assets/create/blockstates/paved_granite_slab.json ad8c79e38ee2b0bdb18e35e9925dc213b4a95008 assets/create/blockstates/paved_granite_stairs.json -6f92ee9fbed9d2ff276224328a9769450597ae32 assets/create/blockstates/paved_granite_wall.json +95ccf04f5dd38c266263189d2291ab8ef92473c8 assets/create/blockstates/paved_granite_wall.json 67df4368fd671d334702134c4011c85d8a7d1943 assets/create/blockstates/paved_limestone.json e1eca91fdcf60b8ac0c2b8cdf6674046b0bc55f4 assets/create/blockstates/paved_limestone_slab.json 20c5434a0fb1108d424c27c44213dc89f5ec0027 assets/create/blockstates/paved_limestone_stairs.json -6fd09280e01b9be3a80122d6335155711857f6a3 assets/create/blockstates/paved_limestone_wall.json +b1b2426f87a7e56e72d93db293b05c570d2bbac6 assets/create/blockstates/paved_limestone_wall.json 1ec5fafef5d6447938d2741c718b7411bf074e27 assets/create/blockstates/paved_scoria.json 10784fd7ad60cece61c5a10e933be0c33eb8e78e assets/create/blockstates/paved_scoria_slab.json 10a5ff1a5e5ae32a656637da8c41103798f3553f assets/create/blockstates/paved_scoria_stairs.json -10b96679bb11c3979e906fbad11b51d017624454 assets/create/blockstates/paved_scoria_wall.json +76b3299e3e002fa942eb657cda1f6b729ec0b1a2 assets/create/blockstates/paved_scoria_wall.json c17d334e938dcb742550ba8307ca8266a1fc9b49 assets/create/blockstates/paved_weathered_limestone.json cb23aef25f3106b06c8fa8f152c638bb0d2185d8 assets/create/blockstates/paved_weathered_limestone_slab.json d62b0992cec1de45dad1f2c273132225f4ef33a0 assets/create/blockstates/paved_weathered_limestone_stairs.json -e29e245d06c46dac94fcd0e01a9bf7fa8e02fb87 assets/create/blockstates/paved_weathered_limestone_wall.json +dba4cf86e82ed4502fffed363fbce226a445e774 assets/create/blockstates/paved_weathered_limestone_wall.json 30971f2f76fe56f144178c33ad6bde5fc9fb61c3 assets/create/blockstates/pink_sail.json 919a79e4a4a5fab0aac3ef48e1c786017d6aa001 assets/create/blockstates/pink_seat.json 471a3bb474a0ae0453143888d561256cce894e3f assets/create/blockstates/pink_valve_handle.json @@ -309,27 +307,27 @@ e29e245d06c46dac94fcd0e01a9bf7fa8e02fb87 assets/create/blockstates/paved_weather 2f764f460aa1d75ba995da180bc6f8d2bd9db385 assets/create/blockstates/polished_dark_scoria.json 262b22dcf3e151e63f58710f6b6fe4fc4fc2a70c assets/create/blockstates/polished_dark_scoria_slab.json a0dbcb7651b02a4f5c747ad2c6d35da60f768d9b assets/create/blockstates/polished_dark_scoria_stairs.json -1f0970eb7949bdb66ed25b614ab8a09abb154da7 assets/create/blockstates/polished_dark_scoria_wall.json +7c8482b4e3f1593f1cf6d0233a57194456602b4f assets/create/blockstates/polished_dark_scoria_wall.json c197a8c1e80150cf2ef73ed5429b976a6920ee39 assets/create/blockstates/polished_dolomite.json 1c60ab250ae8577fa314b2718d4d8d9885c7a387 assets/create/blockstates/polished_dolomite_slab.json 4ee6fc88ba0b69f144da81c4ec023cd123bb28e1 assets/create/blockstates/polished_dolomite_stairs.json -10584661311a320520ea9867160a8d87fd7263a1 assets/create/blockstates/polished_dolomite_wall.json +0ba06e244995d12d9744fe1aa3f619975f374b7a assets/create/blockstates/polished_dolomite_wall.json c20df6b7240b2aeffd4f66e8b902f71b2a43ea35 assets/create/blockstates/polished_gabbro.json d760a9e9efac9f81b36be2632b4b309f113004a3 assets/create/blockstates/polished_gabbro_slab.json f20b78557066023365b0f1f7c4a95ae50724421d assets/create/blockstates/polished_gabbro_stairs.json -1245b8c7eaab1791c31f19b8a62e8f20da09dff3 assets/create/blockstates/polished_gabbro_wall.json +7192b0fe69a71bf8295ec4c4f60b8a268f9605bd assets/create/blockstates/polished_gabbro_wall.json 039ed5b957758e9c9266764a7787179e0b74c567 assets/create/blockstates/polished_limestone.json a31044438e849f216c5bd5960f57645b22c2ca83 assets/create/blockstates/polished_limestone_slab.json f1bf2d4e4e1dff8cc39652a35f601fc58424e60d assets/create/blockstates/polished_limestone_stairs.json -2f91d896a1b12e45c2685cdc641250a11dafdd70 assets/create/blockstates/polished_limestone_wall.json +7e03ef348cff2678f7d6c65bf48806f887647cd2 assets/create/blockstates/polished_limestone_wall.json 35c8f660a49dd2addae6a77283aba7f581a8d042 assets/create/blockstates/polished_scoria.json a452650af5c929675b0a3c8e8bf23c6cac67152e assets/create/blockstates/polished_scoria_slab.json 8e2c6b205b17dde98e7cc9b4bcea6c75aaaeae80 assets/create/blockstates/polished_scoria_stairs.json -81f78e6299e84170d3326793fc913a2337093277 assets/create/blockstates/polished_scoria_wall.json +0e76787c4e63635cf6f920bd60130dd453c10a2b assets/create/blockstates/polished_scoria_wall.json c8467d55bc22d2e2256b8b732c06c9fdc64d336f assets/create/blockstates/polished_weathered_limestone.json 5d811eab3c5e8411f98e2ea98d93d35955ce18fc assets/create/blockstates/polished_weathered_limestone_slab.json acec6cdebe772ca72de94a85d98199e827495acb assets/create/blockstates/polished_weathered_limestone_stairs.json -ad721e3911f48c61c3639edac1896680a31451ff assets/create/blockstates/polished_weathered_limestone_wall.json +f42ad32aefcfa7ccc6287f57ee1a5f092b65126f assets/create/blockstates/polished_weathered_limestone_wall.json 3bb571d0a2597907bf3a30686b4bfa0841ac990a assets/create/blockstates/portable_fluid_interface.json 1b70b4e5792dccd2110b84e209016ac258005e28 assets/create/blockstates/portable_storage_interface.json 8296d43d5f1c2113012d127038fb319af83aaee4 assets/create/blockstates/powered_latch.json @@ -357,11 +355,11 @@ a5befc14551f043675e985027609aeb7e6bacc0d assets/create/blockstates/scoria.json 4ccf1fb580ce25835329d50dcf0ba91be19baaeb assets/create/blockstates/scoria_bricks.json 145fb4b57649105c6f188bd2b895ee69d2378b1f assets/create/blockstates/scoria_bricks_slab.json 41066da6ae338c079f506c87c0e36fda788f75e4 assets/create/blockstates/scoria_bricks_stairs.json -07e49aaaaaeec02f6ca0e01c8e6ba7c8bd1275aa assets/create/blockstates/scoria_bricks_wall.json +6e18096573621955e077731a0dcdf0eb86678c93 assets/create/blockstates/scoria_bricks_wall.json 20c7cdf5d5e62bdbce53541bdb8079836ad74bb0 assets/create/blockstates/scoria_cobblestone.json be96a5541f211a6929fa04ec3535cb62ce7d4a2d assets/create/blockstates/scoria_cobblestone_slab.json 41d1fbbdfb038e474254bee5284561342fea0fc9 assets/create/blockstates/scoria_cobblestone_stairs.json -b81359a2c80e8fbc4fffd3573ce7dea70e1c2640 assets/create/blockstates/scoria_cobblestone_wall.json +b6e50f46a02f833f2f2bafa8585a909b6da5e229 assets/create/blockstates/scoria_cobblestone_wall.json 46641fdbc6bdc05829153bc28efb90cae26a51f8 assets/create/blockstates/scoria_pillar.json 89e10f35b93b5c72dd235eb79e5fc6f3655027a1 assets/create/blockstates/secondary_linear_chassis.json 81931eb1027dfb42ba4b2186185a4c0a36e0dbe4 assets/create/blockstates/sequenced_gearshift.json @@ -373,6 +371,7 @@ e815bfd854c2653f10828bb11950f7fb991d7efc assets/create/blockstates/speedometer.j 1cb7cdbefa0ff199263782809287854b9d85074c assets/create/blockstates/spout.json d62b7908119fa4f51715a186d0882b388bb25cab assets/create/blockstates/spruce_window.json 8d7dfa60630a8b4bae4e8eca5c66e1cfa34dda1f assets/create/blockstates/spruce_window_pane.json +5d7385d28a23dcfc95a221d36d82337908582726 assets/create/blockstates/sticker.json 3d93eabbb327aecc526beae9c62283f1d43eb710 assets/create/blockstates/sticky_mechanical_piston.json f385988cb6fa9c48b5d59a6942ec50ed2b60c8bf assets/create/blockstates/stockpile_switch.json e815bfd854c2653f10828bb11950f7fb991d7efc assets/create/blockstates/stressometer.json @@ -381,18 +380,16 @@ a2454400b1cf9889f70aebdc89c52a1be25f543c assets/create/blockstates/tiled_glass_p a8094531617e27a545c4815ab2062bf0ffca3633 assets/create/blockstates/turntable.json 69dfe8afaa8eb6105dae9f76ab8b7847bf90b8c6 assets/create/blockstates/vertical_framed_glass.json c4db76b9d36cfb098df0d158cb6f8b82768ebe14 assets/create/blockstates/vertical_framed_glass_pane.json -3a5da54d9763e9512cfaa47b25226b79738b25f3 assets/create/blockstates/warped_window.json -19ef7a16c82f07d304fb60d121845185d189aecf assets/create/blockstates/warped_window_pane.json d995547bcd71603ba7378d8998098e462030bfd0 assets/create/blockstates/water_wheel.json f182669f7547964f9f2ef67916568556870def7b assets/create/blockstates/weathered_limestone.json 27e6740834c0f673acc3531371512daa6dcab025 assets/create/blockstates/weathered_limestone_bricks.json abb74e4f4c2b9851670cb6ad794281b0f7be0f5a assets/create/blockstates/weathered_limestone_bricks_slab.json 3262e838fd36d514dad6b86b83402772c0ddfdc5 assets/create/blockstates/weathered_limestone_bricks_stairs.json -c8ac03b4f198f91177a09bc07543ad507b40736b assets/create/blockstates/weathered_limestone_bricks_wall.json +5ebbc4b70baba82da677ade1110277bb012bbe8c assets/create/blockstates/weathered_limestone_bricks_wall.json f02e0d7738c3c3622d9051db7deca7a9de274868 assets/create/blockstates/weathered_limestone_cobblestone.json fd7a9c7095372485081436c91489cadb2b0c514e assets/create/blockstates/weathered_limestone_cobblestone_slab.json 47f8c91ff4c3f5cad782ab469a1fe5f4909dc7f1 assets/create/blockstates/weathered_limestone_cobblestone_stairs.json -dfa5662bfd5a70bcd87673b1c40bf9106d5e2365 assets/create/blockstates/weathered_limestone_cobblestone_wall.json +c60c3115fd6eeaa3a696428a87a74d184ab7d62d assets/create/blockstates/weathered_limestone_cobblestone_wall.json c77b46d8b459e5c7cc495393546f3fcca8a1fa1d assets/create/blockstates/weathered_limestone_pillar.json 512bf17c9ea309b1f7da54440f923530d25e467c assets/create/blockstates/white_sail.json 4647010162eb4c350fad236d860317eaa1884c77 assets/create/blockstates/white_seat.json @@ -404,26 +401,26 @@ a3a11524cd3515fc01d905767b4b7ea782adaf03 assets/create/blockstates/yellow_seat.j 6801fa1f466f172700e573e5b8ee8ee5f9ca4583 assets/create/blockstates/yellow_valve_handle.json 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json -374efe0548d096c895b0159c0a3895e5f66d50c9 assets/create/lang/en_ud.json -3d5377d3e032225b8d2ac1cd465492f25c236dea assets/create/lang/en_us.json -ab9eec4d6a86d2c62e7fedfe7ff860827fa6957b assets/create/lang/unfinished/de_de.json -4fcababee7ff5b9eb2efc31b4794d0b65abea420 assets/create/lang/unfinished/es_es.json -e5ae6de5f3516476c25d44398a9f20fc3230df57 assets/create/lang/unfinished/es_mx.json -e135cee1220f5e579c9cedf7fdcb2cd00ad16d00 assets/create/lang/unfinished/fr_fr.json -9c71c9e53a051c024dab2e85faf751e3693b1ff2 assets/create/lang/unfinished/it_it.json -f853350b47f69ec56fc70f7d7f2f35da3904ee15 assets/create/lang/unfinished/ja_jp.json -d540b44a3528fb3167263ba4cedc39e2de088d19 assets/create/lang/unfinished/ko_kr.json -259d929e4cc0d3b8f1292e771541659303cd321f assets/create/lang/unfinished/nl_nl.json -0342519553ed670c13cfaf75b425ef8242f81024 assets/create/lang/unfinished/pt_br.json -3b48571a2e06670ba0fb7c92c52cd84ce258a07d assets/create/lang/unfinished/ru_ru.json -cc982d4bb52797978f1274c7b5c3339b20c6b288 assets/create/lang/unfinished/zh_cn.json -2fe73383e29814153d532ddb3ef1f6add62c6a8c assets/create/lang/unfinished/zh_tw.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 -1358ff546e99004444fccca5355853d1738ef191 assets/create/models/block/acacia_window_pane_post.json -bd33b944ec6ad89850a1d275b3d2843fe6f831cc assets/create/models/block/acacia_window_pane_side.json -b272035cd746364a0bd3bf13061f51190e9b46d6 assets/create/models/block/acacia_window_pane_side_alt.json +2b12f3cf99e498899207a8c4855210e7b5dc55cd assets/create/lang/en_ud.json +e371fd4fccf90c4ee6f2fbea91ea5d70e3d6c652 assets/create/lang/en_us.json +610a33e7074c3fb8e88370bed76549bfcfe0eddb assets/create/lang/unfinished/de_de.json +29339e0bf9743251639a2598d17f194cd406602c assets/create/lang/unfinished/es_es.json +e7138596de0babd4fc90a4b8ffb8fdea13088086 assets/create/lang/unfinished/es_mx.json +a95f57787534ae5d4920fe8e4825fe3012fdcd70 assets/create/lang/unfinished/fr_fr.json +7956b67df2d19a9f890f893c9d736516cc6e8629 assets/create/lang/unfinished/it_it.json +95394f8cc9d53397e030c46a9abef4fa4348e2ad assets/create/lang/unfinished/ja_jp.json +edcd5ffe8239f13cedbd63ab11c8334a38b90c90 assets/create/lang/unfinished/ko_kr.json +1749d2d020f02a2ccca4698d85bfdc4dcf849e3f assets/create/lang/unfinished/nl_nl.json +83c43209c295b3d3d85f7bebaa9a8ce7b79d47da assets/create/lang/unfinished/pt_br.json +a1a67295a2fe537080254fc8b353699d4d30989a assets/create/lang/unfinished/ru_ru.json +a525852b4f3aa0af52816e02e5cf4181de0c60c5 assets/create/lang/unfinished/zh_cn.json +51242fa9de9994103e9373e5c8dd6941438ec9a8 assets/create/lang/unfinished/zh_tw.json +846200eb548d3bfa2e77b41039de159b4b6cfb45 assets/create/models/block/acacia_window.json +1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets/create/models/block/acacia_window_pane_noside.json +1763ea2c9b981d187f5031ba608f3d5d3be3986a assets/create/models/block/acacia_window_pane_noside_alt.json +7d23c8e4543108f5f53b78ccb4908f7a5bb76c54 assets/create/models/block/acacia_window_pane_post.json +3bdcc6bd616a179ffc22e66307aab538e9bcb75f assets/create/models/block/acacia_window_pane_side.json +7b5b6809e3ef685a497ba15b549d3918aeb6c135 assets/create/models/block/acacia_window_pane_side_alt.json 8e1e834bab1c09591006a063216e93c832503852 assets/create/models/block/adjustable_chain_gearshift_end_horizontal.json 5d3d8b3989b087a5e9177951e9246f27a1838e84 assets/create/models/block/adjustable_chain_gearshift_end_horizontal_powered.json 0ae6c67468b448f2f05c06f41bb162fafd86846a assets/create/models/block/adjustable_chain_gearshift_end_vertical.json @@ -435,62 +432,56 @@ c3fdfa0ef84a598a17b2194fd0ea56fb323441d6 assets/create/models/block/adjustable_c 221b65e4fed640dc77f8ec5fee300f2a199d05b1 assets/create/models/block/adjustable_chain_gearshift_single.json ef644b33e136692c19cf8e79fcd28431b40dbb62 assets/create/models/block/adjustable_chain_gearshift_single_powered.json 68ad5cab7a32235aabf060f05d72d5a2dcfd0e74 assets/create/models/block/adjustable_pulse_repeater_powered.json -2c88abbdca1e59f971f28276477a24d81bee93e8 assets/create/models/block/adjustable_pulse_repeater_powered_powering.json -fde9ff3520cd7d2cc2926cf95cad8c7ec5bdcae9 assets/create/models/block/adjustable_pulse_repeater_powering.json +415d9426fae5e6db7d09c9813d96db940e383eb7 assets/create/models/block/adjustable_pulse_repeater_powered_powering.json +cda6f9761431c5b8538f746db2dc55e5fb57bf01 assets/create/models/block/adjustable_pulse_repeater_powering.json ce5e0cd1598cf2228bb77a68c304dd210f3848f8 assets/create/models/block/adjustable_repeater_powered.json -b62a75c96400bf75287091ce324727f00754bf31 assets/create/models/block/adjustable_repeater_powered_powering.json -ea279b9b1a2d1eab8a69e5e35627ada170013b89 assets/create/models/block/adjustable_repeater_powering.json -10832d276445d8a5f94413de1979349db1364ec4 assets/create/models/block/andesite_belt_funnel__extended.json -d01611179d3ed6c013f4f649127239772cbdeba3 assets/create/models/block/andesite_belt_funnel__powered_extended.json -ed52e27fd7d645c25dc9dc58a44f29be12cb6d5e assets/create/models/block/andesite_belt_funnel__powered_pulling.json -3c8ed64100de95994580a8e6e24c7b72f2332081 assets/create/models/block/andesite_belt_funnel__powered_pushing.json -240230f29d092505d47c83ae59f5c908e4bf4932 assets/create/models/block/andesite_belt_funnel__powered_retracted.json -c862af2b37ccfd0123e9e96a5400be82033bbdd3 assets/create/models/block/andesite_belt_funnel__pulling.json -884aaf754de0bfd51690aab6e01f775419728cf7 assets/create/models/block/andesite_belt_funnel__pushing.json -7b1888eec72c04677a3dfb709b04ad10d08d74d0 assets/create/models/block/andesite_belt_funnel__retracted.json -de448acc19ddd984f2599ce9ce5bf9489235fdc9 assets/create/models/block/andesite_bricks.json -3d285d395c45662a0ffe89c0259f519285cae899 assets/create/models/block/andesite_bricks_slab.json -6eecf3e3d3f184aa69d224bbb3b82b5164a8726b assets/create/models/block/andesite_bricks_slab_top.json -5faa0ffc6dc62b2391bbace7a5f0179a8ab92e6b assets/create/models/block/andesite_bricks_stairs.json -be7f1cbd9489e19a8b928438958a02f437a5d244 assets/create/models/block/andesite_bricks_stairs_inner.json -4658bf73f575628caa11f8fc28470209c5904d81 assets/create/models/block/andesite_bricks_stairs_outer.json -ce05c7fe01f1d491359f4db7914d9dfe44146c90 assets/create/models/block/andesite_bricks_wall_post.json -1d58235e937f342affb387192a62971a68c56051 assets/create/models/block/andesite_bricks_wall_side.json -602f741fe0594836ee81b1711f1bbcc7bca4c6b1 assets/create/models/block/andesite_bricks_wall_side_tall.json -4e44ccdc5e396c4380a7e59408db50553fa25226 assets/create/models/block/andesite_casing.json -33a3e4b7d78044e740d8ac8b6ac21bceaaf3d614 assets/create/models/block/andesite_cobblestone.json -67040762d99792f187257458325df4a1733a4fc1 assets/create/models/block/andesite_cobblestone_slab.json -97f69cb74150b1c8a04bb27bf741471c9b942af0 assets/create/models/block/andesite_cobblestone_slab_top.json -0c63e71a38b0c8fe3c45f84b587f78481619c5d1 assets/create/models/block/andesite_cobblestone_stairs.json -873148d69e4c4bbec96450dac544db11117d165a assets/create/models/block/andesite_cobblestone_stairs_inner.json -4005ee3942885a589648258fb1e140e08835e484 assets/create/models/block/andesite_cobblestone_stairs_outer.json -ea94d40df307d5792934bc532fc2d24d50efe756 assets/create/models/block/andesite_cobblestone_wall_post.json -aa5b45c6c657436bd38621344f6728d44ea974ad assets/create/models/block/andesite_cobblestone_wall_side.json -7c0e71f479aeef7bf02f0fb76c4333fa2227b83e assets/create/models/block/andesite_cobblestone_wall_side_tall.json -7d5faceb2a8d67acddd39625da6d5853f07ea8bd assets/create/models/block/andesite_funnel_ceiling_pull.json -82393ded7287660d16549e321317dfe4488cc81d assets/create/models/block/andesite_funnel_ceiling_pull_powered.json -40d7adae3b5eecd8ed08445b2d7f43d7a0684837 assets/create/models/block/andesite_funnel_ceiling_push.json -940cace1d38fef0d5d88a391b0ba8cf690b38a44 assets/create/models/block/andesite_funnel_ceiling_push_powered.json -c77c660ea142419e93754c9702445c269dbcd0cc assets/create/models/block/andesite_funnel_floor_pull.json -16d402c764364254a704a13736bd68455edc28ba assets/create/models/block/andesite_funnel_floor_pull_powered.json -6a809d0e0e53b845b587276444cb7b64a1e15e81 assets/create/models/block/andesite_funnel_floor_push.json -6eac3e4f593e4182f5c216a900136a62ea953fb5 assets/create/models/block/andesite_funnel_floor_push_powered.json -cc187c98c62b47f5bdb6e5187f52d3d927486376 assets/create/models/block/andesite_funnel_wall_pull.json -525cf080df53a428d1321d25c2021b5f3b80a4e6 assets/create/models/block/andesite_funnel_wall_pull_powered.json -78fcd6a91a84f5824e3e0006609b6f01760238d4 assets/create/models/block/andesite_funnel_wall_push.json -6c48d1a0b8cb007a6eddaa9b2f6cb8a98334d34e assets/create/models/block/andesite_funnel_wall_push_powered.json -f77390658e8aeed4352e47b94fd24df116ea1857 assets/create/models/block/andesite_pillar.json -2294f74b5c30430de89a345af60f6669c975f33a assets/create/models/block/andesite_tunnel/cross.json -17f860947f51e84a3f9b32b10cdf61f863db3afc assets/create/models/block/andesite_tunnel/straight.json -e74aa39f8142293c202e57dbd92e8660818b18b5 assets/create/models/block/andesite_tunnel/t_left.json -c93978d636fe70d456a6e1914b65527cbc18544c assets/create/models/block/andesite_tunnel/t_right.json -2a86780c6825edce8fbdaa118a267fc09ce410b0 assets/create/models/block/andesite_tunnel/window.json -0ce09f6fdfb07dead5936c118efb4064f2f6f50f assets/create/models/block/birch_window.json -a5f0ed76e27d2ca706445f7f7c5f9270f98e34f9 assets/create/models/block/birch_window_pane_noside.json -9ad5224419ab7165c5208852bc4a4a5e65dcbf83 assets/create/models/block/birch_window_pane_noside_alt.json -f40c4d4ea6c037158f4b9862a7c11e6024a261e6 assets/create/models/block/birch_window_pane_post.json -dbfd2a996820d885d9741a3f168aa36c3538cfbd assets/create/models/block/birch_window_pane_side.json -557b35671ec417597259ba8d0239fe18c14c3d20 assets/create/models/block/birch_window_pane_side_alt.json +c82a31943f5adb4a64c6db4c48c94cbce5d95bc4 assets/create/models/block/adjustable_repeater_powered_powering.json +51cf61f8bc25cf62b0e0c0705c75512809358ff0 assets/create/models/block/adjustable_repeater_powering.json +bcbe466da8b2172aa0f6e5c846b2e261632ceb6b assets/create/models/block/andesite_belt_funnel__extended.json +9218b0a053911071dbde66fdc97de7485a08c54e assets/create/models/block/andesite_belt_funnel__powered_extended.json +433daa4b4cb4b6bc12918b2e78c2141d941e78d8 assets/create/models/block/andesite_belt_funnel__powered_pulling.json +a3581f92b80a7adf2f933cfbeda43f88db7d8615 assets/create/models/block/andesite_belt_funnel__powered_pushing.json +14b6689a3c67bfb4fddbd062e9bdb0957e228a8c assets/create/models/block/andesite_belt_funnel__powered_retracted.json +657f22838ee3e8719fa33e1f85034043c4907310 assets/create/models/block/andesite_belt_funnel__pulling.json +59016d8f76df2920437168368cfba47bbf19d214 assets/create/models/block/andesite_belt_funnel__pushing.json +997495a40f20d13a6b7f6083bb8f519ff107ca28 assets/create/models/block/andesite_belt_funnel__retracted.json +4d412de3eb98dfee548a0dcdbae5d0168ac67123 assets/create/models/block/andesite_bricks.json +054ef3fff7f146dbf8adc92dc2b6d169c2bdb7a5 assets/create/models/block/andesite_bricks_slab.json +8784414839f6a5786bf43d6a7dff6c27bdf7fe46 assets/create/models/block/andesite_bricks_slab_top.json +65e606737196fbc94a3a18601db6eeaf7eb18414 assets/create/models/block/andesite_bricks_stairs.json +71e05082703286f237ccfd1f353da86da4f67aeb assets/create/models/block/andesite_bricks_stairs_inner.json +87d60652c7ceb8f03a26c2e0853243d1f397555a assets/create/models/block/andesite_bricks_stairs_outer.json +f0a955282f7abd5ce0b412ec7b59024113ca970a assets/create/models/block/andesite_bricks_wall_post.json +0ed2fa65af49b5c92c4e5c688c155e37d3d6b118 assets/create/models/block/andesite_bricks_wall_side.json +b9943c5585fc081385ea49a4199efeb6c7c22423 assets/create/models/block/andesite_casing.json +77a045e855eb37d2da7ed8f7d27a85b9546c0ab8 assets/create/models/block/andesite_cobblestone.json +7d816d54c85bc7d0cc8db9c68abcba960daa7b43 assets/create/models/block/andesite_cobblestone_slab.json +5179ecd1f926bf3211a1a3f033dfd1d2368eeb20 assets/create/models/block/andesite_cobblestone_slab_top.json +2c0fd862bbbfa1cef2d418661ed180e39b0a3988 assets/create/models/block/andesite_cobblestone_stairs.json +ad255a62a5f54b578db06e89fd7160001f905675 assets/create/models/block/andesite_cobblestone_stairs_inner.json +a033fbac3129bba9211c6c4a0e16c905643afa39 assets/create/models/block/andesite_cobblestone_stairs_outer.json +1c574ee47aeb6fcb305bfc95dd131e153b795a0e assets/create/models/block/andesite_cobblestone_wall_post.json +0ed983628e8868f77301bea1111570d3631f24fb assets/create/models/block/andesite_cobblestone_wall_side.json +8d4e4a7c6ad6d45c7aa7ca3105a025511571ff26 assets/create/models/block/andesite_funnel_horizontal_pull.json +9841d6a09a09bf4d5d6a39bdc4904d86b3a825f8 assets/create/models/block/andesite_funnel_horizontal_pull_powered.json +86d5df6e365d9b2e9682f0839f61058360828ba2 assets/create/models/block/andesite_funnel_horizontal_push.json +50af1ff6ce9af162d4e438f21952c7215608dc8e assets/create/models/block/andesite_funnel_horizontal_push_powered.json +75c914bf9448e25fd01d597de48375a9782bef36 assets/create/models/block/andesite_funnel_vertical_filterless_pull.json +4d70a221809f5bc598a0a0e98bd152e9ab7a2f7f assets/create/models/block/andesite_funnel_vertical_filterless_pull_powered.json +a41c7351513a9514dfdc0fc552b646b1d715c977 assets/create/models/block/andesite_funnel_vertical_filterless_push.json +e7931f28887baadd52ac988fc8eeeb84ee6f0d27 assets/create/models/block/andesite_funnel_vertical_filterless_push_powered.json +b1d0bb538fc8285b7d3fd77a977d78a104b83b62 assets/create/models/block/andesite_pillar.json +aaf2e4259bcfcedd3400e9acb2d64c0cf06f7fb1 assets/create/models/block/andesite_tunnel/cross.json +75f628178fa21a2bd301eea8d1cebf7e94f7d5cc assets/create/models/block/andesite_tunnel/straight.json +c9aec5c30e6821c8f125202cad236afa48f6c358 assets/create/models/block/andesite_tunnel/t_left.json +1dcb8fe81a275ef8a49c04db021ad29abe8b38ae assets/create/models/block/andesite_tunnel/t_right.json +e2801a0c3fe8e1c2485291485b977f581fdc8b7c assets/create/models/block/andesite_tunnel/window.json +87f90e8256060683b834d57d3c11248d5ea84e34 assets/create/models/block/birch_window.json +94317904054cbf651846716d8af3bca618d3130f assets/create/models/block/birch_window_pane_noside.json +7a4cae5b075c4ac96a3113afafa391d024fc117f assets/create/models/block/birch_window_pane_noside_alt.json +3905ced5892afa60009bf26279f9fa4756c273d4 assets/create/models/block/birch_window_pane_post.json +62b3f2edc5ef5d7dabbcff19220921b0e3582376 assets/create/models/block/birch_window_pane_side.json +95d4230eb366f5e7684820c9337e3956ed34042a assets/create/models/block/birch_window_pane_side_alt.json 2b59d6f937cd542eba670689c30fe16887dfd9a0 assets/create/models/block/black_sail.json 97d79ab99c0fb278a9b5dc54e1c6563868f87b76 assets/create/models/block/black_seat.json 02747ea1a0e5d4a1cd466bf26878885a89d347fa assets/create/models/block/black_valve_handle.json @@ -517,20 +508,16 @@ bc23a91f300e46761bb14c597fad39c3d414e84d assets/create/models/block/brass_belt_f dfc6250e28e12ff193a45891978ec50c406fc0c2 assets/create/models/block/brass_belt_funnel__pulling.json 5409325494780afe32e6e30377314e2992ca4aa5 assets/create/models/block/brass_belt_funnel__pushing.json 97410a12b7c1461f88fb633f26ff566a0636b627 assets/create/models/block/brass_belt_funnel__retracted.json -5adb8b446817eee3a31971d708320c7104d6bbd8 assets/create/models/block/brass_block.json -2e67c147d7c69aabd9ab9f7aa80f60671d5a03aa assets/create/models/block/brass_casing.json -f5f689dc8be53e560878d3dde7b6eda6b3bf28e3 assets/create/models/block/brass_funnel_ceiling_pull.json -142a56e522c74268d0b418985eb3fd285e371295 assets/create/models/block/brass_funnel_ceiling_pull_powered.json -e583d701961b68223778d28edc0e2686c1a5c5df assets/create/models/block/brass_funnel_ceiling_push.json -ccb2b596c3f190c26fdec06dd2b53ac3e59b1ff2 assets/create/models/block/brass_funnel_ceiling_push_powered.json -7f541d8235326fea3ecb370c4cf2913867f439ad assets/create/models/block/brass_funnel_floor_pull.json -5277d7c614991a5bce0e9234c4094f02c6d201c2 assets/create/models/block/brass_funnel_floor_pull_powered.json -1831d87b5a9784c12cecefbb9d3173c29f4ddc87 assets/create/models/block/brass_funnel_floor_push.json -6aee078641719086c9a98ebd1c0d0d61cd4d33a9 assets/create/models/block/brass_funnel_floor_push_powered.json -aa86ddeeb41aea5bd85dd488d932fbc913828b1f assets/create/models/block/brass_funnel_wall_pull.json -161b420ee4f41d436177e20314dcbe61ecec53a8 assets/create/models/block/brass_funnel_wall_pull_powered.json -24362e71ca3a6d0f2dbf129909eceb8b3937a66b assets/create/models/block/brass_funnel_wall_push.json -76cdebba3116be88926d9640917e579377ef3134 assets/create/models/block/brass_funnel_wall_push_powered.json +71d0ad31d89d4ea3f243c6003b17f57fd168c933 assets/create/models/block/brass_block.json +166a5c053a81e6aadc24509ed24dc144a7255969 assets/create/models/block/brass_casing.json +f7fd1f49857eca94e4135e65c85127510d666e4f assets/create/models/block/brass_funnel_horizontal_pull.json +45a23298ad03fd3b5dc2757dcd7edc18b8cce222 assets/create/models/block/brass_funnel_horizontal_pull_powered.json +a9fc7210d44b47202438668f11b31099e82c9ebd assets/create/models/block/brass_funnel_horizontal_push.json +4049bf503ec2ee22412c59e05299de20319b0dc6 assets/create/models/block/brass_funnel_horizontal_push_powered.json +320e377a4380ac637bff2e0535f229c52d886437 assets/create/models/block/brass_funnel_vertical_pull.json +28c2f8ca6403f98b82e3a0eadb608a41490cc96f assets/create/models/block/brass_funnel_vertical_pull_powered.json +c4c46d47854c9a6cf8f410006a35bbc8e599f0d5 assets/create/models/block/brass_funnel_vertical_push.json +fd6f6607a4742fa87dfe1768927a29dc4975ce7a assets/create/models/block/brass_funnel_vertical_push_powered.json 520087db8d479c66f85f3483af813fb668f27503 assets/create/models/block/brass_tunnel/cross.json 347ed67bf3426e323354e2d959fc9563dc7eeecd assets/create/models/block/brass_tunnel/straight.json a959e03ca339badb49fe58ba53d86a84352e91f3 assets/create/models/block/brass_tunnel/t_left.json @@ -539,15 +526,15 @@ a0612a633756433e1b37ddc6d290aa1fc07839ef assets/create/models/block/brass_tunnel 8ab097caaa0db0915ae9254f7d65092d9171bc60 assets/create/models/block/brown_sail.json 4eed0ad902f5e84f2b6c160f3283e8028640e77d assets/create/models/block/brown_seat.json 6c39677f8c3a84280835c717ea1ef569b7c76a1b assets/create/models/block/brown_valve_handle.json -db7279f05c1d89e21da8887a15d3a1cfff4a9cf2 assets/create/models/block/chiseled_dark_scoria.json -22d4ad2de48739ab754f8dfcd6f84ad2267abf8b assets/create/models/block/chiseled_dolomite.json -550dc0622377b4736610b1c924dc890c857a0fd0 assets/create/models/block/chiseled_gabbro.json -1deb93125b9a8cac79bec1f4ea5345d6ea857656 assets/create/models/block/chiseled_limestone.json -1cf4b68c8cf1885ede334fbfa54e52c76ba211b6 assets/create/models/block/chiseled_scoria.json -041a20dd674277ff4f1613a0a89600f05458edf4 assets/create/models/block/chiseled_weathered_limestone.json +028a07b49c05fe8a93f1d8c229d81e73d887c2df assets/create/models/block/chiseled_dark_scoria.json +b1f9ee4867373dd8f976625bab744a1c72c7fd16 assets/create/models/block/chiseled_dolomite.json +cd7751090cf3d55296b8e415d0af9b6f18d69770 assets/create/models/block/chiseled_gabbro.json +d2e195aa2e90c712e51d855a9a4a334b52f62a69 assets/create/models/block/chiseled_limestone.json +ac07568fa7b2d3fa84d0fe89a498514d30514291 assets/create/models/block/chiseled_scoria.json +ecb2b85ee210dce329d2be66b98d0f0d4e6fc223 assets/create/models/block/chiseled_weathered_limestone.json 4156227e18c0896ce83f260f71b939abbbf4f01e assets/create/models/block/chocolate.json 30fe120af3cb32faf0729df4d2cdf868f804be17 assets/create/models/block/clockwork_bearing.json -1f01a4b6608f75145734b60ddf4a33ce318425ff assets/create/models/block/copper_casing.json +70406933cc4fa5471af6e562fd84a397347dba17 assets/create/models/block/copper_casing.json b2c528cfd24a5cb0cb96c45d0a914f1090f8c32b assets/create/models/block/copper_valve_handle.json 1ef7060b0ca7e9c0bfc8151f98ca08da31862cda assets/create/models/block/crate/brass/bottom.json 4ef2c7c3018f2d219f159a3ce58ceb00610b9c5d assets/create/models/block/crate/brass/left.json @@ -583,161 +570,140 @@ feed58a4ad7d7a9e855f0cd7b3fc720616120b4b assets/create/models/block/creative_sin 59c43cc18525792ca96026c966076f52cf7ebef7 assets/create/models/block/creative_top_window_nw.json a6eea01609266b757342984889af16234ecd5189 assets/create/models/block/creative_top_window_se.json 6e1d2fb66291f2a3e3a213f43b47fb9760cb959f assets/create/models/block/creative_top_window_sw.json -8390ebba3a149135c21a3e48fcc84660eea5f766 assets/create/models/block/crimson_window.json -5e0c0ac8b2d222bb359a84a1f179c54c823ad5b8 assets/create/models/block/crimson_window_pane_noside.json -19503fe4a6eec4d250efb1a7a4fe53fd1035b429 assets/create/models/block/crimson_window_pane_noside_alt.json -14a14ab7c1a812a5ac8e282747f125461bf6b1d5 assets/create/models/block/crimson_window_pane_post.json -b9e6d8befe3f2281413288e0350425987256e238 assets/create/models/block/crimson_window_pane_side.json -bcbfa40524cff0314d9e764a64f90f2095d14064 assets/create/models/block/crimson_window_pane_side_alt.json 68843a02a32c156afad85830877b83f9b51c5147 assets/create/models/block/cyan_sail.json 6704782830b3d872321e895b6903709c18e3778f assets/create/models/block/cyan_seat.json f45ef4a5f0aa8482d493661673b1c0ab6d061157 assets/create/models/block/cyan_valve_handle.json -f5ac5007454cb04490e36f39e9047cc90501b2f6 assets/create/models/block/dark_oak_window.json -d1914f0b453d360221b14ff128f5a5040441a0c6 assets/create/models/block/dark_oak_window_pane_noside.json -ebee7c581235fb4166862c238469bf7c81bf0b8c assets/create/models/block/dark_oak_window_pane_noside_alt.json -92f856a51b8cf433beed6aebea70304062e0073b assets/create/models/block/dark_oak_window_pane_post.json -7be662a7534de3932eb0790a0387ba4049938e0d assets/create/models/block/dark_oak_window_pane_side.json -22a3f10d9c541c5503fa7c1a4d5caef06f53f287 assets/create/models/block/dark_oak_window_pane_side_alt.json -b9f6de353a4ed2ff9d62f74689a38a1b7b42fda4 assets/create/models/block/dark_scoria.json -6d383bf3ac6f8cfce8ec8aae8c04d0fdbe9188bb assets/create/models/block/dark_scoria_bricks.json -6679044b854314fb6879e8949091ea546b508ea7 assets/create/models/block/dark_scoria_bricks_slab.json -a93395d01c2a7ecb1e9b9d515f6ef1cf54a08c98 assets/create/models/block/dark_scoria_bricks_slab_top.json -cee30fc817760cb285089cdf8e6b7aeb12ba32f2 assets/create/models/block/dark_scoria_bricks_stairs.json -ebb4ce21338cc316771b3418e0ff3a5f49692315 assets/create/models/block/dark_scoria_bricks_stairs_inner.json -74ff3f848dd7cef18af53ccd9de37888f71e3a7f assets/create/models/block/dark_scoria_bricks_stairs_outer.json -4f71dba3766029e91fb83a16f63056951fa2a0f5 assets/create/models/block/dark_scoria_bricks_wall_post.json -338dcf43999be383a266a6b8feb4f6b4b289b2c2 assets/create/models/block/dark_scoria_bricks_wall_side.json -c5f03f56a1985b7d803fab74af8e941c56a74656 assets/create/models/block/dark_scoria_bricks_wall_side_tall.json -f6df99387ebcd3b113049cec593b329b4edc201c assets/create/models/block/dark_scoria_cobblestone.json -2a9117f1ac977628134417e1653374353d5d7478 assets/create/models/block/dark_scoria_cobblestone_slab.json -7f336fc5adec46c56316f3fea57499a3c75d125a assets/create/models/block/dark_scoria_cobblestone_slab_top.json -3e5a8b25291f34b865d0ed982a3a5a993466dbbd assets/create/models/block/dark_scoria_cobblestone_stairs.json -85a8a9e4cafee7cbce29ee02e8da0d7397eecd8b assets/create/models/block/dark_scoria_cobblestone_stairs_inner.json -1bf11c6ac8323110c082fb7631cab9670e85fabb assets/create/models/block/dark_scoria_cobblestone_stairs_outer.json -607f2f3fde2cb651170996ca54b548f78f57fc01 assets/create/models/block/dark_scoria_cobblestone_wall_post.json -81a6b3b17aeaab343cc2118af09c42609a672e05 assets/create/models/block/dark_scoria_cobblestone_wall_side.json -4d87cf568af6d547c1aa37a19d245d9803f71c48 assets/create/models/block/dark_scoria_cobblestone_wall_side_tall.json -ef13cb3904ae5a58c1ee1d5c5f4890100b2c83e6 assets/create/models/block/dark_scoria_pillar.json -14185f85fa40aca8faac0db0a49caf1d7c447e6b assets/create/models/block/diorite_bricks.json -0256c5fbd1d17ef12eb669f7fa3d19286987b757 assets/create/models/block/diorite_bricks_slab.json -4e75faf1a393aa7ae9f0126a5af4fb076bbe45b8 assets/create/models/block/diorite_bricks_slab_top.json -f221cdc538812bacff510292ccab09703b483d92 assets/create/models/block/diorite_bricks_stairs.json -4d7fcffcb3819dc30b936f6f0736e76842025e01 assets/create/models/block/diorite_bricks_stairs_inner.json -a1ce8c61ca6e8f3d8bb8a369e3b9615d6c64b37d assets/create/models/block/diorite_bricks_stairs_outer.json -51dca9272e4eb965ece1744ce46c295eeaccc587 assets/create/models/block/diorite_bricks_wall_post.json -5b7fcebc241c23a46bfe561f5c50e53bd70df589 assets/create/models/block/diorite_bricks_wall_side.json -8011a39fe0edaf13013a4885c6137994ad72d35b assets/create/models/block/diorite_bricks_wall_side_tall.json -268a5c6bdb9203ddb657295d5478abbb1e383d92 assets/create/models/block/diorite_cobblestone.json -83d0e0a294b7879be1a526f781bac8df9e74d061 assets/create/models/block/diorite_cobblestone_slab.json -c129369c66e8ab9d58f22e69a706a6fbc49540d6 assets/create/models/block/diorite_cobblestone_slab_top.json -e913be24e7701292ed37f5efe35f670edb7b8383 assets/create/models/block/diorite_cobblestone_stairs.json -7c3c7e3b00c1db496d8ff51a004c18362dad4252 assets/create/models/block/diorite_cobblestone_stairs_inner.json -da009814dd8ce2d15212c8f7e9af3a60a1680e99 assets/create/models/block/diorite_cobblestone_stairs_outer.json -e839463ea43e5e5eb88c2c3d37b86d6dd934d8b0 assets/create/models/block/diorite_cobblestone_wall_post.json -4c4d40cfe1b2a03584e1b2998a48392efe50d2e4 assets/create/models/block/diorite_cobblestone_wall_side.json -8ef4bc97a1e61e4604f1b774c95fcd5f75efb93b assets/create/models/block/diorite_cobblestone_wall_side_tall.json -8d6c9b0f04df490a538fafd221f96f41d530b027 assets/create/models/block/diorite_pillar.json -8a542f001f83a6fec09205b01f95de98e4c7b9e2 assets/create/models/block/dolomite.json -d14d17594c7f082d5116a98fde7cc3e89d2994f0 assets/create/models/block/dolomite_bricks.json -1b8c1706838ee851c08b48dc5319cb050127f7b6 assets/create/models/block/dolomite_bricks_slab.json -40e83ceb543602e7ac492539fb1c82623326744d assets/create/models/block/dolomite_bricks_slab_top.json -941becbb7b24aba402d9c1a8469e5c4474d5796e assets/create/models/block/dolomite_bricks_stairs.json -6a2a86684046ebdc1896c558e5074a4fb264b4cc assets/create/models/block/dolomite_bricks_stairs_inner.json -10930b8099f3debbcc6d9cbebf4f1e06f6efec67 assets/create/models/block/dolomite_bricks_stairs_outer.json -865f13731f268738bc4f5abf4c8508f51bcf5d8d assets/create/models/block/dolomite_bricks_wall_post.json -67063dc664eaf25284a4db772d11514163950835 assets/create/models/block/dolomite_bricks_wall_side.json -edfe903d4b7114903579d463a9f646471de88f04 assets/create/models/block/dolomite_bricks_wall_side_tall.json -d1dbbc57d2a83e02b2af81e91dcd3b4b5e3d4975 assets/create/models/block/dolomite_cobblestone.json -693da6d55884a0cad25dc4c8cce4f031d8074573 assets/create/models/block/dolomite_cobblestone_slab.json -5c2083992e0be36cbdf71f07117793ab1bc85e40 assets/create/models/block/dolomite_cobblestone_slab_top.json -509bb35202791d0fcfb3374e340e7469c280c68a assets/create/models/block/dolomite_cobblestone_stairs.json -b0bb64b0d78f767ced3622a7231f52f6b6f6bbbe assets/create/models/block/dolomite_cobblestone_stairs_inner.json -f5322b52daff06bd1ebf87415b8e333e66d22920 assets/create/models/block/dolomite_cobblestone_stairs_outer.json -dba1df027963cddf283d81ab014f9fc4a8efe5fb assets/create/models/block/dolomite_cobblestone_wall_post.json -f09c30ce1edfa2e59b56d17a76243cefc1c78dd6 assets/create/models/block/dolomite_cobblestone_wall_side.json -e38a985deccedf9eeff61ae268c181bb5bfff224 assets/create/models/block/dolomite_cobblestone_wall_side_tall.json -5e39ecedd6d79b5b858a10722df8d6bb35bf7de9 assets/create/models/block/dolomite_pillar.json -489c20dc7506d73e128c3113d52912a651c5ced0 assets/create/models/block/fancy_andesite_bricks.json -cbfafcd4723fb660637a631bfdcf014097c72b36 assets/create/models/block/fancy_andesite_bricks_slab.json -80054d5af2c6ac4cff85acec7060cff0e34e1381 assets/create/models/block/fancy_andesite_bricks_slab_top.json -a96ee6b47596ea0e0ecda2b616ea7ea23d3c67c0 assets/create/models/block/fancy_andesite_bricks_stairs.json -57ac5569dadd908ae2be2456a2235bc294cb96bc assets/create/models/block/fancy_andesite_bricks_stairs_inner.json -70f8a95c1d88fa400f2ed3974efa8254e8da17c1 assets/create/models/block/fancy_andesite_bricks_stairs_outer.json -f170475f5145a9b06a308fb892b1bdd732036cfa assets/create/models/block/fancy_andesite_bricks_wall_post.json -80cdb62798a4f197b31adb9422a6e80443bcb58f assets/create/models/block/fancy_andesite_bricks_wall_side.json -f24d9009e8fd4e702f7211a486b909e7d4a0ed3c assets/create/models/block/fancy_andesite_bricks_wall_side_tall.json -9b18f371a9d56d89e177921b38f1eaa65be25725 assets/create/models/block/fancy_dark_scoria_bricks.json -44f964bb9cedda2557e9a652a144c2198c4a7070 assets/create/models/block/fancy_dark_scoria_bricks_slab.json -1ac687280be50b6f5642ad3a58110a37e6732798 assets/create/models/block/fancy_dark_scoria_bricks_slab_top.json -ff2a5eb23fbc40462ee57b278d605e21edbe2cbf assets/create/models/block/fancy_dark_scoria_bricks_stairs.json -ddacd07e953bf381f2266bcc8b2fed32e7b035aa assets/create/models/block/fancy_dark_scoria_bricks_stairs_inner.json -c24db1bdfc182042ec36b745f36e1f70af4269e9 assets/create/models/block/fancy_dark_scoria_bricks_stairs_outer.json -382cfe4b53714ce461576cfebb92508c2c5b4daf assets/create/models/block/fancy_dark_scoria_bricks_wall_post.json -24aa38a3bd3fe3bc8fc6b6bd73bac3c00d389f49 assets/create/models/block/fancy_dark_scoria_bricks_wall_side.json -60687b5250adbf2899756ffa0f6c521bbf92a0ec assets/create/models/block/fancy_dark_scoria_bricks_wall_side_tall.json -7bb168b8a313a6df7d74a40bcc50b5ac5235a8ad assets/create/models/block/fancy_diorite_bricks.json -87394a268fe9075b21bcaef3197331dd352735c3 assets/create/models/block/fancy_diorite_bricks_slab.json -5ab5b40702b5b238eceb7fe2777aba743759e6c6 assets/create/models/block/fancy_diorite_bricks_slab_top.json -d029ef8b094a38f2e21569372d812c5e616a5cb7 assets/create/models/block/fancy_diorite_bricks_stairs.json -02a0d08ab71c863e8d72b799e2a195e2b6de9c88 assets/create/models/block/fancy_diorite_bricks_stairs_inner.json -158c87cfd4073577da85f81dfee0a0682d84cf28 assets/create/models/block/fancy_diorite_bricks_stairs_outer.json -7735bc449f719196504977a83a6342ea376a4349 assets/create/models/block/fancy_diorite_bricks_wall_post.json -f582b920a09424326ecc1a5ad042673825ddd63a assets/create/models/block/fancy_diorite_bricks_wall_side.json -0e36a523baa20454b4b301d37c7a12d574fb8cfa assets/create/models/block/fancy_diorite_bricks_wall_side_tall.json -649e285e01eee4fba10d411619ed74517aa7c221 assets/create/models/block/fancy_dolomite_bricks.json -5c27d32fe145925bda5fe073b81070a9bec93fb3 assets/create/models/block/fancy_dolomite_bricks_slab.json -8828b7c7142222ba15ef5f76bb347357d28363c8 assets/create/models/block/fancy_dolomite_bricks_slab_top.json -f25ca562e30f56c2f28581e0b85f1546ad02fa7e assets/create/models/block/fancy_dolomite_bricks_stairs.json -3b0bc61f00c744669faaa7bf60dadc58db66b06f assets/create/models/block/fancy_dolomite_bricks_stairs_inner.json -e2a4b49535bff7f72e0aed3384416a98c7e27716 assets/create/models/block/fancy_dolomite_bricks_stairs_outer.json -8d97d5be4053883fe230f5cb2eb2156fbcb164b4 assets/create/models/block/fancy_dolomite_bricks_wall_post.json -8c1f3dcf25aa06f75e238938e3bedb60fc863689 assets/create/models/block/fancy_dolomite_bricks_wall_side.json -6c2ae8aa965a760783fd43726ff3f91beb2a72e2 assets/create/models/block/fancy_dolomite_bricks_wall_side_tall.json -c16aab98fded136e2a41ba14ae4e0475da6062c0 assets/create/models/block/fancy_gabbro_bricks.json -21d497f0899813f81848cc6fc4810e5fe63f521c assets/create/models/block/fancy_gabbro_bricks_slab.json -92dc64333330f35ce3b6f9108f273e52a5bb9e23 assets/create/models/block/fancy_gabbro_bricks_slab_top.json -99d90844f8b855deb428209fe1fc27a2aed35e38 assets/create/models/block/fancy_gabbro_bricks_stairs.json -c1f1052a0a1d39c8bc577f124870df9409d56f5f assets/create/models/block/fancy_gabbro_bricks_stairs_inner.json -b64992036f07b73d3bcd96191c2c29f953efdf2d assets/create/models/block/fancy_gabbro_bricks_stairs_outer.json -f6fac15ca4f51cabac7986eb27f9bc8436798595 assets/create/models/block/fancy_gabbro_bricks_wall_post.json -37ab1882407053ce95934b8eab190005a61b94d3 assets/create/models/block/fancy_gabbro_bricks_wall_side.json -bb1ea3a25950249d5594f2912ad635d15963209b assets/create/models/block/fancy_gabbro_bricks_wall_side_tall.json -56156acd09e621fff1ac20814fb070f074bfb4cd assets/create/models/block/fancy_granite_bricks.json -650e3ef58369cb932e317f0b8f795095201262b2 assets/create/models/block/fancy_granite_bricks_slab.json -21aad26099be9f3f1b0cdd1d65493c99ff803878 assets/create/models/block/fancy_granite_bricks_slab_top.json -49459e34fb078677d7ac3e51c56c2c187a6f7953 assets/create/models/block/fancy_granite_bricks_stairs.json -2b6fc0a03335521f7077abf87a8a6659263d5d1f assets/create/models/block/fancy_granite_bricks_stairs_inner.json -49c9ea8b3d28c1a8b6e3eea656ce33aeca22a5e6 assets/create/models/block/fancy_granite_bricks_stairs_outer.json -983b73c5e40969711a7005736df3150a74856726 assets/create/models/block/fancy_granite_bricks_wall_post.json -aee26644ef11d70260aecfb672f60438ecb6c2a6 assets/create/models/block/fancy_granite_bricks_wall_side.json -b487d415e8907ccdafbc70c7984998854abe7880 assets/create/models/block/fancy_granite_bricks_wall_side_tall.json -8c60c75e807536b05c107bab254ff6ab09b739e1 assets/create/models/block/fancy_limestone_bricks.json -f477c2c20c5cc7bd757e922a0c9355cb19b34f83 assets/create/models/block/fancy_limestone_bricks_slab.json -f00c29d425da90d8b3240b77cfb88ceaf6afab78 assets/create/models/block/fancy_limestone_bricks_slab_top.json -ec4bf9b0617c29fa44aabb23d5054bb17682abba assets/create/models/block/fancy_limestone_bricks_stairs.json -01a463a58c18187c9f79ca64263944bf2ea053c9 assets/create/models/block/fancy_limestone_bricks_stairs_inner.json -fd095f4683a090d1d5cd4e53e8b7456d681db426 assets/create/models/block/fancy_limestone_bricks_stairs_outer.json -98811f6422cdf0e19471ec05615e87c53caf711f assets/create/models/block/fancy_limestone_bricks_wall_post.json -265f732337fe09912c6e0636c653c0bf12f9a5f8 assets/create/models/block/fancy_limestone_bricks_wall_side.json -7c6f56bd05acc6844b99c5757369c0cdebddc12f assets/create/models/block/fancy_limestone_bricks_wall_side_tall.json -7cabc6c5ce879c2f1709fe3367aec4a11ad4cbd9 assets/create/models/block/fancy_scoria_bricks.json -cafb9eb7ba8c18f7ae6067c62facaec9868ebb48 assets/create/models/block/fancy_scoria_bricks_slab.json -290e52d2ff26ce579a64b5476b283f3cfb543bf5 assets/create/models/block/fancy_scoria_bricks_slab_top.json -7b04dc34f640cd56026bc6bc8a64f662c1baa084 assets/create/models/block/fancy_scoria_bricks_stairs.json -b4adb6686f3f761dd8e2acbe443536f2dcd0b521 assets/create/models/block/fancy_scoria_bricks_stairs_inner.json -22e85cfab9ce8519debced054dc513f2df5f3c4f assets/create/models/block/fancy_scoria_bricks_stairs_outer.json -0dd6cdb9c49eac40292047a697b73b0e3f67cadf assets/create/models/block/fancy_scoria_bricks_wall_post.json -2314ae5865cbbc927f16902c270b637ed7657f7a assets/create/models/block/fancy_scoria_bricks_wall_side.json -df83f318dc824d12be532f55302ee67c61b3229a assets/create/models/block/fancy_scoria_bricks_wall_side_tall.json -5b55183ba555f76e42bc53c786be97e51f4d0bf8 assets/create/models/block/fancy_weathered_limestone_bricks.json -b7966bf07ff8272b80b1886a833fe6ab563315bd assets/create/models/block/fancy_weathered_limestone_bricks_slab.json -affca2bf79c86505f0fed32b821af3f65dce73cd assets/create/models/block/fancy_weathered_limestone_bricks_slab_top.json -fef76e7ffc390e3c56222c84fb32f9d92479f259 assets/create/models/block/fancy_weathered_limestone_bricks_stairs.json -f56f3d6a4a678cfd7a8d618c784ce6d7293d0bf4 assets/create/models/block/fancy_weathered_limestone_bricks_stairs_inner.json -c395d4be2554efec583dc940e540f235d459e1c6 assets/create/models/block/fancy_weathered_limestone_bricks_stairs_outer.json -eaedc072f8ae70db3ffb34b0a71ffc2d40387dfe assets/create/models/block/fancy_weathered_limestone_bricks_wall_post.json -fb5797cc9cbe457b7b435164d6a1622e26cf1eac assets/create/models/block/fancy_weathered_limestone_bricks_wall_side.json -dd4011acc0f15444da84461387501a2ee02ad075 assets/create/models/block/fancy_weathered_limestone_bricks_wall_side_tall.json +57e70af1da4e971eca075616b787b70104189d60 assets/create/models/block/dark_oak_window.json +c7b06bc1688f3f9417d38c492d83069f493df78e assets/create/models/block/dark_oak_window_pane_noside.json +3cf8adcb5d1c8f53d2144e1a85bebe593522a34e assets/create/models/block/dark_oak_window_pane_noside_alt.json +6060e8256251807871046edb701ae9af057c6b25 assets/create/models/block/dark_oak_window_pane_post.json +6b548c48245d3f9d0cc8340495f0218c8c76968d assets/create/models/block/dark_oak_window_pane_side.json +a021dc24e218a0d12af8c1defd6eb994f3cd52ef assets/create/models/block/dark_oak_window_pane_side_alt.json +e12bf7ec94790c1fef9db1e0a209ba55b026f39e assets/create/models/block/dark_scoria.json +acbf07b2b9518dd10b03f34a46115432b6e9bf18 assets/create/models/block/dark_scoria_bricks.json +04c07c1c83371d21e79e2f54b89bed840b0b373c assets/create/models/block/dark_scoria_bricks_slab.json +b51e13fa3704c6b731062758e1bb0fdbb8d3b501 assets/create/models/block/dark_scoria_bricks_slab_top.json +f054596722c031e05403d1dfa0ebb873549364f3 assets/create/models/block/dark_scoria_bricks_stairs.json +955b30a1010ae5d1923f9759af86dee1a881d061 assets/create/models/block/dark_scoria_bricks_stairs_inner.json +f4ae0b386bdf3173a8cd30c11993395c5ff6557e assets/create/models/block/dark_scoria_bricks_stairs_outer.json +024df9c96f8004418529cfc2558f4f066eeac21a assets/create/models/block/dark_scoria_bricks_wall_post.json +3cdcc41c6b833d14a00942504c49ff2261aada88 assets/create/models/block/dark_scoria_bricks_wall_side.json +4b0850fdf9ace0f10250692c93196d5620b800ba assets/create/models/block/dark_scoria_cobblestone.json +02a39b76219bb3a52d1947cf7f72cbc1df2fd673 assets/create/models/block/dark_scoria_cobblestone_slab.json +87119cdd2e5a5793e83c534128c1da15e5ea639f assets/create/models/block/dark_scoria_cobblestone_slab_top.json +203f4fd2cfaba624620a352f6d65ba58f0412a40 assets/create/models/block/dark_scoria_cobblestone_stairs.json +4a78513a157ee7c5ed7ccaadd2bf8954268c203b assets/create/models/block/dark_scoria_cobblestone_stairs_inner.json +868362ffc0331d24e35407a27b65cbfa94c538af assets/create/models/block/dark_scoria_cobblestone_stairs_outer.json +310c6ec1d83a7731ca4baac0ebddf1b508ce1c70 assets/create/models/block/dark_scoria_cobblestone_wall_post.json +fe7666edd1e5117384c4ff032cc25cd06175df24 assets/create/models/block/dark_scoria_cobblestone_wall_side.json +b29e7589789628ddc180e146aab70ad70a461ccf assets/create/models/block/dark_scoria_pillar.json +b021c62e9c164d37bee0af97a75a0fb91dd1c9ef assets/create/models/block/diorite_bricks.json +2820f2976d73deed740356fcd19cfb4f4f493f9f assets/create/models/block/diorite_bricks_slab.json +5fb8e28b42b803199c6347f27fb06480f2d637bf assets/create/models/block/diorite_bricks_slab_top.json +70fe07eb3b04286b165d5f2e9b5fe1e75e85ad1e assets/create/models/block/diorite_bricks_stairs.json +aa23e5c6f5f3be1e7cb57f03fe044b2c6a4cfea5 assets/create/models/block/diorite_bricks_stairs_inner.json +e8dfebbc0d53bc707daafff42461fa58f4d568c4 assets/create/models/block/diorite_bricks_stairs_outer.json +5b749343983f90edcdfb07412b41014840c2b485 assets/create/models/block/diorite_bricks_wall_post.json +aed9793db091577ca75bfaf496cc9967204cb27a assets/create/models/block/diorite_bricks_wall_side.json +4a1cbe7266099a0433bc341ca5b0f750568b2355 assets/create/models/block/diorite_cobblestone.json +2ad5210a878dbe4b31c6ce5e1962fb3c0fd7f450 assets/create/models/block/diorite_cobblestone_slab.json +0587d7c549648ebd8796ad39b1887497842bbfb9 assets/create/models/block/diorite_cobblestone_slab_top.json +3e959e30e67820f14c2b5afcdd5e710025d60341 assets/create/models/block/diorite_cobblestone_stairs.json +77906d654b5601e58b1485abb4d91b10bee6d665 assets/create/models/block/diorite_cobblestone_stairs_inner.json +7e4c4297dd55ee374ed5b3599c9b86ca2001d952 assets/create/models/block/diorite_cobblestone_stairs_outer.json +98738523c2aaf9ded7f0a23edd3df05d0a1684dd assets/create/models/block/diorite_cobblestone_wall_post.json +0907ef0284c7b8624d627fca66a3bb58d0f8dbb3 assets/create/models/block/diorite_cobblestone_wall_side.json +fc589cad1cee51965d4015404ecfd3c5be7bf9e9 assets/create/models/block/diorite_pillar.json +bc70a14ba2410586e8df5df2f5f367d1160b99ca assets/create/models/block/dolomite.json +bf5a698cb710b7eea9f34224be963fd949e48fd1 assets/create/models/block/dolomite_bricks.json +6fcecec93ca2d956908e3f24e9f9c2b1a9cf6866 assets/create/models/block/dolomite_bricks_slab.json +6f0cee5268aba5a54619c51fd703fcdb5abef317 assets/create/models/block/dolomite_bricks_slab_top.json +e83a06bffddbbc901246c18451057385bbeb4368 assets/create/models/block/dolomite_bricks_stairs.json +3a77383e573704b77952cc757653347edfbea4e2 assets/create/models/block/dolomite_bricks_stairs_inner.json +92f359fa78c7a923c6093abe0e2054364c17ff4a assets/create/models/block/dolomite_bricks_stairs_outer.json +f12601207b1cf723ed84ad07b6fdc54305707689 assets/create/models/block/dolomite_bricks_wall_post.json +227729855743169df83e5795ca98af45cf7ce193 assets/create/models/block/dolomite_bricks_wall_side.json +8dfeac10f0e994714f8528608ec01f165e024e12 assets/create/models/block/dolomite_cobblestone.json +38a7bdd45f3cd806f229ae4f21df45e981c5044a assets/create/models/block/dolomite_cobblestone_slab.json +e0bc8a3e14cdab30f0304d59200392858aac6753 assets/create/models/block/dolomite_cobblestone_slab_top.json +eb3f33f313beb57f05172a60259efbb39b99b64c assets/create/models/block/dolomite_cobblestone_stairs.json +c9f925ee5d38173873e3885d34d9f2a41fb355d4 assets/create/models/block/dolomite_cobblestone_stairs_inner.json +cc6d9300cd26f2323c653dbcc61b7a885be8fa3b assets/create/models/block/dolomite_cobblestone_stairs_outer.json +a101974d906487326dc38916f828d12a278a49ae assets/create/models/block/dolomite_cobblestone_wall_post.json +9c497140dfe73abe1964479eaf1af8f1892de290 assets/create/models/block/dolomite_cobblestone_wall_side.json +999a7cd79a9dc80c47fd6103b65f006b55187402 assets/create/models/block/dolomite_pillar.json +17dae5fdc1a551d8ab1ab8a68cabf7a8c3848d86 assets/create/models/block/fancy_andesite_bricks.json +cfb2cd84a1cbd9226a77ebc1f6c29e8eaa9c577f assets/create/models/block/fancy_andesite_bricks_slab.json +8ee27601996ab577991b6a0f7e9df27db0282cad assets/create/models/block/fancy_andesite_bricks_slab_top.json +07562e409b89e641c65884e52299d01bc7bb5d4c assets/create/models/block/fancy_andesite_bricks_stairs.json +8f4ff7a0dbc504555aa4aa4034a58dac58bfddc8 assets/create/models/block/fancy_andesite_bricks_stairs_inner.json +c1e49595d1608099bbf6be79c277b37ee83cb4d1 assets/create/models/block/fancy_andesite_bricks_stairs_outer.json +ad10259e6b2afe96cf7420f53813dea061654271 assets/create/models/block/fancy_andesite_bricks_wall_post.json +a69dd114a8c6889a8cf84b3c818ec68c823d45a4 assets/create/models/block/fancy_andesite_bricks_wall_side.json +e02e5d3049e414ba2bebcbe0c9e98a7a6f668044 assets/create/models/block/fancy_dark_scoria_bricks.json +8aafa8dcba2f77ffa044d2a1a708ccb7ee9ad150 assets/create/models/block/fancy_dark_scoria_bricks_slab.json +e0349402a5d1ba7ce787cc516568aac0fe6e3a77 assets/create/models/block/fancy_dark_scoria_bricks_slab_top.json +0b70f03aa9d520826bd95848dcc50d42497c2962 assets/create/models/block/fancy_dark_scoria_bricks_stairs.json +0efa7fc5b325be824f314424273ff693eb9c1c5d assets/create/models/block/fancy_dark_scoria_bricks_stairs_inner.json +d6d1354ed26cf6b08f3f1a8d624abcd0a38c88d7 assets/create/models/block/fancy_dark_scoria_bricks_stairs_outer.json +9f622e86a49954e3ec3ad30186e2782595306786 assets/create/models/block/fancy_dark_scoria_bricks_wall_post.json +fce2c713cf10bcf22e5d67a2992e9b2cc6361fa9 assets/create/models/block/fancy_dark_scoria_bricks_wall_side.json +b5262f179a7e16a4ea38e610ad0cb5f542c3ce23 assets/create/models/block/fancy_diorite_bricks.json +613531115eb9da3e62c8f29f7bda070b9636d21d assets/create/models/block/fancy_diorite_bricks_slab.json +5b5e0ffb6dbee224e0b113e28a28cec0400fccc0 assets/create/models/block/fancy_diorite_bricks_slab_top.json +56d4280cdd32d0084891731e77719ae5b12c1343 assets/create/models/block/fancy_diorite_bricks_stairs.json +63f6a321bc330d394b0f4504e43a381ab27052f4 assets/create/models/block/fancy_diorite_bricks_stairs_inner.json +a35cf29224543bea9e410633156c6e7eb9b2cd33 assets/create/models/block/fancy_diorite_bricks_stairs_outer.json +e9c641ee32689729d020a9ec3cdf8b6f323c5d68 assets/create/models/block/fancy_diorite_bricks_wall_post.json +7aea79798d3a28172cfd5dbccbcc1bc27d6e1858 assets/create/models/block/fancy_diorite_bricks_wall_side.json +8d2d5e999618ac31fdece4a629a676e8dc123d92 assets/create/models/block/fancy_dolomite_bricks.json +a619df1e34763ba4c5d07ae09646626b47ec20ea assets/create/models/block/fancy_dolomite_bricks_slab.json +28f7c18f1a991f6ac2feb232c4d8dfacda1147c0 assets/create/models/block/fancy_dolomite_bricks_slab_top.json +76e8f44ed6c65f05e95fa092507a59b0b4ec06a9 assets/create/models/block/fancy_dolomite_bricks_stairs.json +b53c77095b44821e89199e7c060b9b51eeee08fa assets/create/models/block/fancy_dolomite_bricks_stairs_inner.json +7f3a5b2beb22180cc3eeb4c180132f3e909501be assets/create/models/block/fancy_dolomite_bricks_stairs_outer.json +0bb02cea3f7e4835503edaa6d3fb63d22750ebd9 assets/create/models/block/fancy_dolomite_bricks_wall_post.json +dc3433b852df03964bf65e7d1e2f4475741bc35c assets/create/models/block/fancy_dolomite_bricks_wall_side.json +31f49733e5fca173547c6fdb10f76b896fcc5995 assets/create/models/block/fancy_gabbro_bricks.json +b7f39739146673062d537399d3afc82c724b5487 assets/create/models/block/fancy_gabbro_bricks_slab.json +4ff85261739e4252b7d15fd35e87a7a39ba618d6 assets/create/models/block/fancy_gabbro_bricks_slab_top.json +02a8dc9079d62a138343df963c951e5a24be4967 assets/create/models/block/fancy_gabbro_bricks_stairs.json +907c443b1deb4aa1e852d038fbbbccf43439a00c assets/create/models/block/fancy_gabbro_bricks_stairs_inner.json +f573f3310f05385536c4eb285e83844faa8f97ce assets/create/models/block/fancy_gabbro_bricks_stairs_outer.json +16edcdd0330034cc27c34bf4b7962a12a9758584 assets/create/models/block/fancy_gabbro_bricks_wall_post.json +75dc73daac8c47bf032313cc2234bcd6cb1570ce assets/create/models/block/fancy_gabbro_bricks_wall_side.json +4b2759734096cbe5219d62d2f8506aecc19697af assets/create/models/block/fancy_granite_bricks.json +9dbb77b7bab451db81db5d1f4f241c710f186117 assets/create/models/block/fancy_granite_bricks_slab.json +bcface0b5cad3c2498c9bd774676d5d2ad3a7fcb assets/create/models/block/fancy_granite_bricks_slab_top.json +bfd6c7779ab9fa23fae2e3a55924d0831a3e49ca assets/create/models/block/fancy_granite_bricks_stairs.json +bbb97a95452efbc20545d9a275c3d7d45494fb41 assets/create/models/block/fancy_granite_bricks_stairs_inner.json +cfbb7d33ec6313c56731385f8321a3aac9cb0455 assets/create/models/block/fancy_granite_bricks_stairs_outer.json +1a1a92f776c558173bff0e88e736fc8c89d49603 assets/create/models/block/fancy_granite_bricks_wall_post.json +13a94c47fe855532882e22ab3c7e96c4ad101df4 assets/create/models/block/fancy_granite_bricks_wall_side.json +d2c78c1efc32154b5cb7b6994e237b12b11995c7 assets/create/models/block/fancy_limestone_bricks.json +62d3c6f4cbc5e3fb21e8b8ac1a4b6b7d13c71f4f assets/create/models/block/fancy_limestone_bricks_slab.json +c194a63f4c4759c907fdfdeefbc61a7e52b0d98c assets/create/models/block/fancy_limestone_bricks_slab_top.json +2a3524c64c9703f12f713cbb2ac629eeb7387dd7 assets/create/models/block/fancy_limestone_bricks_stairs.json +92e3cc9b274cb1cad33fc0b9a47e220030cfeab4 assets/create/models/block/fancy_limestone_bricks_stairs_inner.json +6c9ac7b68f8d0716ce6929ed4a513b00daa0ec41 assets/create/models/block/fancy_limestone_bricks_stairs_outer.json +b2f3ff1718bd599ceff121b6afa3e4b4a7121c20 assets/create/models/block/fancy_limestone_bricks_wall_post.json +28c828ae08f3a84d65b5d7a28864ea9911cc3cf1 assets/create/models/block/fancy_limestone_bricks_wall_side.json +6da75b5353a49f8c68ebc8e760a1ea9c1bd72cbb assets/create/models/block/fancy_scoria_bricks.json +aa752c7269ee79f584f2fd53b69f38ee407c5b83 assets/create/models/block/fancy_scoria_bricks_slab.json +616215efa32da630dca0e768fd2b2c4f3587ee3b assets/create/models/block/fancy_scoria_bricks_slab_top.json +0d1e864a85aee0a4e0b734d2c6fe7298195e056b assets/create/models/block/fancy_scoria_bricks_stairs.json +2910394962403031789e07ff7ce6cff411ee0d85 assets/create/models/block/fancy_scoria_bricks_stairs_inner.json +fb318bb52c43acfc0f371b69905ba4d286f85754 assets/create/models/block/fancy_scoria_bricks_stairs_outer.json +1888c192a0e765dbd264f64ae658ccbe1aa04a15 assets/create/models/block/fancy_scoria_bricks_wall_post.json +46351521c89870d27c8ed12937f5fdf8f4a234b2 assets/create/models/block/fancy_scoria_bricks_wall_side.json +daa7dca22c363d09a81f01716c80f09b22c65226 assets/create/models/block/fancy_weathered_limestone_bricks.json +857392d468416cdb55fdfa090e2c321c3fdf7024 assets/create/models/block/fancy_weathered_limestone_bricks_slab.json +8a63a56cf3ece060b1804ededdf103376691baa7 assets/create/models/block/fancy_weathered_limestone_bricks_slab_top.json +852a1dbcae18274080f6fe14483c21b8134bf56e assets/create/models/block/fancy_weathered_limestone_bricks_stairs.json +fff01c45f01d2b1c4c0555f2ab4d66442c90148e assets/create/models/block/fancy_weathered_limestone_bricks_stairs_inner.json +1ea72b0ca54c8237351b4be0a7b44b94a8b0bb87 assets/create/models/block/fancy_weathered_limestone_bricks_stairs_outer.json +d7385af6e7c8124fda4d391c2e7fba55cdc9977e assets/create/models/block/fancy_weathered_limestone_bricks_wall_post.json +215671ac8e468015e8d52054c863110465c33fc9 assets/create/models/block/fancy_weathered_limestone_bricks_wall_side.json 71f74388319567d4ab13c508bf3b4d59f1a19b2f assets/create/models/block/fluid_pipe/ld_x.json bd6b0c6d773e3996d949de55873d20b0e192499d assets/create/models/block/fluid_pipe/ld_y.json ddba92d010016a0147ceecc30a30c9c1622d3daa assets/create/models/block/fluid_pipe/ld_z.json @@ -759,32 +725,30 @@ c09f2f36e3df4642b48f9e331d5000c4f58047ca assets/create/models/block/fluid_pipe/r 2635da812f9dec0c408fed329b3962bd14972d95 assets/create/models/block/fluid_pipe/ud_x.json 4a0d4fb1aaf05b8f388e4add0f45d2a22dde2ce6 assets/create/models/block/fluid_pipe/ud_y.json f7d3a9ff5a0d050f5822dba9ec6cb68a2e4cdecf assets/create/models/block/fluid_pipe/ud_z.json -b1e94d2858c3a8807def6c5131b6f63fe586fb91 assets/create/models/block/framed_glass.json +9730fcb02f679087e81e24c836751e625be6a298 assets/create/models/block/framed_glass.json d13df8a5920c5778d98081fb0e97f045e2fd46a2 assets/create/models/block/framed_glass_pane_noside.json 3e975bec02e2670ce2b1868cebcbd780a5ebf3f8 assets/create/models/block/framed_glass_pane_noside_alt.json a5938ddd48109f067a19a90a0f9abab655c18821 assets/create/models/block/framed_glass_pane_post.json 41645919ece236df5804a5a73ef682720194de34 assets/create/models/block/framed_glass_pane_side.json 8bc0abaabdc62d0c27730dba7eb6da54607b7e96 assets/create/models/block/framed_glass_pane_side_alt.json -894518bf911d73cece24d4557ab29829829d70c0 assets/create/models/block/gabbro.json -d84f558506d4a399f72d86b15f318b234ce67e58 assets/create/models/block/gabbro_bricks.json -6ca3de3137526e3e103b9759c9f79edcaec3bab3 assets/create/models/block/gabbro_bricks_slab.json -fd6102766ba2567a70c86e7613992a23a5a3e7c6 assets/create/models/block/gabbro_bricks_slab_top.json -ae26c480f3d9d51c8b9d2e20427ec9234a0db8d5 assets/create/models/block/gabbro_bricks_stairs.json -8a19d9f9f8f1d0f0ea9311cb8b2488c5027fba25 assets/create/models/block/gabbro_bricks_stairs_inner.json -78d2189693c37ff41751cc5f0464f88c36482d77 assets/create/models/block/gabbro_bricks_stairs_outer.json -79e4fcf540e86a4d5910d57d9d9045ce181b0070 assets/create/models/block/gabbro_bricks_wall_post.json -49398d10642388e8301159505dde8b0c25ab2edc assets/create/models/block/gabbro_bricks_wall_side.json -23854558036ea469c6d78880d0f5244b64fdb418 assets/create/models/block/gabbro_bricks_wall_side_tall.json -c50dddabd9be06f251f6bedcf7e122eb79bb9400 assets/create/models/block/gabbro_cobblestone.json -19f29ac6c463b21311629ef277ddb6dc0673caa1 assets/create/models/block/gabbro_cobblestone_slab.json -3eaa34ce53980d6340547445536444f5fcfd4e2c assets/create/models/block/gabbro_cobblestone_slab_top.json -ca94584799cbc0861e783dee631ea70e154a0898 assets/create/models/block/gabbro_cobblestone_stairs.json -47ea92c04b31fc43a2123d418ac2142f7104d780 assets/create/models/block/gabbro_cobblestone_stairs_inner.json -dc099cc48208c776cb561fb0cf20142fe1f905a4 assets/create/models/block/gabbro_cobblestone_stairs_outer.json -acb516b2ecb4bbb8dc9c7c4a8b4ef8f7347af0f7 assets/create/models/block/gabbro_cobblestone_wall_post.json -a66072ee1cd164a10935417c036f4f55772769b1 assets/create/models/block/gabbro_cobblestone_wall_side.json -b8f5a5d25a3e3731670b4a7f7c83fd22f72ebd1d assets/create/models/block/gabbro_cobblestone_wall_side_tall.json -4f8ee4ea7f0a79f7da29414397d8829c1969b7b5 assets/create/models/block/gabbro_pillar.json +af8bceaa94d714ab377ab9cef1a46ec8cd2b6382 assets/create/models/block/gabbro.json +d21fdbd5ae4013fed068e6ae015d68880d4d3d5c assets/create/models/block/gabbro_bricks.json +acdb20098521f67a530dd809190b1c024464749d assets/create/models/block/gabbro_bricks_slab.json +10621d5aecf9d97bbf0ffec5540d6590ba88eb75 assets/create/models/block/gabbro_bricks_slab_top.json +dfb61cb5f05c385fe9a459685804eef7a5961e15 assets/create/models/block/gabbro_bricks_stairs.json +c61f0ee76ba24ecb4f597f83b45ecea3ccb9531a assets/create/models/block/gabbro_bricks_stairs_inner.json +6dc59aaa66608e8d11b67ce2c5432f7b38003113 assets/create/models/block/gabbro_bricks_stairs_outer.json +9b851103cec9334e98008a8955df62f52edeab1f assets/create/models/block/gabbro_bricks_wall_post.json +ca28cec552b4d3401854c2d00d43b3a3e01995f2 assets/create/models/block/gabbro_bricks_wall_side.json +fbdc91941c4694507a759d105dc4284914a2eaa7 assets/create/models/block/gabbro_cobblestone.json +c660c81a9faaf7cd12b50d2a329e52c377cb96a5 assets/create/models/block/gabbro_cobblestone_slab.json +b5c4037b01c2e02eee1275a36d62b2f364a49775 assets/create/models/block/gabbro_cobblestone_slab_top.json +75589542f32d2cdad96afb2348cd6fbff2475b07 assets/create/models/block/gabbro_cobblestone_stairs.json +f278ec09c13f98ccbce1a8488d4d51c72f398ed4 assets/create/models/block/gabbro_cobblestone_stairs_inner.json +094d753164a282b2a5608202ab38bd354abb1a14 assets/create/models/block/gabbro_cobblestone_stairs_outer.json +5e50c62a9db350f3a2c0e4b1c37a8dc0d149f287 assets/create/models/block/gabbro_cobblestone_wall_post.json +820235f51e7c3b4c05a327c3aa66618ea1e89c9c assets/create/models/block/gabbro_cobblestone_wall_side.json +ede9c9209f9cee3d8e1ffc5008b1b8b026aee998 assets/create/models/block/gabbro_pillar.json f7f55d8107d9128f7be42b2a07fd99aeeba44954 assets/create/models/block/gantry_shaft_end_flipped.json 33196bb0c2f7ca356fc62854349a3ab5fdf2d119 assets/create/models/block/gantry_shaft_end_powered.json 410c0ae1995a079766cab96a3545bb61159feba3 assets/create/models/block/gantry_shaft_end_powered_flipped.json @@ -797,25 +761,23 @@ c81b86c2186cbe9867ea041776c8e70059d70f7e assets/create/models/block/gantry_shaft 347430ecc316d502cea2e0f90d43ff106e9cb15c assets/create/models/block/gantry_shaft_start_flipped.json 0e1a5a8f38cd6cd3e2f7d2c0d147d924414b0560 assets/create/models/block/gantry_shaft_start_powered.json 4b2f2e9eb3d426b56bb2e0f530b249469200afd0 assets/create/models/block/gantry_shaft_start_powered_flipped.json -adf7ef2d029fb6b26a445de79c62b710e6832c06 assets/create/models/block/granite_bricks.json -47765dd5359ab0a1d76cbc503d621250224063fd assets/create/models/block/granite_bricks_slab.json -80d7b25ff3782fc7e5cd419e275300fe3722892d assets/create/models/block/granite_bricks_slab_top.json -a56aa126a5a4a88914e62926630f5548b24c62e0 assets/create/models/block/granite_bricks_stairs.json -cdafe87bed3980b6109a2d85dd85a207967382da assets/create/models/block/granite_bricks_stairs_inner.json -b15b4ef4354b189b678fa944cf3ad456480fd30a assets/create/models/block/granite_bricks_stairs_outer.json -45999378195baa93e1eec5e58c0065a3d255490b assets/create/models/block/granite_bricks_wall_post.json -c1c86afd629d16387627d1f136e5ab6f846e072e assets/create/models/block/granite_bricks_wall_side.json -44df8fb0bcf2bb17aa0c70ae3829d01c3452e4be assets/create/models/block/granite_bricks_wall_side_tall.json -8804fa93deed01d2c488894ae0f4e35ceed0218c assets/create/models/block/granite_cobblestone.json -ea28ac79636a92779066ab43d727cc0dd99f12a5 assets/create/models/block/granite_cobblestone_slab.json -0425978f192f8dbaa6e077739f4ef77443b03b7f assets/create/models/block/granite_cobblestone_slab_top.json -9f1243adc9affaaaa43355a73570d8b8cc0b76ab assets/create/models/block/granite_cobblestone_stairs.json -ddc8bf8dc62464d424ab812f801dd7a1f68072d0 assets/create/models/block/granite_cobblestone_stairs_inner.json -2ed22800ed503bd0b903b2b7ed86209861833fcd assets/create/models/block/granite_cobblestone_stairs_outer.json -01236266fd0d5057e97dea0fbb114de702fe2c48 assets/create/models/block/granite_cobblestone_wall_post.json -87f6b4e30f2cdd0ddb3b48e43f15317b386597e6 assets/create/models/block/granite_cobblestone_wall_side.json -5c7340740d822deae7aa32c15c36531476862fbb assets/create/models/block/granite_cobblestone_wall_side_tall.json -f55c5825c63f345a95e822a2113e76b5a62d8f7c assets/create/models/block/granite_pillar.json +392dd57e5b96214335867799347e21ac0d05457a assets/create/models/block/granite_bricks.json +0ee90049ce09f1f1c96063bc7239cd1fadbdb947 assets/create/models/block/granite_bricks_slab.json +37737d6767ba08b6bd96de1ff3b920522dc3cd51 assets/create/models/block/granite_bricks_slab_top.json +e1fe76be531aec81e97a4b28f5e7cd426e48975f assets/create/models/block/granite_bricks_stairs.json +a976ff37a2acc9f84a37c397f06c08edc0a7674f assets/create/models/block/granite_bricks_stairs_inner.json +44189d38e42d2e2ab2c1115e569d60379f9d90a3 assets/create/models/block/granite_bricks_stairs_outer.json +f949f1e763f745f140e763043cc16d68c7ee0f1f assets/create/models/block/granite_bricks_wall_post.json +1d0e735ed822d17825f20270640510a68c835a3f assets/create/models/block/granite_bricks_wall_side.json +6b9e3507606968748e48517f3aa29c2c1ee4b16e assets/create/models/block/granite_cobblestone.json +99b6c148a801868be5b265a3f7a9b86e3bc46718 assets/create/models/block/granite_cobblestone_slab.json +a54dbe2ab2ddca316efb05d8d3094dc146ced339 assets/create/models/block/granite_cobblestone_slab_top.json +d52844bdcf33a2f0111c7664a848b510a0f13b8d assets/create/models/block/granite_cobblestone_stairs.json +e2fc1797ddb503b887cf0871526e7d889df32a05 assets/create/models/block/granite_cobblestone_stairs_inner.json +d25cb5553bfd89cd3fca61ebd2204bf2a44cc3da assets/create/models/block/granite_cobblestone_stairs_outer.json +cf267628d47aa424bc20977e69e255ceda3ddfe4 assets/create/models/block/granite_cobblestone_wall_post.json +a4f50b75a3186829fc5d62ee4e33997cd202dbd5 assets/create/models/block/granite_cobblestone_wall_side.json +349a58ac4e4535d0fe9ea467632ed904da2c6098 assets/create/models/block/granite_pillar.json a68cd40ffb769b195437107f4a2c2188b222b74a assets/create/models/block/gray_sail.json 6eb5e59e803e1055968b90f3099cd0a17a1d3fd5 assets/create/models/block/gray_seat.json 7e213be39cc928363bf2b096f055439211050b8d assets/create/models/block/gray_valve_handle.json @@ -823,27 +785,27 @@ a68cd40ffb769b195437107f4a2c2188b222b74a assets/create/models/block/gray_sail.js 1438b8ce54ac5557b8f10dcef94f3525eae19461 assets/create/models/block/green_seat.json cc7ce9b6bc687ad5027a67c3bf22bdf5bcd71674 assets/create/models/block/green_valve_handle.json 5163171ed77af879fa06f290bf24b1bb99735c94 assets/create/models/block/honey.json -b1e94d2858c3a8807def6c5131b6f63fe586fb91 assets/create/models/block/horizontal_framed_glass.json +9730fcb02f679087e81e24c836751e625be6a298 assets/create/models/block/horizontal_framed_glass.json d13df8a5920c5778d98081fb0e97f045e2fd46a2 assets/create/models/block/horizontal_framed_glass_pane_noside.json 3e975bec02e2670ce2b1868cebcbd780a5ebf3f8 assets/create/models/block/horizontal_framed_glass_pane_noside_alt.json a5938ddd48109f067a19a90a0f9abab655c18821 assets/create/models/block/horizontal_framed_glass_pane_post.json 41645919ece236df5804a5a73ef682720194de34 assets/create/models/block/horizontal_framed_glass_pane_side.json 8bc0abaabdc62d0c27730dba7eb6da54607b7e96 assets/create/models/block/horizontal_framed_glass_pane_side_alt.json -35253c91ed72c7c2ce981c384d334c1113851469 assets/create/models/block/jungle_window.json -65da656d412d973865f50ab7f02e278fe5398bea assets/create/models/block/jungle_window_pane_noside.json -9f4144df2e6b35c1fad04e594be5adb3b107bdb8 assets/create/models/block/jungle_window_pane_noside_alt.json -2e8cec84ae0fe8933a3e2e39721937673c4941d1 assets/create/models/block/jungle_window_pane_post.json -4e3cc8764a8e5cefd2dfb415e66e75c4059cb804 assets/create/models/block/jungle_window_pane_side.json -b233d493ec57204f7527c6ccf803580c1131b2ae assets/create/models/block/jungle_window_pane_side_alt.json -6abd1f7dd176b861e2335f65c8f8cdc50c90aaac assets/create/models/block/layered_andesite.json -be3a70d4f88abeb9321bdef6629790cb4220b688 assets/create/models/block/layered_dark_scoria.json -936e118bb2275fa468bc0d0e934a14e3a6c768ee assets/create/models/block/layered_diorite.json -e1add9f62cf886a7989f7ebb545906da16ad7a41 assets/create/models/block/layered_dolomite.json -3ed6faede6762dd9b44139d137ff081797189300 assets/create/models/block/layered_gabbro.json -650f878e71110f84abaa44c076b0c0023425be45 assets/create/models/block/layered_granite.json -cecf946818c65370b685dfeaade50819183acb41 assets/create/models/block/layered_limestone.json -258fb9644d396872719c56ae1ca89f50667a1077 assets/create/models/block/layered_scoria.json -60b05926e706d5dd27f3cb4997120c948797f2f4 assets/create/models/block/layered_weathered_limestone.json +2536b29d5d87ba7da1d0f29c791572f67d1bd951 assets/create/models/block/jungle_window.json +50ad1922e3fcc045c9ea9fc085fdeeb53ab95c7a assets/create/models/block/jungle_window_pane_noside.json +38e4df0859d04d1a2dd4973b530748eb39c9f6c9 assets/create/models/block/jungle_window_pane_noside_alt.json +bf353e0eb2f8906a14bc35edd4ba0c0100ac211c assets/create/models/block/jungle_window_pane_post.json +41db69ebd3815264bba50a842888d436105a5ebf assets/create/models/block/jungle_window_pane_side.json +45ae3d910768519c5490f0c55c986eb0fef0bccd assets/create/models/block/jungle_window_pane_side_alt.json +08db5db16af40320d5d28f68d0c59bea8ca4d181 assets/create/models/block/layered_andesite.json +072766a01b510ab062c22c811577d15a5822b7dc assets/create/models/block/layered_dark_scoria.json +3592d257cf99bb6aa507a0e4a88fd26bca992e8f assets/create/models/block/layered_diorite.json +e9b639cb29051249a9999dd05e09eb820159cd40 assets/create/models/block/layered_dolomite.json +ff78465839cbd36a356cd4153c721c88b1f0b297 assets/create/models/block/layered_gabbro.json +0fe90b060613a824effaeeff6b3d13399681cbf0 assets/create/models/block/layered_granite.json +8f1014b1fdef246c2ce525f33ade4f03c85d0217 assets/create/models/block/layered_limestone.json +9408ce7ba29a96053c9333b15a05d716752392c6 assets/create/models/block/layered_scoria.json +da71aca99ac5cf3731896be47e15d774397a3330 assets/create/models/block/layered_weathered_limestone.json 19bd08ad6ac351e6eee2131f7b4c11a768bf8f08 assets/create/models/block/light_blue_sail.json 1a28b07da68d1461cd04c971ae548d94165e0cf3 assets/create/models/block/light_blue_seat.json 68e01f8d8a31f07f236383e19b49ae1be4cbe3f4 assets/create/models/block/light_blue_valve_handle.json @@ -853,31 +815,29 @@ cecf946818c65370b685dfeaade50819183acb41 assets/create/models/block/layered_lime 8292d043ebfe280340526a6a0f96d4160099e213 assets/create/models/block/lime_sail.json 31c9474210d8535c5417021fe042d4cc31e17328 assets/create/models/block/lime_seat.json 74008bd0d775b0e2e96b43be2e51d0f3c3abdf21 assets/create/models/block/lime_valve_handle.json -fccac0de94fff5f4e180fc9dbddeb0f8ddf3baab assets/create/models/block/limesand.json -3c49d63386b3f5326051edbf6e2f0f8f0e2ff4f3 assets/create/models/block/limestone.json -84920646b4df506f94e64611ee231f3af51b5379 assets/create/models/block/limestone_bricks.json -34a6379261b13f0b5b856bdcbecac1aa8de98ec8 assets/create/models/block/limestone_bricks_slab.json -a4eb94d59365c854b205c22b98c03742a3e45007 assets/create/models/block/limestone_bricks_slab_top.json -6030ff8209edb3ef04e6dcf83cf181ee4cad13fa assets/create/models/block/limestone_bricks_stairs.json -0e830acdd0e39b099d0d0b3f2b9326af0c182633 assets/create/models/block/limestone_bricks_stairs_inner.json -38c3bc0412baa9ed842c6436874c528e4a27fe00 assets/create/models/block/limestone_bricks_stairs_outer.json -d36db8a76c0abf8f42798fb2d8914d4aad0cb7b9 assets/create/models/block/limestone_bricks_wall_post.json -628493255ec16d79455bc54497c6a4b8207e0649 assets/create/models/block/limestone_bricks_wall_side.json -9c4cbf01802a59919c284bc616ae4d390b34d917 assets/create/models/block/limestone_bricks_wall_side_tall.json -93d3ca6df1c824a6f8b54d917bc61e48675f5ff5 assets/create/models/block/limestone_cobblestone.json -7786068e25079538528bf717e473d5c4e2266f7c assets/create/models/block/limestone_cobblestone_slab.json -454f09c5eb4c92bfa0e0b81c0b28c88caa78a907 assets/create/models/block/limestone_cobblestone_slab_top.json -213e897e2e2df5647e6c2df23691e52e92eaccab assets/create/models/block/limestone_cobblestone_stairs.json -c54e5a17495f88fa21b3488e8da32a365452c36c assets/create/models/block/limestone_cobblestone_stairs_inner.json -17cd5d20df9a8a16ad8993bcf5fc273ca80933dc assets/create/models/block/limestone_cobblestone_stairs_outer.json -464053d2fad1f398662a0878e6891a0dc613061d assets/create/models/block/limestone_cobblestone_wall_post.json -9d2826391999f3d65b948f560c91bc178dbe8846 assets/create/models/block/limestone_cobblestone_wall_side.json -6d4fb04b155e1460c6f8019491310707ed5cca28 assets/create/models/block/limestone_cobblestone_wall_side_tall.json -7527b3f1274744a64f7eb4bc94f7bc125dcbcf28 assets/create/models/block/limestone_pillar.json -0766a12c95977dfb8f3a8ea453d45c9832e7e824 assets/create/models/block/linear_chassis.json -7991d6620d2225b1a026e2b62dc076cf0a33613d assets/create/models/block/linear_chassis_bottom.json -56e585805c6235552ce5e15ff2f125ff8ec0fa2d assets/create/models/block/linear_chassis_top.json -12b35c916e3ee83ee4fd1e309c73403dec9a7297 assets/create/models/block/linear_chassis_top_bottom.json +ce6fb36a386c895486e021823eb008b0fa4862c3 assets/create/models/block/limesand.json +a2cbc86d24fdd70c5f33c8b30ba52a8928dde63f assets/create/models/block/limestone.json +447686a6861773e03c5c18f2de4bc11d06c65f78 assets/create/models/block/limestone_bricks.json +4aa8f22c5c48b20170f7050ad7ecf65d08c1a6fe assets/create/models/block/limestone_bricks_slab.json +7a890ab6513ead1b4d20b023e7a04a4d4d8b8c3d assets/create/models/block/limestone_bricks_slab_top.json +180c37c3ecec8e036a12840b1440c6b9d7b21cef assets/create/models/block/limestone_bricks_stairs.json +a30fc3563f85b189a16cb4b2af6cbb587b33b354 assets/create/models/block/limestone_bricks_stairs_inner.json +cb8d4ba5a0e1372520f55ddd659ed8f944700730 assets/create/models/block/limestone_bricks_stairs_outer.json +bd46a9a9650fc893b0403a4427dace9fc2c0002a assets/create/models/block/limestone_bricks_wall_post.json +774de72109796d55c5548e4194461ce27083a20d assets/create/models/block/limestone_bricks_wall_side.json +59202c99e39fc26497cd7c27b2e5edc9b1310457 assets/create/models/block/limestone_cobblestone.json +fe6a5228bf9ca394b234afd82467efe65544afc2 assets/create/models/block/limestone_cobblestone_slab.json +d1718b257af8f892a6ed28638399a57cc6c3d8dd assets/create/models/block/limestone_cobblestone_slab_top.json +3a15866b7c6df7e035afcc4b32321d8dad07d5f8 assets/create/models/block/limestone_cobblestone_stairs.json +fd0a970c68c7025040bede0a07fef46c9047f611 assets/create/models/block/limestone_cobblestone_stairs_inner.json +abef3f97c28321ded3bafc90918377981038d7b2 assets/create/models/block/limestone_cobblestone_stairs_outer.json +eee8ae85daa99fcd594da3d4af393726af69493b assets/create/models/block/limestone_cobblestone_wall_post.json +0effd13c1ff224f4c2d7017c6505f48d31815934 assets/create/models/block/limestone_cobblestone_wall_side.json +7336e008b3af80e054c9f15be381b7fe307e97d4 assets/create/models/block/limestone_pillar.json +20432687c62402a4bc0f2415113e7470231cdf03 assets/create/models/block/linear_chassis.json +595bfec2293c44deae49147016cb7971bdd721df assets/create/models/block/linear_chassis_bottom.json +999ce855842170f47db9d1e8e8636c24f7d3ad3d assets/create/models/block/linear_chassis_top.json +b9abbd1dcf71e0a1416fd998a82a560c06cef5a3 assets/create/models/block/linear_chassis_top_bottom.json ec6b5f636e163ff5e361d486cf628ca1af4849a1 assets/create/models/block/magenta_sail.json cbee001cd1bb1125a97d1bb2d1e6e5a68f129303 assets/create/models/block/magenta_seat.json bc5a03a5552eb4a518abefe5e8615f14ee13ca29 assets/create/models/block/magenta_valve_handle.json @@ -891,17 +851,17 @@ f2f7cda5de21279ff8e359142c523e07a3377477 assets/create/models/block/mossy_granit de9b0f933881cc735ae0acf2bd71e6eafa732ff8 assets/create/models/block/mossy_limestone.json f88a9558a20033d4955e7b6de4f8aa23b1a11b9f assets/create/models/block/mossy_scoria.json 8c3296378aa7e5dc1bc7dfdde2f0a436b8bb8b78 assets/create/models/block/mossy_weathered_limestone.json -50f28bf7a7de95caf12b4f040994f0f3da72a55a assets/create/models/block/natural_scoria.json -e3cd8b33b8c5f0543e4f6728a5b3e05642f9efe1 assets/create/models/block/oak_window.json -54a3b3158f8c914788812aa44515b798b2a9e2f3 assets/create/models/block/oak_window_pane_noside.json -b9c27f90d4d258e3fdcd713aaa42142f5d46a79e assets/create/models/block/oak_window_pane_noside_alt.json -8c3fdc51742897d110641ba9127f857297300edb assets/create/models/block/oak_window_pane_post.json -8f77db5a66b165d2ca85f9119666907dcf65105f assets/create/models/block/oak_window_pane_side.json -b3e056a176e86660fc2d3a51f9ba8b01eebb56c5 assets/create/models/block/oak_window_pane_side_alt.json +24cbd7e60a7769a8fc9f530978ef7094ae65a9eb assets/create/models/block/natural_scoria.json +269ec2c32ba22a216b1c6831e6284ef98e78ee75 assets/create/models/block/oak_window.json +f324403f578d724c118055ca04e6bec23607ea90 assets/create/models/block/oak_window_pane_noside.json +e55363147cc27fba84590c7e24460603988118e3 assets/create/models/block/oak_window_pane_noside_alt.json +88883e266828422f86ec71db455a41f0279926fd assets/create/models/block/oak_window_pane_post.json +aa12818d00d1995e5b8a218cb613215ec0161d23 assets/create/models/block/oak_window_pane_side.json +488dfd3f4bd82ab1b5b751b4a46881befb8d6819 assets/create/models/block/oak_window_pane_side_alt.json ff9b51fcaffe54e321b9479f035f4ea7b278bfec assets/create/models/block/orange_sail.json fda0628a09ef726e3e8323b2f38b6a3e612dc2ca assets/create/models/block/orange_seat.json 3b07f3f1985495051d173725b01ddd52b5f70ac4 assets/create/models/block/orange_valve_handle.json -de5ecd753303b2c5dc3819299b9a316f0d7035f6 assets/create/models/block/ornate_iron_window.json +006115bf8e36367c0c409effdeab939a54c20776 assets/create/models/block/ornate_iron_window.json cc9614e892b12c6053d45a35d534eddf36285cf1 assets/create/models/block/ornate_iron_window_pane_noside.json 6b935d54de7c37f835df48f7b6e5e614a0d12b6e assets/create/models/block/ornate_iron_window_pane_noside_alt.json 19942331411716035d79adabe6d2daadd6025e90 assets/create/models/block/ornate_iron_window_pane_post.json @@ -916,197 +876,182 @@ ca08c15006d65701d72bb88852df884236822522 assets/create/models/block/overgrown_di 3368bbdf335c81b9e84adc30afeab9261256279c assets/create/models/block/overgrown_limestone.json c21c58e982ec0eb1c88948ac53b570b26bf1c9bc assets/create/models/block/overgrown_scoria.json 6d7842c5c0f58a3cb3150e54bee2b51e7138df45 assets/create/models/block/overgrown_weathered_limestone.json -8dfe5334887c09375f2571aa3835f2dd9de76875 assets/create/models/block/oxidized/copper_block_0.json -3f5af8864db20346df2463066265d7f6709a5e65 assets/create/models/block/oxidized/copper_block_1.json -ee0f11c96fafc164fd9ac64fde0f89cfd527a65a assets/create/models/block/oxidized/copper_block_2.json -060743439c0f0e991a7ccfcc9053ee9741e73805 assets/create/models/block/oxidized/copper_block_3.json -131b2a2b3c883deeb6af544f15fcc0d88a3ff5fe assets/create/models/block/oxidized/copper_block_4.json -4e0fbfc3b61f04f68c6022d6a9a9eabdffdd8673 assets/create/models/block/oxidized/copper_block_5.json -e3d374a2e5ceac212bed21b6ec964b4593aa847a assets/create/models/block/oxidized/copper_block_6.json -125966d6e25b601779e3bff4a9da84d85e3984ff assets/create/models/block/oxidized/copper_block_7.json -8f2b2d983c1a0d128dbb1d6465a4eb3a7f98e34c assets/create/models/block/oxidized/copper_ore_0.json -4fd860b564a98869c6450e21446e0e41a8303206 assets/create/models/block/oxidized/copper_ore_1.json -430a115e26a2e95b7a6c04746b10f617212a3091 assets/create/models/block/oxidized/copper_ore_2.json -596fb93cc5f59ccff8e84c07a99398f5ec20d169 assets/create/models/block/oxidized/copper_ore_3.json -d7e94d32a8c739fe8ccfc51b3bf5c1dff038b47f assets/create/models/block/oxidized/copper_ore_4.json -895d3ce98dc576b7396fa309dce69eaeba419c95 assets/create/models/block/oxidized/copper_ore_5.json -578ee4b7b0aaf4f5fbdecc7800f1d8b0d9ea6576 assets/create/models/block/oxidized/copper_ore_6.json -7c4e54d05a8e76e390044099ad02c5dd082f2460 assets/create/models/block/oxidized/copper_ore_7.json -2091e38299cd736320de736b9450e9b5209106cd assets/create/models/block/oxidized/copper_shingles_0.json -3614bcea228962535a048b68b3069a9058156a16 assets/create/models/block/oxidized/copper_shingles_1.json -3d2219e127df9e14109c876ef2e3499a21268209 assets/create/models/block/oxidized/copper_shingles_2.json -6f9461d372dbd9561460649a9325c62cd3f3ef36 assets/create/models/block/oxidized/copper_shingles_3.json -d9867c3574ecd484ea179a8ffc2d3b562a389bc2 assets/create/models/block/oxidized/copper_shingles_4.json -649cf546f5f4535f0936dedf0074aeb878829129 assets/create/models/block/oxidized/copper_shingles_5.json -c3bb01e750f02312c62990d71bd113df41f0746c assets/create/models/block/oxidized/copper_shingles_6.json -cde13928d8643fe28f891b4ed6358971b6eb49f7 assets/create/models/block/oxidized/copper_shingles_7.json -a223e5ddcd9c0f282a0193434189ae91b67e1571 assets/create/models/block/oxidized/copper_tiles_0.json -590c75f1c1a9013c8adb5b90f05e8578a75a140f assets/create/models/block/oxidized/copper_tiles_1.json -66af247eac88396e9c26b61443e2d324f250a160 assets/create/models/block/oxidized/copper_tiles_2.json -3fc4e85ed7115e4b3289739268b4366f8d8777c5 assets/create/models/block/oxidized/copper_tiles_3.json -abdcf49a3ad1a25b37653c1c6eccd24b9a97c87f assets/create/models/block/oxidized/copper_tiles_4.json -99580c32742505b9a2eb64185f9529a5388d2751 assets/create/models/block/oxidized/copper_tiles_5.json -be9ac7815d4bbf0c42dc40d20d34212250ac86a7 assets/create/models/block/oxidized/copper_tiles_6.json -a4e5715d04bd13860e2d5981c2122fbc6b435e80 assets/create/models/block/oxidized/copper_tiles_7.json -44abcee4d7f0d63d2f91b42a6e223cb8211597df assets/create/models/block/paved_andesite.json -afcf525fd574ebd6918d0357442d2f8099276079 assets/create/models/block/paved_andesite_covered.json -ee19b3143803e4d41639dbd564f84bf86b01d77d assets/create/models/block/paved_andesite_slab.json -39da471b29a69b94dd481b8a7d6aad2b8efcc993 assets/create/models/block/paved_andesite_slab_top.json -7f61f36812ec6f1a684bfc06e7058114dbe4c7d4 assets/create/models/block/paved_andesite_stairs.json -91a169ff2d8463520d419738d2341afdc4cf1f0f assets/create/models/block/paved_andesite_stairs_inner.json -7c7d1081ce8c4cf8c247afeafed434172c8ccd00 assets/create/models/block/paved_andesite_stairs_outer.json -b14d753208e48c3a2780d258bec6e0d20ccbafc1 assets/create/models/block/paved_andesite_wall_post.json -1edd248747a0db1381115b3ecc40f7fa24ae845d assets/create/models/block/paved_andesite_wall_side.json -5bfc3655067f7ac2e80dee3ccc1c4a9b387316a0 assets/create/models/block/paved_andesite_wall_side_tall.json -516936f48542723e9ea19fe06412348d36d4461b assets/create/models/block/paved_dark_scoria.json -5a9c0029ac5c10a65709bdf59a4f3dd778369370 assets/create/models/block/paved_dark_scoria_covered.json -4dfbc6beec27bf266b03a7fc9c9ddd8dc2d24745 assets/create/models/block/paved_dark_scoria_slab.json -9657df68fa3903ddef2aa49b88ec66a7e91ebb7e assets/create/models/block/paved_dark_scoria_slab_top.json -8c6fcbe10e4287e39b7f5161d677b628b933cb17 assets/create/models/block/paved_dark_scoria_stairs.json -fb5bd6499bf17d861d5f504b45d2caf9a734ff77 assets/create/models/block/paved_dark_scoria_stairs_inner.json -bc58687ad19f3a12b8c730dd2c7284b3baff370c assets/create/models/block/paved_dark_scoria_stairs_outer.json -346b7db2932c5f32a26e35bf0383b33c6109ee3c assets/create/models/block/paved_dark_scoria_wall_post.json -695b167aa884c3c827bf3f743233d7c5f0d220d3 assets/create/models/block/paved_dark_scoria_wall_side.json -75870726f58f388244ffbbde1676a9f66c52120c assets/create/models/block/paved_dark_scoria_wall_side_tall.json -ad5ecc000e088252a9aa144250f1be3324dac366 assets/create/models/block/paved_diorite.json -171351fbd56ea8a19ba6c9b0fd82bf88ee176528 assets/create/models/block/paved_diorite_covered.json -bc66da45a57ac338c066aa26427c3c55d78d798c assets/create/models/block/paved_diorite_slab.json -c3e7a4cc76ea1cf2511f6921ed715540dcb200df assets/create/models/block/paved_diorite_slab_top.json -dfd06d83473b0cf8855fbd0ed89831567bcc6212 assets/create/models/block/paved_diorite_stairs.json -6f852f3f90c24cfebbfc603f11803e039ea9a0c0 assets/create/models/block/paved_diorite_stairs_inner.json -cd32a4355eed1eadfdd133a2acc135c0836011a7 assets/create/models/block/paved_diorite_stairs_outer.json -6c52f7f025f56dcd45fcdef87c76263318ffbee5 assets/create/models/block/paved_diorite_wall_post.json -5ee12e7349d48986ff245512764defbf18d03a45 assets/create/models/block/paved_diorite_wall_side.json -1584f34af51c9ee584d7e6c528d68a7ff2a9b5a0 assets/create/models/block/paved_diorite_wall_side_tall.json -e763ba96670e52800dfadb96cc402ef50bc23c21 assets/create/models/block/paved_dolomite.json -1ea5247d696ab136f8e323f68e2918a9e871ce1c assets/create/models/block/paved_dolomite_covered.json -dba94cd61f0672829bbab3ace3409dce589bef62 assets/create/models/block/paved_dolomite_slab.json -74e8a30e8e14e4f4bb05f53159928544e99006ec assets/create/models/block/paved_dolomite_slab_top.json -c282fd047907899c439f022203aee6a1491070b4 assets/create/models/block/paved_dolomite_stairs.json -88f4e3af8e0a7fd38adc300e49f8f0efb19ee8a9 assets/create/models/block/paved_dolomite_stairs_inner.json -91b6be901eb9a18518585c679757c1baec16c7c5 assets/create/models/block/paved_dolomite_stairs_outer.json -8b9309e098b6066dff8cd206e80938e33b692c8e assets/create/models/block/paved_dolomite_wall_post.json -378609052c8daa9a38259b54a0a0d995c4636396 assets/create/models/block/paved_dolomite_wall_side.json -47b5f4d682d041008c8256fc3df1be25130fa10a assets/create/models/block/paved_dolomite_wall_side_tall.json -f90897992da49371e405088756b9077113a5c7dd assets/create/models/block/paved_gabbro.json -7ab1400fe9c2968fbe276bf70325ae6d159d37c3 assets/create/models/block/paved_gabbro_covered.json -fa1ed152122fee3a8bce34157159964b5fd8d79a assets/create/models/block/paved_gabbro_slab.json -8cd07e28885661fedca14b976dcd48b7042cee2a assets/create/models/block/paved_gabbro_slab_top.json -460a95cf5fc13f037902b6794a7e8c54a091b3cc assets/create/models/block/paved_gabbro_stairs.json -ce9c4a0cc7168b2fbe094b40a9a13c5fc5368426 assets/create/models/block/paved_gabbro_stairs_inner.json -f51b8fe5408d80ecf79b45fd2e758b947bd89d12 assets/create/models/block/paved_gabbro_stairs_outer.json -3113c182a4ff13adbc156b70a31c80b0e7de064a assets/create/models/block/paved_gabbro_wall_post.json -39a7a337bdca36263fb998c22a02b698b3e9ef06 assets/create/models/block/paved_gabbro_wall_side.json -8bce3c1a2d05e3d1897670c4768883b7a02e5159 assets/create/models/block/paved_gabbro_wall_side_tall.json -12ddeae599606fa0aaee5539f9cea99003220dd3 assets/create/models/block/paved_granite.json -528f2d902f402260d7d7670ef0f0b01b5367cb7b assets/create/models/block/paved_granite_covered.json -053fcddd1f3705dc47f2be515470d6cd006cea04 assets/create/models/block/paved_granite_slab.json -23329b2e8aaf3adddc50aba4ad8e2204db6677af assets/create/models/block/paved_granite_slab_top.json -1f39a935603bd49a76721cccafe49ca56ad616b9 assets/create/models/block/paved_granite_stairs.json -e9a6d727123642bc7db48f1f7e6024f08fa389c5 assets/create/models/block/paved_granite_stairs_inner.json -f7fddf3184dc69b095c432f3f2dfe9204b36ce21 assets/create/models/block/paved_granite_stairs_outer.json -2897b4cc6610e9cbb57582e84913f613903eda2d assets/create/models/block/paved_granite_wall_post.json -7292a674884325407786551a47f42ddc751b8e38 assets/create/models/block/paved_granite_wall_side.json -eec5d2ea68490b4b377bc8d8ae8dcc168e450174 assets/create/models/block/paved_granite_wall_side_tall.json -fd47f060b2d9686414d771fa79f73b0d7d18d1cf assets/create/models/block/paved_limestone.json -a02a16fcd7157e6e7485526673ba6fb30d228501 assets/create/models/block/paved_limestone_covered.json -3af3115c9d46fbf5ff9fb0c2c315292b2932601f assets/create/models/block/paved_limestone_slab.json -73873290e35c04be5e373593c5ab8555d045f239 assets/create/models/block/paved_limestone_slab_top.json -77d83f143597871e51450a370a4c3bf9a21d2d9f assets/create/models/block/paved_limestone_stairs.json -a95e3d5f34c0c8b03bd2a995a2811f3f63f91378 assets/create/models/block/paved_limestone_stairs_inner.json -825770b522f098d39c20850b7e8c887f429cdce1 assets/create/models/block/paved_limestone_stairs_outer.json -7462e8f922b26eacfe28ef5bc56fd1ed2ffdfb0a assets/create/models/block/paved_limestone_wall_post.json -1b3f725c75a524fe9e8039e03f8db84a1b252a96 assets/create/models/block/paved_limestone_wall_side.json -3a5f1bbca22ba53520138c192de22fa05c36fbfd assets/create/models/block/paved_limestone_wall_side_tall.json -2ad932c3a89dd2faa2f6d82c97f32242b092f7d2 assets/create/models/block/paved_scoria.json -a24a73544adbd4dc8afdcb42f42fe95e401a40c0 assets/create/models/block/paved_scoria_covered.json -f737e38308efcf68537505069cf60dba6d1c3658 assets/create/models/block/paved_scoria_slab.json -c6dab2f8010a5d75b1b145ea9c7e30329d099243 assets/create/models/block/paved_scoria_slab_top.json -ffdb9bb5e7072576a9db048fdb6375a27ad6df51 assets/create/models/block/paved_scoria_stairs.json -de95cca903aea66a0fd33e5629b1014fe33e6211 assets/create/models/block/paved_scoria_stairs_inner.json -f70d47a341a352ce53c39c272ef0556e8d6f62b5 assets/create/models/block/paved_scoria_stairs_outer.json -060b7c9b493c172916e99310663636376192eedf assets/create/models/block/paved_scoria_wall_post.json -308450fd3a19195364d268e29bef8afc7f9ca733 assets/create/models/block/paved_scoria_wall_side.json -100b1a1142953a107d283eab42000664c356c214 assets/create/models/block/paved_scoria_wall_side_tall.json -af309a5dd825509e64e3f2dc4db749e7d416cd71 assets/create/models/block/paved_weathered_limestone.json -04f8ab203f904371d9075d601dbb467931a75a50 assets/create/models/block/paved_weathered_limestone_covered.json -2d3700ea734cc2805fff93e1e7c63d8b716b3f43 assets/create/models/block/paved_weathered_limestone_slab.json -38177158a119e703e4e99b47eb12733e232ae768 assets/create/models/block/paved_weathered_limestone_slab_top.json -7aac84ea55c52494e5d9d61f53dc6f9a794afec4 assets/create/models/block/paved_weathered_limestone_stairs.json -db56f592a9ce027f33264d381b29830592b7d42e assets/create/models/block/paved_weathered_limestone_stairs_inner.json -f924c6104378768a3a645f5e77f9ed80d2c31e5a assets/create/models/block/paved_weathered_limestone_stairs_outer.json -46e3eeeefd47f7e6007e53bb1b22de2c6c2a5923 assets/create/models/block/paved_weathered_limestone_wall_post.json -c7941c0bcbdf7ec7e2d34679afac744cf81b7489 assets/create/models/block/paved_weathered_limestone_wall_side.json -39aaea370e31fa032e471d3b8f0ebf0586ee1a03 assets/create/models/block/paved_weathered_limestone_wall_side_tall.json +e151c82942df13d7f4296b6b717b12036c4c47fe assets/create/models/block/oxidized/copper_block_0.json +35cb12fe13b6f39d2baad9b5a1638b6c5b364513 assets/create/models/block/oxidized/copper_block_1.json +a7ea046b36c810816dd749727fcc3f1008807c4c assets/create/models/block/oxidized/copper_block_2.json +e06ed91723927def43bd21d9b26230c07e80151b assets/create/models/block/oxidized/copper_block_3.json +45dc4f29c527b614ce3b12706342233a6de82fa4 assets/create/models/block/oxidized/copper_block_4.json +3890ed69f41efe49233c063c572c6bfb8319e37b assets/create/models/block/oxidized/copper_block_5.json +6b681b9829a2493ee5312d4021e9302cb23d7e28 assets/create/models/block/oxidized/copper_block_6.json +b1ed190a331ba21ffeba378e9526364874a22a9d assets/create/models/block/oxidized/copper_block_7.json +375323c5dfaf643cdce4792e2c86ed6033d43412 assets/create/models/block/oxidized/copper_ore_0.json +e5be33b30e6e83ea1cfdf09201fde1255b0f7a11 assets/create/models/block/oxidized/copper_ore_1.json +cf9ab024daedfaab9e4f3f35cb788e259c3616a4 assets/create/models/block/oxidized/copper_ore_2.json +8f24fce14e52cc4082bf292c9ca8043c98023e0a assets/create/models/block/oxidized/copper_ore_3.json +db2990e91a12fd5c5a039b724da9377bb2a861a2 assets/create/models/block/oxidized/copper_ore_4.json +ffc37d15dde98e7e03d189f55fca33ac203bd1e0 assets/create/models/block/oxidized/copper_ore_5.json +4bfbc1352c961f6beeb35ca44bdc8f4084e7edc0 assets/create/models/block/oxidized/copper_ore_6.json +90daa6f691b18a078eab36a21c0a2d6fadfe20c3 assets/create/models/block/oxidized/copper_ore_7.json +2a88da386c48ff915c9a7fb6b1d96bde796020bb assets/create/models/block/oxidized/copper_shingles_0.json +79c45f98817de41f23e2a6a2a2197fdaf3e8ee8b assets/create/models/block/oxidized/copper_shingles_1.json +0085be85c60675694cfc97d39eb595327c953d02 assets/create/models/block/oxidized/copper_shingles_2.json +b4987ed1fbd44719e59cf911d606b964d51a734c assets/create/models/block/oxidized/copper_shingles_3.json +33d060556bd43b1b51f9a990fc802b204f07ceeb assets/create/models/block/oxidized/copper_shingles_4.json +c9f722cd27fb18239f796eb1fa11a73e5339005a assets/create/models/block/oxidized/copper_shingles_5.json +4df00795cde9497a0910584c6a53b62bfb18fef1 assets/create/models/block/oxidized/copper_shingles_6.json +712f8b01330a1aeff2efce5ac1ec2fdd84b622c7 assets/create/models/block/oxidized/copper_shingles_7.json +d23868f342aa1d821c2971f16b62915d24f257cd assets/create/models/block/oxidized/copper_tiles_0.json +14d893f509073bc0ee6b8a487d1ec4457f717e7a assets/create/models/block/oxidized/copper_tiles_1.json +9d531696a9e989ab090f653d50152fcdf0b8519f assets/create/models/block/oxidized/copper_tiles_2.json +84129b54eb4484c59ad5f3b95b5dea4130a934bc assets/create/models/block/oxidized/copper_tiles_3.json +0e4b39cd5d14470ee9055c3332d3c930d985e075 assets/create/models/block/oxidized/copper_tiles_4.json +c3f2f3574f33ea87c8c32a88c60b386b2ce5c59e assets/create/models/block/oxidized/copper_tiles_5.json +1bdc82a5d6deecaa6e62986bfa4d83ed80cad269 assets/create/models/block/oxidized/copper_tiles_6.json +4ba81cdb32477181225521b13de34b5cb81d3ab1 assets/create/models/block/oxidized/copper_tiles_7.json +081d87f990e01211789e9d0dc43acfceb6982aaa assets/create/models/block/paved_andesite.json +30b9aafb43ecfffcbffdf0aa19b5243e38065ff4 assets/create/models/block/paved_andesite_covered.json +ab78afb3c487976c2dc5dcefa12153fd4a064ca8 assets/create/models/block/paved_andesite_slab.json +7883fa378c843ad87593798e8129eb82f6f2e034 assets/create/models/block/paved_andesite_slab_top.json +d2d8c145ee2ae181370d53224d23df7ec2f3a1c1 assets/create/models/block/paved_andesite_stairs.json +7481fc2f5a2b3ee2259b410da2c1f35e9bc0dff8 assets/create/models/block/paved_andesite_stairs_inner.json +1226bf0720fa814125f7718ec5f2216b36e75b81 assets/create/models/block/paved_andesite_stairs_outer.json +8856b9a15c3239be81cd49a25495367eb755bb9c assets/create/models/block/paved_andesite_wall_post.json +c5814ebc7106b7d729f444f782cc03b91ebdf66d assets/create/models/block/paved_andesite_wall_side.json +bee20297f99cb4377b9c478c86db0c10fd59fddc assets/create/models/block/paved_dark_scoria.json +40a4bc726fa798d6c969dcb0fd8a04941c0e18ff assets/create/models/block/paved_dark_scoria_covered.json +c7bcf573bc82403bb84ac8df63bec1c445cd8e30 assets/create/models/block/paved_dark_scoria_slab.json +9f66f54331e40df74c6b63987d6183aca11695d3 assets/create/models/block/paved_dark_scoria_slab_top.json +5fa06fd6002ec820528623d47ffb67d3c7ac71d9 assets/create/models/block/paved_dark_scoria_stairs.json +313a75f8469ed545da798ad922b55188af1f152b assets/create/models/block/paved_dark_scoria_stairs_inner.json +f86a35c6f20a4582311677bd4ed515cfc52f6719 assets/create/models/block/paved_dark_scoria_stairs_outer.json +f4e0b3486f97dfca7dc0508d807afe037d79a40a assets/create/models/block/paved_dark_scoria_wall_post.json +a5201829b4ec5ff4f940c1b8d903f6766cb62f46 assets/create/models/block/paved_dark_scoria_wall_side.json +ed010fd12474e33023399848eaa2560e67fb1786 assets/create/models/block/paved_diorite.json +9f0f979d9e15a87a909cc7ee523c9efa2fee188f assets/create/models/block/paved_diorite_covered.json +4dc52f0705c0d3add4abf4273d1021cf907c5f10 assets/create/models/block/paved_diorite_slab.json +98556b2a6bab79bd34464c5b54b832ae716dccb0 assets/create/models/block/paved_diorite_slab_top.json +b745c52b431c44683ef6f6eb35d29a795323ac71 assets/create/models/block/paved_diorite_stairs.json +4a45dccbf43ffd8a3e6d2afb41156e24bf69c262 assets/create/models/block/paved_diorite_stairs_inner.json +b06dabc15eca7c4d8e41eb784de259a2fb0b32b1 assets/create/models/block/paved_diorite_stairs_outer.json +e3349e5f33144dca393a08fe573b499917a6491b assets/create/models/block/paved_diorite_wall_post.json +727dfa282f0f9c9f462243c6b85edd3b964982d5 assets/create/models/block/paved_diorite_wall_side.json +af2c89fcdaa2e414ca309e3cee25fe316f976269 assets/create/models/block/paved_dolomite.json +2c907a7d85c6f078fd8c7cab25d7fa0fce95cbb8 assets/create/models/block/paved_dolomite_covered.json +cd87ae72be668bf69f61b83ca0e8579963556d69 assets/create/models/block/paved_dolomite_slab.json +a2e38092ec694840be0cd5d0dd632586668166da assets/create/models/block/paved_dolomite_slab_top.json +1257a4336e687c8a8ae083d7277be594d392df49 assets/create/models/block/paved_dolomite_stairs.json +876d6a25ac6bd8a69b3a302ccd9f5db6de20855f assets/create/models/block/paved_dolomite_stairs_inner.json +f352f5468190893ccf05f77fc93c312c1bee75b2 assets/create/models/block/paved_dolomite_stairs_outer.json +0b280906a41d046dd4340f6cfcf9439abbefa388 assets/create/models/block/paved_dolomite_wall_post.json +7dd9db1faa5075f4c024a7150bbaa36aa206a004 assets/create/models/block/paved_dolomite_wall_side.json +bf650bbe4a716461ee6629d55a80e4fdbf186e7d assets/create/models/block/paved_gabbro.json +3b61df4ad67c9dcc732b1af9efa11ae6fe82c8f0 assets/create/models/block/paved_gabbro_covered.json +386cfdccfc679e32a4ef3c298a5b17f079b7f40d assets/create/models/block/paved_gabbro_slab.json +01d58ff2bb85cc74163aa4c6e528ebd5529342a6 assets/create/models/block/paved_gabbro_slab_top.json +52a5f96e46d53261097a4e190510b64f9f2a4f97 assets/create/models/block/paved_gabbro_stairs.json +97101aeefced27810dd89adc753b1a3e9526f3b6 assets/create/models/block/paved_gabbro_stairs_inner.json +648982e8e37f75b4146096dc04e2ce46c69f25dc assets/create/models/block/paved_gabbro_stairs_outer.json +405bf0ad098f7e525b0b46b2e0810a45ec3f22f2 assets/create/models/block/paved_gabbro_wall_post.json +2b03c0f5fa9ff9b5a18fb64eb1963ee49a585236 assets/create/models/block/paved_gabbro_wall_side.json +737ddffd50beb12e64fc651abf6b39eef15678b8 assets/create/models/block/paved_granite.json +6520e67aedc7f09ae1e0ccf249421dbbbc01c410 assets/create/models/block/paved_granite_covered.json +cf9afa3923d1dd6f9082ea2579c671663cb12aa2 assets/create/models/block/paved_granite_slab.json +981101ec1847e17bd7115580995059fcdbb0a39a assets/create/models/block/paved_granite_slab_top.json +a56941299579280b1ac970802b15b91d0f2af60f assets/create/models/block/paved_granite_stairs.json +9f98d88d6194a740afe26fab7b510ad0ba7b612a assets/create/models/block/paved_granite_stairs_inner.json +b1d2b9eaef07034c619ff897d22440a8e3f30624 assets/create/models/block/paved_granite_stairs_outer.json +d5190b5ebfd581f66a63f7c8af191e484851fb25 assets/create/models/block/paved_granite_wall_post.json +1313a39aac0091a92ebdcd67efa5682b0fa8b6c2 assets/create/models/block/paved_granite_wall_side.json +5caa126fbc2aa3e970c04a93b369e43dbe75ba4e assets/create/models/block/paved_limestone.json +598dab6d11f56cce1d98c46855ccde3f8c3a40db assets/create/models/block/paved_limestone_covered.json +40b0930304bfbed399e0fe4a46d6d4ee23015060 assets/create/models/block/paved_limestone_slab.json +7234c2cc3f40224fa881e7347ab72b154e102bb8 assets/create/models/block/paved_limestone_slab_top.json +7b30942c7e504f0d4656a81bcc11eaa83eddbebb assets/create/models/block/paved_limestone_stairs.json +ff51dfa74e7c3f7c7f6c05ccafc39333b6c1e1ad assets/create/models/block/paved_limestone_stairs_inner.json +9e70c6f40945e723ebe1525bfe317c221a1493e6 assets/create/models/block/paved_limestone_stairs_outer.json +0711327be8ecf3dff399a22f10ed4962c311fc9d assets/create/models/block/paved_limestone_wall_post.json +7bf11f179347567575bd839b6df5982c54309a47 assets/create/models/block/paved_limestone_wall_side.json +df6fdefa2a2bdd6ab737244234c907f88cf38070 assets/create/models/block/paved_scoria.json +3041e4b37080bb6ed2ccaa4e7727791bdac14394 assets/create/models/block/paved_scoria_covered.json +c2034068ee2c9a9dfa7d7070df8742891a599576 assets/create/models/block/paved_scoria_slab.json +5d6f360d60157b54c9f676a71390ea5bec4ba1a7 assets/create/models/block/paved_scoria_slab_top.json +ac2017f2746b34b173eef62cf60586d4a3dacbc3 assets/create/models/block/paved_scoria_stairs.json +a07f07b9e03f07fa4681b291191a9c15527f956c assets/create/models/block/paved_scoria_stairs_inner.json +cd54fcdacb9a762bba771ddcfe6d4bd824495e7b assets/create/models/block/paved_scoria_stairs_outer.json +c495e4fee97b022fd1f3c97ff51543c79bab1cab assets/create/models/block/paved_scoria_wall_post.json +7524fedd7bf1283eb2ee2747af8031a2cade5f97 assets/create/models/block/paved_scoria_wall_side.json +651289c401a89ee5a1a21497153067e7e46918cb assets/create/models/block/paved_weathered_limestone.json +afe2c1f8a14119f3746e741214fd0438bf0ed26a assets/create/models/block/paved_weathered_limestone_covered.json +f09a45d1d83aad870018f779472510a9d6201a4b assets/create/models/block/paved_weathered_limestone_slab.json +a36fff1ba5d2b5e40468c106902e083b41a0d20d assets/create/models/block/paved_weathered_limestone_slab_top.json +cc36e21013b80b1dfa041b55047096db127ffa51 assets/create/models/block/paved_weathered_limestone_stairs.json +8589358359ef3a2fbe054ca61da13c4042e2f431 assets/create/models/block/paved_weathered_limestone_stairs_inner.json +743fc37d4c96834f9bd0697ad7990c721436b901 assets/create/models/block/paved_weathered_limestone_stairs_outer.json +34ba32e570e0a54501db071b9f8c38513edea93d assets/create/models/block/paved_weathered_limestone_wall_post.json +daf65510d95730bcf0373d746f2a2dbfe6b44fc0 assets/create/models/block/paved_weathered_limestone_wall_side.json 1b5f9e819cd4b5f5fe6e8c24920b916e8d93c95e assets/create/models/block/pink_sail.json ecc60ce7ee6b753073a99c597db95d6d9df3d438 assets/create/models/block/pink_seat.json 7ada61878d3a3c1d3cc33bcf9a80c21b8f9aaff2 assets/create/models/block/pink_valve_handle.json -84fdb35acc12ae9580496f458def3e49aa0551ea assets/create/models/block/polished_dark_scoria.json -5ca3d6cbbf1fdd6437d9951b9d2937838ec480f1 assets/create/models/block/polished_dark_scoria_slab.json -737cbe0048415e9e5c5c112fbad541ef17eab94c assets/create/models/block/polished_dark_scoria_slab_double.json -33004fa06ca5bfd3b2266a93cee0ff7a38be7463 assets/create/models/block/polished_dark_scoria_slab_top.json -3fbea8604c9fb464201d8d5beb8fe60ed6aacd11 assets/create/models/block/polished_dark_scoria_stairs.json -c848a34c91e632272bc933c2bb7dd47598ab51d1 assets/create/models/block/polished_dark_scoria_stairs_inner.json -68a2199990dfb12fccd515de2108ddcfa92f238f assets/create/models/block/polished_dark_scoria_stairs_outer.json -51f929698d4ffc536a936d8c8e67c5b7679291ac assets/create/models/block/polished_dark_scoria_wall_post.json -ba98e5023cb9dd7612240d53e12bf3d56f81b84b assets/create/models/block/polished_dark_scoria_wall_side.json -e9c32e77c8bcb9a51bf6d888a071ac7a9aaaf1f6 assets/create/models/block/polished_dark_scoria_wall_side_tall.json -d64f39a77c34577e70e8d98aaefe75aeb6945c79 assets/create/models/block/polished_dolomite.json -bae7b9ad632d19e08e7f2d446ea4a0466afc557d assets/create/models/block/polished_dolomite_slab.json -39585239f35d11e200638fa90df216281814e9a1 assets/create/models/block/polished_dolomite_slab_double.json -2454d00584fa6fdf7a7f59b6b17747a3d049d6de assets/create/models/block/polished_dolomite_slab_top.json -e32d237a575640d8404fc2d7fc85a5c9539bf6fd assets/create/models/block/polished_dolomite_stairs.json -e467c5dc1f54018b59c548e6e78ee13f651d58fd assets/create/models/block/polished_dolomite_stairs_inner.json -46b3356f62263591042ba48a637fcd5838aad34a assets/create/models/block/polished_dolomite_stairs_outer.json -a0eaaab5153b1aea3bc8be6e7d4101403bc53b4d assets/create/models/block/polished_dolomite_wall_post.json -c568d81cbc1a9f246af2dcc899536bdb1d4c521e assets/create/models/block/polished_dolomite_wall_side.json -8520a8b65622208e1d5e7fd5344ed72adb0def48 assets/create/models/block/polished_dolomite_wall_side_tall.json -93f1602bbb8f14760113b5c0ac54a9269c7d8d82 assets/create/models/block/polished_gabbro.json -db4eda3cfdb6d553c097861e474d58591b8c7a3c assets/create/models/block/polished_gabbro_slab.json -95539fcf3d6d4b80df4950f584b7b9fe39835411 assets/create/models/block/polished_gabbro_slab_double.json -19b8e86060d7aec0c2588f97fc7800eb2cd80c10 assets/create/models/block/polished_gabbro_slab_top.json -3748a6803606b4734243af86ce64ba8766d1b54f assets/create/models/block/polished_gabbro_stairs.json -ff2072572e472d6ea19f855abb234c4bfaa5e3f7 assets/create/models/block/polished_gabbro_stairs_inner.json -4035407cd699b1558547ad641a9b5ea6dc2f401d assets/create/models/block/polished_gabbro_stairs_outer.json -2e66935d3c0c264f53778b5197562b622116fdc8 assets/create/models/block/polished_gabbro_wall_post.json -dc5e702f2d1695f18cbfa8807f5fd0aedbbe0b84 assets/create/models/block/polished_gabbro_wall_side.json -df2e04f9d71663cd4e1d6185dc82789d10d7f42b assets/create/models/block/polished_gabbro_wall_side_tall.json -45de1db80d556ef2ae35fb89dd7688bd7fb20d68 assets/create/models/block/polished_limestone.json -fa5ca4787a5ca464807e7807191c227338fc6cd7 assets/create/models/block/polished_limestone_slab.json -2dc18b1073d002ee0f011e3529f1b679cd76ebbf assets/create/models/block/polished_limestone_slab_double.json -dba191453c529e190f104924e8289fcf33fb90a3 assets/create/models/block/polished_limestone_slab_top.json -cce2117c0387032248a6dde70560f5e2043ee883 assets/create/models/block/polished_limestone_stairs.json -e7e3ceb0e9cf0e8cdd6be6cbd8c611e11fd41662 assets/create/models/block/polished_limestone_stairs_inner.json -703fed54153c39fec9efaabe772c93b01e2501d0 assets/create/models/block/polished_limestone_stairs_outer.json -63fec82f0294cb24f6be547bbb24197247cbde7e assets/create/models/block/polished_limestone_wall_post.json -e585a788d160c508b16a4856fbe07152b943fbd1 assets/create/models/block/polished_limestone_wall_side.json -de0629f2ad853bb2a68038381497cb3fcecafe6d assets/create/models/block/polished_limestone_wall_side_tall.json -deb6b365d524f669e8afc62df5adf95763c5aa5f assets/create/models/block/polished_scoria.json -c0ab83dbde560220cbfbab9e87b4f0b42a07eab2 assets/create/models/block/polished_scoria_slab.json -d129e5a5131fcae7c26e23ea40d2da5310aadcd4 assets/create/models/block/polished_scoria_slab_double.json -b36808e58c118269513b1b07c6a5ca47f5355444 assets/create/models/block/polished_scoria_slab_top.json -a1174e2dc5584fb58b6e1fefc1aa0af486a7f79f assets/create/models/block/polished_scoria_stairs.json -ac3b02410e9fd180cc473571764da9b6fa2e5487 assets/create/models/block/polished_scoria_stairs_inner.json -f7f3ba575009735faa2b0cc163d8a498d4b7299d assets/create/models/block/polished_scoria_stairs_outer.json -f78c3b82fa220a6af9b943eb9a5d150ce4f6113a assets/create/models/block/polished_scoria_wall_post.json -f2c04200e1ee865a2b83a69e8fc780de4bf68795 assets/create/models/block/polished_scoria_wall_side.json -15085c7f310e40cb64a272489d35b8ceea9c95e9 assets/create/models/block/polished_scoria_wall_side_tall.json -20e3631cea96df2cefa3cd4f059b466b3525bfd7 assets/create/models/block/polished_weathered_limestone.json -2e6f189cc00e560e0be7bd47f8de0f934987dc66 assets/create/models/block/polished_weathered_limestone_slab.json -df39dc2c6d9fcf87efb59dc67566221695d6583b assets/create/models/block/polished_weathered_limestone_slab_double.json -f1dcba08d955a239b5c4a5a83c32280e57535126 assets/create/models/block/polished_weathered_limestone_slab_top.json -a25db26c0639a9d07219ff6e4e4cc0576bec8913 assets/create/models/block/polished_weathered_limestone_stairs.json -43164817d6bb2a76fba3672f67bc683d0beed272 assets/create/models/block/polished_weathered_limestone_stairs_inner.json -4f3d81ddb0f2dcff148eb7341bb4798ef10bb0fa assets/create/models/block/polished_weathered_limestone_stairs_outer.json -96b3a50bb338484a88c448bb9a412b47e6faf45a assets/create/models/block/polished_weathered_limestone_wall_post.json -d31088540cd68cf1156d9ebd328129aef36e17ca assets/create/models/block/polished_weathered_limestone_wall_side.json -c934df1cfe097bcc0f0c21d1b1a3f3b53e50e831 assets/create/models/block/polished_weathered_limestone_wall_side_tall.json +83a4922d5799a5a1391a2675e9273caa24cde192 assets/create/models/block/polished_dark_scoria.json +3fcab24848791fcd591bf4a2a73147c3391e24b8 assets/create/models/block/polished_dark_scoria_slab.json +7c1b4b3b22c711224a54d55d7c49429c4238d5a7 assets/create/models/block/polished_dark_scoria_slab_double.json +3ea396a641bb21c15badaff996be3bca3076f73d assets/create/models/block/polished_dark_scoria_slab_top.json +9bbd768f40e839ac73f58f8cb5d53ae01c3fdf70 assets/create/models/block/polished_dark_scoria_stairs.json +9d1d2165a7c802518add0defccf6ae97e2d3b3d1 assets/create/models/block/polished_dark_scoria_stairs_inner.json +7b4401d6edb395052d409605a9d475e6345bd001 assets/create/models/block/polished_dark_scoria_stairs_outer.json +bc8ee0c03f6894b38bfa778fe5874d46fc2b6931 assets/create/models/block/polished_dark_scoria_wall_post.json +e2ba5f686d9bd400073073d40f571e7f780f60e9 assets/create/models/block/polished_dark_scoria_wall_side.json +3467c7239bcd6122ce8636f249e29f04dc3bec21 assets/create/models/block/polished_dolomite.json +69307691e26a042a769d9d9d223707083e42efab assets/create/models/block/polished_dolomite_slab.json +b6dadea740a2dec5edd6322994102d5014886d6f assets/create/models/block/polished_dolomite_slab_double.json +1085bcf23b13a587d620cce624546fa287104526 assets/create/models/block/polished_dolomite_slab_top.json +640ad613dce98a4fb37bf1c896fc12bf44762a8b assets/create/models/block/polished_dolomite_stairs.json +2d14ccf702b3d0074d12c04f84cea8a61d122ea3 assets/create/models/block/polished_dolomite_stairs_inner.json +0590c2b945abb66adb859cc85ebe22092f262180 assets/create/models/block/polished_dolomite_stairs_outer.json +298fa4cafd59612cac9cf9f2e8fe20228c02d28d assets/create/models/block/polished_dolomite_wall_post.json +7c52b561d00133ef0ed81036ad5552fbbe10285b assets/create/models/block/polished_dolomite_wall_side.json +ab65a7a8f0c12a441c8653043c59385b834ef71e assets/create/models/block/polished_gabbro.json +2931c767a92c642c7c0d296e38af8f08217263da assets/create/models/block/polished_gabbro_slab.json +f50506b204f2245893df223c86a9245af5ee7cc4 assets/create/models/block/polished_gabbro_slab_double.json +052969eeefba6fd97feb520bcfda97c994dad91d assets/create/models/block/polished_gabbro_slab_top.json +353ab3fa0c2250bff91efd7827f12af5d89f8ad9 assets/create/models/block/polished_gabbro_stairs.json +4c7796d26f3d0bda10244c3243d3e11691a90083 assets/create/models/block/polished_gabbro_stairs_inner.json +fa9f24ab6291189812c5697323c7b66bc960b23a assets/create/models/block/polished_gabbro_stairs_outer.json +bce13297eea7998073f998dffb5dfbd858f3c4ab assets/create/models/block/polished_gabbro_wall_post.json +04b2e4985401f484dfcd226ecb332247773b2f8a assets/create/models/block/polished_gabbro_wall_side.json +77cc6a327584ca4cef6ec3bab9eb1df1053a3fac assets/create/models/block/polished_limestone.json +78b4bc45cb2a89f07d7d012859aae4a995788ec4 assets/create/models/block/polished_limestone_slab.json +d4d74fcd6d6cb63d44392796bd7d8818dd117b57 assets/create/models/block/polished_limestone_slab_double.json +f1204df2a6e31679375045ea57cd07dff1d783ca assets/create/models/block/polished_limestone_slab_top.json +378038e958728919a2239eb0dd65ca5d72112b7f assets/create/models/block/polished_limestone_stairs.json +270091da3f63a2fb2af45ec0cc9200ecb45f5844 assets/create/models/block/polished_limestone_stairs_inner.json +4a7764d8e3aca090ccf34ab53b49941addd30523 assets/create/models/block/polished_limestone_stairs_outer.json +58620d0d6ac6bf70c5cf89951f6de84cf033ad7f assets/create/models/block/polished_limestone_wall_post.json +50b1a7510912db50bca9df368a7f1aade846cee8 assets/create/models/block/polished_limestone_wall_side.json +714126588c571fb7e56eab01b0a638de20f45270 assets/create/models/block/polished_scoria.json +d45780fed06163c231393bfff4ccd70a99e6ff4c assets/create/models/block/polished_scoria_slab.json +f7b96f804379f377038d07af4f1fbf6890ba7f7a assets/create/models/block/polished_scoria_slab_double.json +73d5e1cd975a506f2b07139d0506d5fa1021af75 assets/create/models/block/polished_scoria_slab_top.json +4eb1e9b1235141a2a1c529ca09a3353ee4be5cf8 assets/create/models/block/polished_scoria_stairs.json +0316333eddde04727d7def7c5b7555df6a4a8900 assets/create/models/block/polished_scoria_stairs_inner.json +e4e00e01fa479c6fc9aa450a2e7999ce94504987 assets/create/models/block/polished_scoria_stairs_outer.json +1b9e41ac5b2a89557613c2c8c2cd2c8abcf11af0 assets/create/models/block/polished_scoria_wall_post.json +46227ab60086f0978ba12b8c071b295060e775c2 assets/create/models/block/polished_scoria_wall_side.json +0975a5158ea64238f78c7db8e2a1ddbb4c49d9e6 assets/create/models/block/polished_weathered_limestone.json +8fdfd28ea7b9053b956a93c09d90129ba94baab9 assets/create/models/block/polished_weathered_limestone_slab.json +9243b6fa9210da0fed582b802d0ffc2e1923789a assets/create/models/block/polished_weathered_limestone_slab_double.json +9f3ff426e79bb446a3e913cb7fca0056bed57f0f assets/create/models/block/polished_weathered_limestone_slab_top.json +39bd43b67badad90e1377142facec0ef3e3cbbbb assets/create/models/block/polished_weathered_limestone_stairs.json +1eedeb1b66b7c48c848c66d3ed2d99f4d9e58966 assets/create/models/block/polished_weathered_limestone_stairs_inner.json +97c066d14c3ee37ce4f580d25d3c29ac94a6adf4 assets/create/models/block/polished_weathered_limestone_stairs_outer.json +6d690b231f60496f9b3103e71adda09f8e649158 assets/create/models/block/polished_weathered_limestone_wall_post.json +ba4e86079668f2c03070c99b8d8ef642b60fd634 assets/create/models/block/polished_weathered_limestone_wall_side.json 1c5e97ce8e5b3f5b320873120a4f3084915c0af7 assets/create/models/block/powered_latch.json 3e414b053b973729577a61bb1d73b9a2c2eb56a4 assets/create/models/block/powered_latch_powered.json f22d7d8263dcabd726aa04784031ae9062633579 assets/create/models/block/powered_toggle_latch_off_powered.json e6097d9ab9dc9954cbc750020bc33c7a423b73c6 assets/create/models/block/powered_toggle_latch_on_powered.json 622239a3a09fcac7235b9670eb395a530839a59b assets/create/models/block/pulse_repeater_powered.json -d469dce70d15759baed35025b8c7fa403c8b3b26 assets/create/models/block/pulse_repeater_pulsing.json +0102e253c941904f12de7acdd46b0079ee3ccf69 assets/create/models/block/pulse_repeater_pulsing.json b56fad63b82434564bc41ae9c01e3b427203fb5b assets/create/models/block/purple_sail.json 96adc7865ebe64b43865bc2fe914830c11258856 assets/create/models/block/purple_seat.json 062406aacf25e099f9b28a3bf7cacfcaa1da4ef6 assets/create/models/block/purple_valve_handle.json @@ -1119,38 +1064,36 @@ bffca231a146a6ac49e028f3790cdcbf375e98b0 assets/create/models/block/radial_chass f0099576080a0f2bb09dd85e55777bad69f9f265 assets/create/models/block/red_sail.json 12d4f4119b994c5d71c96ab3aa09beb89dad1e10 assets/create/models/block/red_seat.json 0064825ee3c1702c524d34abb6adb66906586851 assets/create/models/block/red_valve_handle.json -61ce6e1ba7fee30683c86b09ec35da4fbff8f9cb assets/create/models/block/refined_radiance_casing.json -0fa50139aa2ff171feaecf3062b2037fab10b786 assets/create/models/block/scoria.json -055249d2dec8b94abb919cfb834767c9fbfb89ee assets/create/models/block/scoria_bricks.json -50951f14324df91347f72662a1ad59a106de4087 assets/create/models/block/scoria_bricks_slab.json -9d7cf929f10cd44fba457f905f7933c319770573 assets/create/models/block/scoria_bricks_slab_top.json -8bac5d96e08ec5c0e4767079c9e445b3a5c90065 assets/create/models/block/scoria_bricks_stairs.json -8e57f73d1c53e1026a4c4b66a9a1c1b1451eda56 assets/create/models/block/scoria_bricks_stairs_inner.json -335e9464ef1d191b45080ff23326279a25d281ee assets/create/models/block/scoria_bricks_stairs_outer.json -8684da45450c61dea65a8804e1c8ffaf07771e9e assets/create/models/block/scoria_bricks_wall_post.json -67adf9034cf36c0c3c6ae11d7f691b2d75eec85c assets/create/models/block/scoria_bricks_wall_side.json -9cface9b8238c71164d5bd14cca97341372cf93f assets/create/models/block/scoria_bricks_wall_side_tall.json -a550b247d64c533a53399aaf032bc905d53cc4bd assets/create/models/block/scoria_cobblestone.json -737da3e1fb5d383df8f87698816d05c6707639fa assets/create/models/block/scoria_cobblestone_slab.json -35d8cceb387ca76cc6635c29536a5fb02b6e5f11 assets/create/models/block/scoria_cobblestone_slab_top.json -6343fb437c2b6db2cb49e4198f335e433a422dc9 assets/create/models/block/scoria_cobblestone_stairs.json -543e2c46f60db20d8fb61332f82b94fc74c25e1d assets/create/models/block/scoria_cobblestone_stairs_inner.json -00273f15e4bd44881024c7d52acfb58f4bc0dadf assets/create/models/block/scoria_cobblestone_stairs_outer.json -7c1ec0220820fa47c948e3aba053b4dc06711e86 assets/create/models/block/scoria_cobblestone_wall_post.json -a5ea862312a58bc3153971b386a6eeb46c7b2a1e assets/create/models/block/scoria_cobblestone_wall_side.json -43d1dcf26be225c778cf99ace91c8dac17c39986 assets/create/models/block/scoria_cobblestone_wall_side_tall.json -f1596a182600fbc2461cb82bbdbd7e2647b7ddb4 assets/create/models/block/scoria_pillar.json -0dc7fb2eab3443bb029d9433036db0a67fcce4f2 assets/create/models/block/secondary_linear_chassis.json -73bbca2adae7ebe54115df8c3dcd31280241cab5 assets/create/models/block/secondary_linear_chassis_bottom.json -dc120319696c6bd58472383c2b5f8f656c0a4d7c assets/create/models/block/secondary_linear_chassis_top.json -6a1aae30a9ca08d28a224bfc532a6bf56411e026 assets/create/models/block/secondary_linear_chassis_top_bottom.json -d2d943d45826352f96158a393f0d750c71fd50a3 assets/create/models/block/shadow_steel_casing.json -5757ae82250167dff2fb56fd38624d1cb312fd71 assets/create/models/block/spruce_window.json -f6096d529b8f97f0bfdec75c13e4b31958346c58 assets/create/models/block/spruce_window_pane_noside.json -703b2f32430e2cc55b4f617cab5a1fa38c4de962 assets/create/models/block/spruce_window_pane_noside_alt.json -ea7952f49c78f0d7b95f3ed34df35a44a921ce15 assets/create/models/block/spruce_window_pane_post.json -04b92ecb2aea4264c58e2d3df0d77ab9fcdcf2d7 assets/create/models/block/spruce_window_pane_side.json -a5bb90cb3f5353bbfe767b3d42f4d1dbac3b498a assets/create/models/block/spruce_window_pane_side_alt.json +c4bb40ed2bddabff154a34f4eff7a485bf6488a0 assets/create/models/block/refined_radiance_casing.json +c145d8e0d7f8f41afa80b9727a107b2ad2f0c3c9 assets/create/models/block/scoria.json +59c6f6a4ffe43485244a8561d7e8341f796e268b assets/create/models/block/scoria_bricks.json +d86ca38a0c1bac89e545916c59f23f6f0c9f7d7a assets/create/models/block/scoria_bricks_slab.json +ac0731b633bf1d1af38fcb6b5c17dea405a017c8 assets/create/models/block/scoria_bricks_slab_top.json +aefdd0cf03f7b07ecbd20aa9743d8b0c1ac01c7b assets/create/models/block/scoria_bricks_stairs.json +fd93d2aa5e2e1646ddf12c3ca8c011eb0791653d assets/create/models/block/scoria_bricks_stairs_inner.json +54e43e6e17dd9df3696005cfb803fc20d403c1ae assets/create/models/block/scoria_bricks_stairs_outer.json +6e01226f5586ff2885b001a020386dcd9da4cea5 assets/create/models/block/scoria_bricks_wall_post.json +eb72b9a4daf4a045a7583d8187107edbad9d7856 assets/create/models/block/scoria_bricks_wall_side.json +a5feba461b74c57a9583ef855b779142a618a844 assets/create/models/block/scoria_cobblestone.json +b5de7b127d49a69ae57e4be6fa6a0299d9df357b assets/create/models/block/scoria_cobblestone_slab.json +7e5a50dbafa8f3b8e285fa6efb995ad234377242 assets/create/models/block/scoria_cobblestone_slab_top.json +0da9d63d95f0cc05e764c0db65dc9f05d9f6b803 assets/create/models/block/scoria_cobblestone_stairs.json +6fb83d3bfb13d62822fbab12bb991e7fc595c8ad assets/create/models/block/scoria_cobblestone_stairs_inner.json +de66b504054f37eca6e5eeee6245fb8f9db2e1bf assets/create/models/block/scoria_cobblestone_stairs_outer.json +34aa3f34fce851ac6f87be0c276e074dacd9bbf4 assets/create/models/block/scoria_cobblestone_wall_post.json +43cd43cc26ba06f953c52c3fb67841141a99da6e assets/create/models/block/scoria_cobblestone_wall_side.json +0e70dc21ac625a0796ded99c734087c97fa5966b assets/create/models/block/scoria_pillar.json +74cd7c13043f6a5c680a7c73ed46a44a7507b8bf assets/create/models/block/secondary_linear_chassis.json +fbe57e52b0234c2c379d82d6cc425d6ce9492454 assets/create/models/block/secondary_linear_chassis_bottom.json +e439d642f3c2049dce444b7b4bea8532eb22699c assets/create/models/block/secondary_linear_chassis_top.json +5fc7d8839c6de9363d22fd22be7f440aab853121 assets/create/models/block/secondary_linear_chassis_top_bottom.json +3020d66d33996dd4b203905a54538d3dd5f01330 assets/create/models/block/shadow_steel_casing.json +3fc9a7ae552095d0f45f8e632e2bf04d1378946f assets/create/models/block/spruce_window.json +f39904a8a73a25e440d6a35fad931f8ce7ef165e assets/create/models/block/spruce_window_pane_noside.json +7446e12a5ba91c008b17fd70484468caa36500b9 assets/create/models/block/spruce_window_pane_noside_alt.json +f15dfc9e4e6b991ee9fe10e8af3d9c98cb3d7e47 assets/create/models/block/spruce_window_pane_post.json +0e8be4d143d1fd8300c00ce709139a0e577cdec3 assets/create/models/block/spruce_window_pane_side.json +aea7061aed39bc8c9ab51c8d7d0d86b11fc9e6b4 assets/create/models/block/spruce_window_pane_side_alt.json 3bda065e24a71b82b92b9c805790ba6d1791ef6a assets/create/models/block/stockpile_switch_0.json 335d6bc2b19d3cdbc9ed8b344142e2e3aa397994 assets/create/models/block/stockpile_switch_1.json 655d5cd249291a550bb3508c97f5a7a3606a7848 assets/create/models/block/stockpile_switch_2.json @@ -1158,157 +1101,148 @@ cd8242a881e78831f6573c1fef99f9941ecf6ef7 assets/create/models/block/stockpile_sw ad1950ba333cb2095c0dba5c0c020517acbfeb28 assets/create/models/block/stockpile_switch_4.json ba22751c2d11fbe0ee03d90d408250edb4148080 assets/create/models/block/stockpile_switch_5.json d6a49bf3c26ab83de70190db5f8a9c6dca85df52 assets/create/models/block/stockpile_switch_6.json -050ba6ad19c79ca0c7e5a2876981f47b54c1dad1 assets/create/models/block/tiled_glass.json -105f953f708c78f95de5db5def20c6ff0d1af4c9 assets/create/models/block/tiled_glass_pane_noside.json -d257b024117a6003196c1feb85e759a3e1c180f7 assets/create/models/block/tiled_glass_pane_noside_alt.json -87abdc362465124e14b49ea5fd4135a071e71eae assets/create/models/block/tiled_glass_pane_post.json -53f8eeba028cdef5fecbdfa91a573d6f19bfd150 assets/create/models/block/tiled_glass_pane_side.json -6b1727111d9178162598b4ef7106da807d590bf0 assets/create/models/block/tiled_glass_pane_side_alt.json -b1e94d2858c3a8807def6c5131b6f63fe586fb91 assets/create/models/block/vertical_framed_glass.json +43d5aec0654274af2202374a77aab0e74ea7182c assets/create/models/block/tiled_glass.json +57ba644714ec486df776d75692b1793b2bda25db assets/create/models/block/tiled_glass_pane_noside.json +886fa013d1fd3bdefbc1aadf0b62e2777ceff4c9 assets/create/models/block/tiled_glass_pane_noside_alt.json +3d293702831960ba6d924753d1fd35de71256c13 assets/create/models/block/tiled_glass_pane_post.json +efed7cdc64a732129964e8f8a9a20ff015f7d287 assets/create/models/block/tiled_glass_pane_side.json +1384613ed9e7f9cd737190703d932466a7143f35 assets/create/models/block/tiled_glass_pane_side_alt.json +9730fcb02f679087e81e24c836751e625be6a298 assets/create/models/block/vertical_framed_glass.json d13df8a5920c5778d98081fb0e97f045e2fd46a2 assets/create/models/block/vertical_framed_glass_pane_noside.json 3e975bec02e2670ce2b1868cebcbd780a5ebf3f8 assets/create/models/block/vertical_framed_glass_pane_noside_alt.json a5938ddd48109f067a19a90a0f9abab655c18821 assets/create/models/block/vertical_framed_glass_pane_post.json 41645919ece236df5804a5a73ef682720194de34 assets/create/models/block/vertical_framed_glass_pane_side.json 8bc0abaabdc62d0c27730dba7eb6da54607b7e96 assets/create/models/block/vertical_framed_glass_pane_side_alt.json -c6c7067a760d8c787841a72c8048172fb534d8c5 assets/create/models/block/warped_window.json -01a1034b3bad86f23874b045c5eceb0f1078d6d9 assets/create/models/block/warped_window_pane_noside.json -51179b8e4e3d91cfb6fbeb08e1920afc2c16c237 assets/create/models/block/warped_window_pane_noside_alt.json -82b11c5dbd3ffdbbd129c4b4244487a8f3256f33 assets/create/models/block/warped_window_pane_post.json -b3682b275994e1dac31d56b56f3f3c1e3b2962d7 assets/create/models/block/warped_window_pane_side.json -0b1c6b66d22338e0152a62f869475d734029611e assets/create/models/block/warped_window_pane_side_alt.json -867c400d32bc2242d041bf650149fced6e7104ed assets/create/models/block/weathered_limestone.json -0235f7c186a5cb6c5081c4bbddb2e5bb0af76c93 assets/create/models/block/weathered_limestone_bricks.json -a569dd152c6a52281fe5ca704fa439768ca9b485 assets/create/models/block/weathered_limestone_bricks_slab.json -9ccff818a7ed23b57c822cc375ebdb5b570cf57e assets/create/models/block/weathered_limestone_bricks_slab_top.json -167e337371c3b173c3fcdd99ad1457e53a0fa85f assets/create/models/block/weathered_limestone_bricks_stairs.json -981c2a48bb7ae15e9c5291eff31f283a8a4739f5 assets/create/models/block/weathered_limestone_bricks_stairs_inner.json -e5ba7ee05569e34ac19e02ac8b16417e64dbba9e assets/create/models/block/weathered_limestone_bricks_stairs_outer.json -50daa813041c3dc7e830c67d12283501adba6b8c assets/create/models/block/weathered_limestone_bricks_wall_post.json -2ac4d82dc632f73dd97dc1b9779c7932fb20652e assets/create/models/block/weathered_limestone_bricks_wall_side.json -5335f6da6c93fada61fcea0036ce335eba0db7c8 assets/create/models/block/weathered_limestone_bricks_wall_side_tall.json -ce57e695293dacf7fdc0b7d9cb8ca798288e60ca assets/create/models/block/weathered_limestone_cobblestone.json -5d5e2e12dfafa81626fbe01314541e1e60c5d9b5 assets/create/models/block/weathered_limestone_cobblestone_slab.json -99fb198ac248520f42c84f19f7f92875abf424b7 assets/create/models/block/weathered_limestone_cobblestone_slab_top.json -acf3900465101f9dd78d2301eab1063cdb461582 assets/create/models/block/weathered_limestone_cobblestone_stairs.json -18124072ac417986b9c2aa1888d5b127fb084929 assets/create/models/block/weathered_limestone_cobblestone_stairs_inner.json -79fa4e8da0dc8a8c10ceaf918baf1f7b86ce219e assets/create/models/block/weathered_limestone_cobblestone_stairs_outer.json -30ea04210ca8cc79404ed54352d1483aec6533ea assets/create/models/block/weathered_limestone_cobblestone_wall_post.json -7f1582fe36aa94be4352b8eda89c8ebf7a353333 assets/create/models/block/weathered_limestone_cobblestone_wall_side.json -3235d3148535283e9e9b4ee336b92055e7c6bf01 assets/create/models/block/weathered_limestone_cobblestone_wall_side_tall.json -8c6feec0411e95f9aae18f9f38b4e045156857e8 assets/create/models/block/weathered_limestone_pillar.json +9ad34714c6be52f9277d888b6901e903ddc3f98e assets/create/models/block/weathered_limestone.json +9b4705c62bc8326ca9e53635de5f84c60085fa23 assets/create/models/block/weathered_limestone_bricks.json +732dd7554fe2c7ad4b0cdbc49d9d10de0da91a06 assets/create/models/block/weathered_limestone_bricks_slab.json +f7896fc9d052a29e16b4f4785455bfc276e24732 assets/create/models/block/weathered_limestone_bricks_slab_top.json +334bdfb69c00847f18b5252b310d4bcbe044b3a4 assets/create/models/block/weathered_limestone_bricks_stairs.json +86bc436e8a38db2c152a1f6cc2711de921283f00 assets/create/models/block/weathered_limestone_bricks_stairs_inner.json +e56eb7d2613b0c17cfbf09deba83334741f62812 assets/create/models/block/weathered_limestone_bricks_stairs_outer.json +30eefefe463c64e1b4c185046be157a29e848880 assets/create/models/block/weathered_limestone_bricks_wall_post.json +d6166f98b0260a4abe5b78d207636d061dfd7109 assets/create/models/block/weathered_limestone_bricks_wall_side.json +3edd6331b30b8db34a147ad4a47164359ce6c0d7 assets/create/models/block/weathered_limestone_cobblestone.json +4c6e4f8d29f62e460f38c69ba98d53383a2cbb91 assets/create/models/block/weathered_limestone_cobblestone_slab.json +273c2b0ac70eceea9d29e82d30318c2251f638a8 assets/create/models/block/weathered_limestone_cobblestone_slab_top.json +e75cd38014f3d96fa164e11a526d5dd74851763f assets/create/models/block/weathered_limestone_cobblestone_stairs.json +714c8065714e13b3b19d1411d8fefebc13dfd0fa assets/create/models/block/weathered_limestone_cobblestone_stairs_inner.json +eb838d687f7a925f5b91c4784bfbf33070515e31 assets/create/models/block/weathered_limestone_cobblestone_stairs_outer.json +7b70d26bf88ccc3bb0657e00c6ca50b7149d3643 assets/create/models/block/weathered_limestone_cobblestone_wall_post.json +5a866d7cca51056c15a5f51e171d89598426fade assets/create/models/block/weathered_limestone_cobblestone_wall_side.json +a5b04a1a35735713f51dcd5a80d9e582e6575bbc assets/create/models/block/weathered_limestone_pillar.json 1377e12f56dce1466ce44078d7154870c5cf7b2a assets/create/models/block/white_seat.json 899f33d51cf36cb1c283bc7e6363f9d451e5736e assets/create/models/block/white_valve_handle.json f2bee22fe03ac047fbe73ca2c5c759f09bf646df assets/create/models/block/windmill_bearing.json 071ca07daceea4d0db7ed41e815d47589fdb14b7 assets/create/models/block/yellow_sail.json 0a0e2cc973e35586ae00ed17b919383868e992e8 assets/create/models/block/yellow_seat.json 55edee7b0833ab19b98694fab21ae0c8e91f76fd assets/create/models/block/yellow_valve_handle.json -36c27bad342c82aa8dc097da87637dca042cce17 assets/create/models/block/zinc_block.json -f3059145a84ddbd54d08167e984112c7baf5ef4a assets/create/models/block/zinc_ore.json +c94c60d1d77404af7d74a29a094c7bdf7501b385 assets/create/models/block/zinc_block.json +a3ff06384fff574ac4cd6c253259f0734b025cab assets/create/models/block/zinc_ore.json 67ef6fd6ec26fc216fa5319b8538beb223da1530 assets/create/models/item/acacia_window.json -c695dab3964186a857767b2b4975aebffa86dcf9 assets/create/models/item/acacia_window_pane.json +cbc0ebadda4497663437f99622914de678d0ffaf assets/create/models/item/acacia_window_pane.json 564f6245f92ec48a733e34d91b96b1beebbaf44a assets/create/models/item/adjustable_chain_gearshift.json 06d8b6e8f050b8ec0bef88b7633f3741baad4571 assets/create/models/item/adjustable_crate.json 96fcec285c0c26a8cb55e126f8c7053c70ad188b assets/create/models/item/adjustable_pulse_repeater.json 30292e874dd36e45eaeebb8d0bb8c4867866a38b assets/create/models/item/adjustable_repeater.json e7759d9b3cd64d2719a58dc35fc75ca65b9e14fa assets/create/models/item/analog_lever.json -2e90c7abfcad12ca656ae253d834fbb799e15277 assets/create/models/item/andesite_alloy.json +168786b05674b17fb1eea530e3575a6f34edc798 assets/create/models/item/andesite_alloy.json a513af38f164a48fd44693b70a93012f3546caff assets/create/models/item/andesite_bricks.json 851090d21c6e6c67444324d975c6b3270eaf4ff2 assets/create/models/item/andesite_bricks_slab.json d283f86cd05ed378efd82ce46cf49bc83783069b assets/create/models/item/andesite_bricks_stairs.json -640e4ae7fd4e79437ce7bf1a1ab5b66dc497b494 assets/create/models/item/andesite_bricks_wall.json +3954907be88f0b6713cec8dcfe0ff665ce33bbd4 assets/create/models/item/andesite_bricks_wall.json 174c9705d25f149052835fdcf7c85626afead90b assets/create/models/item/andesite_casing.json 1fd20e35848e47483f4f3e3ca3376b0519178952 assets/create/models/item/andesite_cobblestone.json 1ceb0e49f2c46f1d5414d5fd6edfc2bdd3afa6f7 assets/create/models/item/andesite_cobblestone_slab.json b0f664dd6de3d0ee9afcb6223fbcd53b97fa0d65 assets/create/models/item/andesite_cobblestone_stairs.json -8861d656eb6f61320b4d80eb079105705c762079 assets/create/models/item/andesite_cobblestone_wall.json +4856d13a72ec0af9f10226b4a4bf0567eb580b9a assets/create/models/item/andesite_cobblestone_wall.json bc6e7469744604e578200ea87690e4dd3b25e447 assets/create/models/item/andesite_encased_shaft.json a3866ea9f44e80b64989f2b5f8a9f344da959c87 assets/create/models/item/andesite_funnel.json 75b8b00c2418b9660d35a7fabd0774925cf1c02f assets/create/models/item/andesite_pillar.json -795541cf7205d90531a23cd5b388f93a03bbf925 assets/create/models/item/andesite_tunnel.json -cf9e35bfea0b0a324e1c6384990425b3d359792c assets/create/models/item/bar_of_chocolate.json +c0e35daccfb398947532e9499d6bda963387cd9c assets/create/models/item/andesite_tunnel.json +54875c992ec4e314826ca37257e64a96f1c0907e assets/create/models/item/bar_of_chocolate.json 421e481b7fbca4c4a1080ed703401eb25375e087 assets/create/models/item/basin.json -ffdb36349fa2e50451c208585162b6a8386ec494 assets/create/models/item/belt_connector.json +1da382e7e58eaa9788f5b1d92221ccac573e068f assets/create/models/item/belt_connector.json 9044243882cfd49a2827e1b910a4c9b0e46daa47 assets/create/models/item/birch_window.json -d537fffaede521efa525fb2a7f9863fe6a80054e assets/create/models/item/birch_window_pane.json +6ed49f59ea91068ef68720f43e67a9237594bdf0 assets/create/models/item/birch_window_pane.json 22632bd681c8a605f0845f7549770389a741156a assets/create/models/item/black_seat.json 56a6baedc608792cd6ab72a1c4fd53046cbda070 assets/create/models/item/black_valve_handle.json 80a6e8b00709fe0521aca5b789ae17485ed9c56d assets/create/models/item/blaze_burner.json -6e350231e9f217019883096b4f0bb95ab0af4728 assets/create/models/item/blaze_cake.json -5d4e5c22295f9b5cc62cf6e74fe1384fbbb319f9 assets/create/models/item/blaze_cake_base.json +c20627feba667b063893b128ee195c1abdb0f88d assets/create/models/item/blaze_cake.json +bb70b42b28a46b58c763053a07bc4e51c76a8550 assets/create/models/item/blaze_cake_base.json 0e1977585128fc0ecef640f72e5fc5e9fb47ef92 assets/create/models/item/blue_seat.json bec96ebf3369d3cffa9bb1b8bf9f2a5cd5d0ef96 assets/create/models/item/blue_valve_handle.json 17d340c3678bd24cb085ba49490b2b4cb341a9e7 assets/create/models/item/brass_block.json f5a18f4279c2e845a5967b1c2f9e807c2bb77afb assets/create/models/item/brass_casing.json c723011e09203821b6b59cff9de22454c5e4395a assets/create/models/item/brass_encased_shaft.json 12781f22d9b91df903d38bc55c4fe9f75dba8867 assets/create/models/item/brass_funnel.json -965f3f992fde899719506fd584f3fbbbf69af93c assets/create/models/item/brass_hand.json -d5e8b577aee56671e117a4a2ac93e58680b51949 assets/create/models/item/brass_ingot.json -44565b9b2c227e99e336357e5caa588438e7076b assets/create/models/item/brass_nugget.json -f7aca6aff65e1de269a99cf2a280d9841b7a0076 assets/create/models/item/brass_sheet.json +361f75a79de5007d7a99ad0a38103c9aa8c3017c assets/create/models/item/brass_hand.json +1786bdffa2ab5a07c88d2797db3d7b54461323c4 assets/create/models/item/brass_ingot.json +a37be4a0ec9bf6c381527403c57ced4f81abd67c assets/create/models/item/brass_nugget.json +14ea6ee4db6e7e76446e331a70b6b6bec31e8eb7 assets/create/models/item/brass_sheet.json 427bef12405e2a99fbf49e27ea5944add244252a assets/create/models/item/brass_tunnel.json 24df6f8391d8ba09cef46e69d65d32ea770745cd assets/create/models/item/brown_seat.json 54211d3bdbeba2ea4dbaed43daa740ae3331640f assets/create/models/item/brown_valve_handle.json -329c17cd2ac693babf6f05d0be94cfb1683a87cc assets/create/models/item/builders_tea.json +a7a17c99ed261f771dabcd0e287281eb1d714139 assets/create/models/item/builders_tea.json 3e232a103f7f916fc11edb4d541ca99fe7b44181 assets/create/models/item/cart_assembler.json -36a680c6d0cd485402b72056cead58fd3dbff5f8 assets/create/models/item/chest_minecart_contraption.json +c9be9d3f8d01ed7e283fdcf347c88458af13460a assets/create/models/item/chest_minecart_contraption.json 99d64b76b3baa84c3bd4b96ccd3376ca12425950 assets/create/models/item/chiseled_dark_scoria.json 83d3571eacde52568786802b268f24c6578c1e5d assets/create/models/item/chiseled_dolomite.json afd697168c9786eb80e54eccdc6a23afa6c7fb0e assets/create/models/item/chiseled_gabbro.json 0cb1692f6cdd007ac690fd1f0222dde3429d136f assets/create/models/item/chiseled_limestone.json a47fbe5f2da79080d99ef0975bfa8da4d08f8be4 assets/create/models/item/chiseled_scoria.json 70232ce9b88119fb383717e2c1ad113f7aad6a99 assets/create/models/item/chiseled_weathered_limestone.json -7a3737f6156213762e28a4dbedc4c6828dc1878c assets/create/models/item/chocolate_bucket.json +eabf1870127d78c920305228eb51ddf36c44d016 assets/create/models/item/chocolate_bucket.json +473c8fcc3c53a7680b2f1c6505517c79fd07153a assets/create/models/item/chocolate_glazed_berries.json fe67c3f380d17735a9436a4579a8be1a02b8e4a0 assets/create/models/item/chute.json -6680a68526576ded5dac2aa3bc9fb9de3e744146 assets/create/models/item/cinder_flour.json +d418205c83d3e57c830755ee8c09e2962353e493 assets/create/models/item/cinder_flour.json c1da21be9f1af4f7a2ef4ec9cd92195d65ada316 assets/create/models/item/clockwork_bearing.json 0a2a0f0aafeab0088172f77afd40c1fa2cc1f2b8 assets/create/models/item/clutch.json dcb09deae110077bcddf090996b51cc66e9a7de3 assets/create/models/item/cogwheel.json 7717e3b21cff39f497f07687c70c1fa40eaa756d assets/create/models/item/content_observer.json -9dbd63c9e1b09a663fd4b83d76e3ab5967086167 assets/create/models/item/controller_rail.json +a43fd15e644dcb8c298f9190dfe6e9802df874e9 assets/create/models/item/controller_rail.json 965a90a882d85dba93b30af9bce7ecf8e68ce747 assets/create/models/item/copper_block.json 759bcb5fe7dfdd628716f9b4ff19a5ab00393381 assets/create/models/item/copper_casing.json -c2a320162daa2d24cef969d1d14a0cbd55eb574f assets/create/models/item/copper_ingot.json -751324b03f657f4166460eb10a64dae47cb97bd4 assets/create/models/item/copper_nugget.json +c5bcfba46f5824654dedaa2c5d5f42deb29e3baf assets/create/models/item/copper_ingot.json +3cdb321193355af630ee0e0b18bf24a9469aabad assets/create/models/item/copper_nugget.json 51be7da59368681522de870f1e09036dac55aa77 assets/create/models/item/copper_ore.json -177dafb51d70c55ec62036332868efed4e01f353 assets/create/models/item/copper_sheet.json +200ef8378a9c014571c414433d4aef73a204dc01 assets/create/models/item/copper_sheet.json d7cb2f7bac8fae893fc5179af8140786a908f3f5 assets/create/models/item/copper_shingles.json f56bf22324faf8958eaef4d94b958f1108d52e5a assets/create/models/item/copper_tiles.json 5583368909c319acfcf0f7a419bedf23272fe613 assets/create/models/item/copper_valve_handle.json -4e253e7c0626dfd76e2d39786ce1a34e0baaa62d assets/create/models/item/crafter_slot_cover.json +4e9126b349d55c65aa5407f05700579e52101c1f assets/create/models/item/crafter_slot_cover.json 7b333dea353afaa27b182aedc647c9e9e34e92ef assets/create/models/item/creative_crate.json f7d06c52c3ca8c22ad67f5741471f06ac22e7fcb assets/create/models/item/creative_fluid_tank.json 5b39403f6c81f05e566b621b62e267267de47c41 assets/create/models/item/creative_motor.json -5680d7cee347c46bb29db8c77dc33f234a7eba41 assets/create/models/item/crimson_window.json -cdcc4c773bdda431e2aef26e83c061db36e66bae assets/create/models/item/crimson_window_pane.json -e5f43ee61a7f434a487a5c91890d7eb295928d73 assets/create/models/item/crushed_aluminum_ore.json -6281a7439c92459761893835f91fde25467fae76 assets/create/models/item/crushed_brass.json -cd148cb7e881091ecce2390dac0d9f545573c91c assets/create/models/item/crushed_copper_ore.json -5b701661c7b847dfe5b4cbc854b48f128f90090c assets/create/models/item/crushed_gold_ore.json -38181d7bf4284534666cfd62c1c9defed69d0788 assets/create/models/item/crushed_iron_ore.json -23bd807b2e667810c800ad56dc1133b96aa32726 assets/create/models/item/crushed_lead_ore.json -5a3e06b518bf5ba66366da2e01797f6d014ec003 assets/create/models/item/crushed_nickel_ore.json -635e874e6e07133786b19110f901363f18930187 assets/create/models/item/crushed_osmium_ore.json -d8af07fa338c986bcadaa3cec0ae9d36bd852f43 assets/create/models/item/crushed_platinum_ore.json -d99a0ad01203ed70cd110acda082a1d55a06b9a5 assets/create/models/item/crushed_quicksilver_ore.json -cecee6daf2619dcf035c7aea5fff1bd892f6ff06 assets/create/models/item/crushed_silver_ore.json -a8d3f330d312f82b0de59940581910090b2bd012 assets/create/models/item/crushed_tin_ore.json -b359064405d189e2802969715cd5f682ddbf0bb1 assets/create/models/item/crushed_uranium_ore.json -2bb791db62dce6bf2e2227f9b607c131828471fd assets/create/models/item/crushed_zinc_ore.json +ef179ce217a5ab581f905a28d463146fd5382b01 assets/create/models/item/crushed_aluminum_ore.json +19c8492ced64a872a040005dd212a9a14e20477c assets/create/models/item/crushed_brass.json +8167f2a6d05d65a4ebd809b9c114027862afb38e assets/create/models/item/crushed_copper_ore.json +371f1c74cf327c3c48a4ba1cffd5f6003ba5ab77 assets/create/models/item/crushed_gold_ore.json +604931d2906bc545a468987a4f151d64f20e79de assets/create/models/item/crushed_iron_ore.json +d66f0c0b34c51752e9697150d8a81c4ca2eb65cd assets/create/models/item/crushed_lead_ore.json +684c42e00735dfdd087636ee3a8349046b962c00 assets/create/models/item/crushed_nickel_ore.json +86c27fa0ab9144fab3f6dc0d40d0b86605cee8ef assets/create/models/item/crushed_osmium_ore.json +e36fc7006a51f0776f2ec2ad794d430b8663d629 assets/create/models/item/crushed_platinum_ore.json +81c49c61f14ecc48515a96504bb0f00d9ad76eff assets/create/models/item/crushed_quicksilver_ore.json +7a411059878535be90bd81a75e3464eddb79b087 assets/create/models/item/crushed_silver_ore.json +1457068ec6d5a0fecdf3527ee4bab39ddfb754c6 assets/create/models/item/crushed_tin_ore.json +dc450a83e510a32921d73a067859dd9c6a490832 assets/create/models/item/crushed_uranium_ore.json +8b9c0aa8aaf979ec85eac59b27799cc1c0cf427a assets/create/models/item/crushed_zinc_ore.json 823c91f63565db54ec3944a1e90e7aee18e41062 assets/create/models/item/crushing_wheel.json dae5cffa4e1263d6a113469f79fba8695fa8232a assets/create/models/item/cuckoo_clock.json 3e3edc9ccded444496d3336926b93bbf1234cd84 assets/create/models/item/cyan_seat.json 523cd531eadaadc45fb356ca58b99a8fe206c3a7 assets/create/models/item/cyan_valve_handle.json f786a43e296d9f10d7c302fe3ae9cddf4ba9984e assets/create/models/item/dark_oak_window.json -515d55b1ce18543fdb44b194901040fd29e75818 assets/create/models/item/dark_oak_window_pane.json +e3e9ebbc694edad1f473e5c3a897d95cc87528ae assets/create/models/item/dark_oak_window_pane.json f0e98871e4bb68c29954f2de24566a6404f21d9c assets/create/models/item/dark_scoria.json 411a6c77ec3c80b3d9134f6595d1996439c7af27 assets/create/models/item/dark_scoria_bricks.json d59c7b08b4b246c9795e579ae1f0a4cdfbcea4be assets/create/models/item/dark_scoria_bricks_slab.json b50e3471476783be80f28bb4e3543f5a426b9eb6 assets/create/models/item/dark_scoria_bricks_stairs.json -865ee1e3b097c090a0a7aa0c7d90ced103732628 assets/create/models/item/dark_scoria_bricks_wall.json +28ed58a754a31b6ace92fd0232b025fc6f87df31 assets/create/models/item/dark_scoria_bricks_wall.json 4dc989dde0810acc9631e03c96d53f4df95166ed assets/create/models/item/dark_scoria_cobblestone.json 6346b77a8a6b854ff345b9b256769dec98c9943a assets/create/models/item/dark_scoria_cobblestone_slab.json e67fe11e9036c81f0f54d368b41a971822a84a32 assets/create/models/item/dark_scoria_cobblestone_stairs.json -6e6867197215635b7febac7ffca77b763c021cc4 assets/create/models/item/dark_scoria_cobblestone_wall.json +59c87e6a439fbcbbbb254e07e7b48209ea31e40c assets/create/models/item/dark_scoria_cobblestone_wall.json f5b2995929ac9dca9857d4618660ffa7778d5618 assets/create/models/item/dark_scoria_pillar.json f06f56ffb1cd7c9a2b81c65f7796726692e5cc59 assets/create/models/item/deforester.json 2104c1276259ab67b94f3d4fe97e14b6bc6941ac assets/create/models/item/deployer.json @@ -1316,96 +1250,97 @@ f06f56ffb1cd7c9a2b81c65f7796726692e5cc59 assets/create/models/item/deforester.js a97ca9b6fc3e10a9c9409b27458a852222045e4e assets/create/models/item/diorite_bricks.json 7a28bb619d37a37ed82509d2ff395d76b4435961 assets/create/models/item/diorite_bricks_slab.json 920804b7380cca2c477d9f901e045597234246d7 assets/create/models/item/diorite_bricks_stairs.json -049f372e364e05817c99fd48fd2ce81a2a88c542 assets/create/models/item/diorite_bricks_wall.json +e266c702b136f20e9196e756bb97fb5c6f73b678 assets/create/models/item/diorite_bricks_wall.json a215bca75c32124c4cb070065967de1d56c6c57f assets/create/models/item/diorite_cobblestone.json 8950fb51aa22e78c68ae2629e7c276989451ef66 assets/create/models/item/diorite_cobblestone_slab.json 645a16dfb3619cedf2046e1d0869a27394e6460a assets/create/models/item/diorite_cobblestone_stairs.json -32ebea959ce34458ac2f5ae105f9b415ab18ae4c assets/create/models/item/diorite_cobblestone_wall.json +a589798ef8b96d6106d0b029711e205a4ef23439 assets/create/models/item/diorite_cobblestone_wall.json e0ecc0a20cf9dd54ccfc48e0041d5220b2c8316e assets/create/models/item/diorite_pillar.json 1bd32eb16dee4bbf313a8813a7f1461ea5feeffe assets/create/models/item/dolomite.json 4c5e12f1acb8c4abc24b9dd80e5cbbf3a5cbd89c assets/create/models/item/dolomite_bricks.json ebb596ce665b085e501ee2fd9a5371ce53e40553 assets/create/models/item/dolomite_bricks_slab.json 9308b10e1108023b5bc61defeed1058844cc38c8 assets/create/models/item/dolomite_bricks_stairs.json -28e57af2bb20d15842fa565d026eb156bb232aac assets/create/models/item/dolomite_bricks_wall.json +ea4f4b85827c0bc8034bb6524236eb0ce6310766 assets/create/models/item/dolomite_bricks_wall.json 8d03066b5fd36bdf017fcb54336cf64294f968cc assets/create/models/item/dolomite_cobblestone.json f92bc71df40567367d08798a6ea45e7e8d0b07b0 assets/create/models/item/dolomite_cobblestone_slab.json be7de1e1529fb2a2e842204136520a760676d4e9 assets/create/models/item/dolomite_cobblestone_stairs.json -7565caff23f608f48bd1d9cb1704553b258eba0e assets/create/models/item/dolomite_cobblestone_wall.json +6b03f2be8fa1e62a89d59859e7d40f9e45ab8b65 assets/create/models/item/dolomite_cobblestone_wall.json e974cd23a5456baef8b634f2d21fd8c3822931ab assets/create/models/item/dolomite_pillar.json -4b2af721dccfcf4e5b5a7b0f64f295d7cfd27f69 assets/create/models/item/dough.json -5c45bf31bc4b6d2c6482318f19a660ad949d796b assets/create/models/item/electron_tube.json +82b73fafdb8bf4f0706012d5baab44cd0e1aa7bc assets/create/models/item/dough.json +36139f3de5fc9e57cb96f2d2daad108bc0635b7b assets/create/models/item/electron_tube.json 971be8e52e8dfef50c8329be83f9c5d5ea869279 assets/create/models/item/empty_blaze_burner.json -5312db341e777c79feeaec99e5cb85bb99bb76ff assets/create/models/item/empty_schematic.json +3bbf9f6b33ef075fb2e1d20d58a6169e2e942314 assets/create/models/item/empty_schematic.json cf34fd7e891a131d763126aa070d5b919e304a51 assets/create/models/item/encased_chain_drive.json 250bd0716cc1f04b03892ab74eb0b3a0f32a6158 assets/create/models/item/encased_fan.json 68833e2a7836c73776551565783a1d175b715c66 assets/create/models/item/extendo_grip.json efcbd30ad7a7658c02a3dc3de5fa0f21d7f49b54 assets/create/models/item/fancy_andesite_bricks.json 7ccd312084128c356307c7ca6e52c65d0a18907b assets/create/models/item/fancy_andesite_bricks_slab.json c8eee9d8df7af227eba051e4b9a7e48a79e682df assets/create/models/item/fancy_andesite_bricks_stairs.json -fa5f2e2b439f5ad116bd13c423b36646cc6669f9 assets/create/models/item/fancy_andesite_bricks_wall.json +959d5f3d6d93b46534a3a5c979daacdf0e325612 assets/create/models/item/fancy_andesite_bricks_wall.json 8794524183309b8185476bcd419fb9a59a879d04 assets/create/models/item/fancy_dark_scoria_bricks.json 7ba01ba3cb1215433b4373d6d5de1b9ba0fd78f9 assets/create/models/item/fancy_dark_scoria_bricks_slab.json d39b008a22a2fbefd509e65eb5165f8a732dc557 assets/create/models/item/fancy_dark_scoria_bricks_stairs.json -9e77a607e9e017d405b5bb4d860fe14705fd7d24 assets/create/models/item/fancy_dark_scoria_bricks_wall.json +a091529129511de51b0c55063a16d61d42dc1b6b assets/create/models/item/fancy_dark_scoria_bricks_wall.json 97b8c3e3125dcb6cfb2ddc55544605caed3baa05 assets/create/models/item/fancy_diorite_bricks.json 2a6ef7a830f95b480d8e36bbafa2d69419688c6f assets/create/models/item/fancy_diorite_bricks_slab.json 38c07a01059d2471f9fe099d0213b06132c67d0b assets/create/models/item/fancy_diorite_bricks_stairs.json -790740325b6cf2afabbfcadc50e1b59922b4fc00 assets/create/models/item/fancy_diorite_bricks_wall.json +e7a8c9d008539dc05e6f26df48ddd2008ea91399 assets/create/models/item/fancy_diorite_bricks_wall.json 84a475673d8719b14aad1ffa4b960c3915461990 assets/create/models/item/fancy_dolomite_bricks.json f3f8e870b2368386f006dadd149227d4c4045c2b assets/create/models/item/fancy_dolomite_bricks_slab.json 098130c5b60997962ff49220f8f0a918f0dfc277 assets/create/models/item/fancy_dolomite_bricks_stairs.json -1de0516db45572c9560c416efa520f4a6cad2ad1 assets/create/models/item/fancy_dolomite_bricks_wall.json +7d27e7419de18c68695cf1c5444414fa80f6026c assets/create/models/item/fancy_dolomite_bricks_wall.json e4d4aec87e5df25cc32209686fcae439fb47e3cf assets/create/models/item/fancy_gabbro_bricks.json 5842bd64fb9ce5a7893f32d86c1e7d0e52dec9ad assets/create/models/item/fancy_gabbro_bricks_slab.json 21ae57bca0821dc3df192377cfdc9b11de076864 assets/create/models/item/fancy_gabbro_bricks_stairs.json -e7e9b456961bde40122d626f6ed3229b8ea0ac2e assets/create/models/item/fancy_gabbro_bricks_wall.json +f4802b85cca42bb3436a871ce9bb9bbdb80da454 assets/create/models/item/fancy_gabbro_bricks_wall.json fd66acae47031df3de863691d81ed333cf98503e assets/create/models/item/fancy_granite_bricks.json f4ab29d669c73651503188b8918fa6926d55f1b0 assets/create/models/item/fancy_granite_bricks_slab.json 668555d15f65972fb8b74a469f625e85b99325a3 assets/create/models/item/fancy_granite_bricks_stairs.json -08f4cf9e002dcbef813e88b997c0ba0c387c4cdf assets/create/models/item/fancy_granite_bricks_wall.json +7c778e27c8c48e376954018b5ce0f968aa760e1f assets/create/models/item/fancy_granite_bricks_wall.json 86af2a7d8e88189a86aa21e217006cb111f71173 assets/create/models/item/fancy_limestone_bricks.json dd122445c8ad8cf65c07a649657ff7341e5aec7c assets/create/models/item/fancy_limestone_bricks_slab.json 5321d0726707859b9a920a6decac2c19f28f97ae assets/create/models/item/fancy_limestone_bricks_stairs.json -b0a52afe2b0b1e892ede5fdbf1c72644870f7220 assets/create/models/item/fancy_limestone_bricks_wall.json +68ff3084a8d3efdac209e3ce05d3f52853c689ae assets/create/models/item/fancy_limestone_bricks_wall.json bcd872f7eeba6512de5c070038fa2e0dc5c54d11 assets/create/models/item/fancy_scoria_bricks.json 3bcf2f856e7c6865a6849c738a7b9eb0b6a9e640 assets/create/models/item/fancy_scoria_bricks_slab.json 37df452fb88f4912e1287d0ec1f699465941b670 assets/create/models/item/fancy_scoria_bricks_stairs.json -fcb036f9bd424152670acb324cc38069426c005e assets/create/models/item/fancy_scoria_bricks_wall.json +ce6ee1fe4a92e26af75c2eaebd5055efdbdff169 assets/create/models/item/fancy_scoria_bricks_wall.json 9b32f3a1144b2e3a85ae416b5ef2d6b6df214eba assets/create/models/item/fancy_weathered_limestone_bricks.json 8fc219b471382cf67d2271edda14d173d40ae661 assets/create/models/item/fancy_weathered_limestone_bricks_slab.json 7c1ed1241d55b105f7acb997d7c0e24b4b945293 assets/create/models/item/fancy_weathered_limestone_bricks_stairs.json -2be26b4e13f5388f92834d390c2819e902efe781 assets/create/models/item/fancy_weathered_limestone_bricks_wall.json +7bdb3d8a59586654df0c2a84d73a346b898d247b assets/create/models/item/fancy_weathered_limestone_bricks_wall.json e5e6fb6eb182b85b977e1025a7fe84d46de59320 assets/create/models/item/fluid_pipe.json e7d2097256fed545064a37d233e7b810b04c26a4 assets/create/models/item/fluid_tank.json f4727119b75ab632c3ad295be4d398b1919d782f assets/create/models/item/fluid_valve.json 8707332c0cb6ee123e7962d08536a60725c64ce8 assets/create/models/item/flywheel.json -f2496d3b16e5b5415474bcfb7d6c6a6c3b28ed60 assets/create/models/item/framed_glass.json +d62b93d3c274d280f3eec22a28b5175943411d25 assets/create/models/item/framed_glass.json 1041d462c6e856f7f3f2365c299c0599703d1ed7 assets/create/models/item/framed_glass_pane.json 0bee2855dc9bad52e941153b87e9c35797c246ee assets/create/models/item/furnace_engine.json -a703b16625ad9d3b9042b6b19fdb88407726898b assets/create/models/item/furnace_minecart_contraption.json +090edb6a728fc3803e870d647c7c4e826faadca0 assets/create/models/item/furnace_minecart_contraption.json 2c1608c114ccc285a84e936dc3f1233c535e1a26 assets/create/models/item/gabbro.json c35900cae8508c292a73239e560cebae17980f96 assets/create/models/item/gabbro_bricks.json b10971277417369f421324b28f0a4b47ce4c8625 assets/create/models/item/gabbro_bricks_slab.json 0b86a2f3ec25fff558429823c6919a5ba081e10b assets/create/models/item/gabbro_bricks_stairs.json -0def0207c101a2d351ec806f42f0cb050aff1c06 assets/create/models/item/gabbro_bricks_wall.json +1b234807907063bfe393382ed066d7c59b694d59 assets/create/models/item/gabbro_bricks_wall.json 307ad613fd2cd964544ea742ad32b4c48edebd09 assets/create/models/item/gabbro_cobblestone.json 61e46397848c551a34f941f31685e3c0a20533bb assets/create/models/item/gabbro_cobblestone_slab.json b3d7398dbc16c450928bd76b772c273382687447 assets/create/models/item/gabbro_cobblestone_stairs.json -4865abd6c7a8140ea7338a545b68d4965d654347 assets/create/models/item/gabbro_cobblestone_wall.json +5680f24b43838cb6632bfcedba282a244bd24db0 assets/create/models/item/gabbro_cobblestone_wall.json 20950b692eecfccd77d96678bb3d909d51f6d787 assets/create/models/item/gabbro_pillar.json -b10f1b188f2bf380628377bd42af2b8f8ffe5611 assets/create/models/item/gantry_pinion.json +a642f570ec8223c066e542f062aff3b7f93e002b assets/create/models/item/gantry_carriage.json b4bfd5041b62f3a0a955fa4872d178b590614f22 assets/create/models/item/gantry_shaft.json 6ab0d17f3d02678ed992e188ff09f6b2c00b5b03 assets/create/models/item/gearbox.json 2fe29893d74c176ea35aed73a169c13dd4ddb2a8 assets/create/models/item/gearshift.json -b8d9269a48244fbda1735aa54a11633b49051e2f assets/create/models/item/golden_sheet.json +21c3dc6a734be582c149b9d1d7da209e178ed58a assets/create/models/item/goggles.json +52108a61865dab38133b9f916496ca680ae364ea assets/create/models/item/golden_sheet.json 46d813bcb6676078347383295bb7dbda1d9dd060 assets/create/models/item/granite_bricks.json 032a31c66d3de63595d478165d54b4f562e9831d assets/create/models/item/granite_bricks_slab.json 9d7a989d644af91a4ca5985396375863cc5de6a7 assets/create/models/item/granite_bricks_stairs.json -cd45a6f8f10a9035ab714065f3b50b4d3041a2ec assets/create/models/item/granite_bricks_wall.json +335bf361c82880c2e0be255b6c79c1370ad595b7 assets/create/models/item/granite_bricks_wall.json 085345339f11023b06717a786ab33f32b3902407 assets/create/models/item/granite_cobblestone.json c1bb87fdbbefaf74e1ead186c43417a051ab3965 assets/create/models/item/granite_cobblestone_slab.json 3c5f83809f945134a861d4ea600a1708de58a422 assets/create/models/item/granite_cobblestone_stairs.json -55d1257e4ff2e505c941975f51736eb43e53860b assets/create/models/item/granite_cobblestone_wall.json +e2d8561a8048fe6144362d13478bba4825588810 assets/create/models/item/granite_cobblestone_wall.json b84a947a1b297513c85bb8d2dbbb780304c95e43 assets/create/models/item/granite_pillar.json e7daa31c1fc445d542bad476dfe1d6a8811f2070 assets/create/models/item/gray_seat.json 0f4981408b08a736ff3eb5bdf1823cd7019ae9fe assets/create/models/item/gray_valve_handle.json @@ -1414,16 +1349,17 @@ ecb9f32f62d3fa43fb226ab85adc2eb229fdfb77 assets/create/models/item/green_valve_h 398b1a7c76c7bdb6a23b1248fdce98f6d835467f assets/create/models/item/hand_crank.json cfab82a2cf7495d21778c1de9730a26afbdd523d assets/create/models/item/handheld_blockzapper.json dee43bf1a9c211a752fac2c07aeba123f7f0c914 assets/create/models/item/handheld_worldshaper.json -f0d5af58e23e2705b3ef675c30bdf85ed9567c57 assets/create/models/item/honey_bucket.json -955e8accadb47f9b360e5fd48cd959c507b00f2d assets/create/models/item/horizontal_framed_glass.json +967695ab65edb8cb19e9759425f2d12d75406122 assets/create/models/item/honey_bucket.json +31809415a3119aeda37cff6f16d2cf47f71e097f assets/create/models/item/honeyed_apple.json +e7ec65ad5be13cae5f7d60836b8df9e4a5baad56 assets/create/models/item/horizontal_framed_glass.json f0e3b2b8a553b6e61746c922c27302dabfff71b6 assets/create/models/item/horizontal_framed_glass_pane.json ff92f6a9dfb73a6ee1eaaed3279c89390ff04a80 assets/create/models/item/hose_pulley.json -d9f222e963f8f8910ca9dbc3c31842ef149f7a1f assets/create/models/item/integrated_circuit.json -9d605ce0da83a73b535bce45c107e604364e2b20 assets/create/models/item/iron_sheet.json +771d439eac70b52f593fa7381f2c48729fbdaec7 assets/create/models/item/integrated_circuit.json +d254f47bc185f2a2f01608a875aa63ed2c4ceb0f assets/create/models/item/iron_sheet.json 52e435014cb03e93411666c4799ebff206e55fc9 assets/create/models/item/item_drain.json 83fa8699318e51f838b483b40b3e897c34ed53d1 assets/create/models/item/jungle_window.json -766323f6026c3505a75db2dee2996d342370d9c2 assets/create/models/item/jungle_window_pane.json -fe89522b2bd9b4393b8afa2a97f6db4277a8a4b4 assets/create/models/item/lapis_sheet.json +34dc05da3edef554dad1cfde834773aecd861293 assets/create/models/item/jungle_window_pane.json +0c9b16c3f5f0a5f77110b3fc2467bde8c1b288b7 assets/create/models/item/lapis_sheet.json bcaaf60d9a853cce90169dabcb36d29a3ce19e18 assets/create/models/item/large_cogwheel.json 281e2b055c6eb6994ca306c8957fc80a98fb5473 assets/create/models/item/layered_andesite.json 7afeb6170b37cb464ea91be18928d21970d556d3 assets/create/models/item/layered_dark_scoria.json @@ -1445,11 +1381,11 @@ e0a1c6102acc10a36de5ae87da629dd3d676e204 assets/create/models/item/limestone.jso 1c2b99db54863eac4947824f4169e51c25d05bde assets/create/models/item/limestone_bricks.json b4bb20a01c516b350c770a5e1149de5fda474eb7 assets/create/models/item/limestone_bricks_slab.json e2445944c220ebadf7e079ba49306c98814cac29 assets/create/models/item/limestone_bricks_stairs.json -b320c238870680fce5225114e705f832a2da8a98 assets/create/models/item/limestone_bricks_wall.json +f2a1a2cc4bbe48c2b1c77e0eb5ab0322b1ec9881 assets/create/models/item/limestone_bricks_wall.json 58234b12ce29574c89bcbd558e467691fd9be267 assets/create/models/item/limestone_cobblestone.json c26a0887356e9e55a0bdc3d885838e4722e0c0c2 assets/create/models/item/limestone_cobblestone_slab.json ebdf23b99b7895e347c29057c8070a6e16e56beb assets/create/models/item/limestone_cobblestone_stairs.json -288da8b29a4e9d0d0b694567a61b5a816a2859b8 assets/create/models/item/limestone_cobblestone_wall.json +8cd46904fd9709377d514e0faf9150ca317f6a9f assets/create/models/item/limestone_cobblestone_wall.json 8065de871ad2fbaed711735561b8ed91a2ce0004 assets/create/models/item/limestone_pillar.json d245aa4994ff197b1ffeb7980d05f96bd20cdeb3 assets/create/models/item/linear_chassis.json d912be3e87f2beaa8e22747f867739139667241b assets/create/models/item/magenta_seat.json @@ -1467,8 +1403,8 @@ f8d0d4b2a890ea7a69ab0c390947b48fe0478d3f assets/create/models/item/mechanical_pi 3fc1fcb2016d2782c3667c21575423122b66705a assets/create/models/item/mechanical_saw.json 3afa723a8ba4160a4bd8778a56e1880e7ff53ed9 assets/create/models/item/metal_bracket.json 0eb5726c8c0de462f432411c210d6132b2c446a4 assets/create/models/item/millstone.json -363c5a2b8ac945b676c838cdf7b0494c3ab13599 assets/create/models/item/minecart_contraption.json -01e3fda31e549a3b6a1e5e615b59478e8f06f16a assets/create/models/item/minecart_coupling.json +1134bc8ecdfefe5d30ee4973c37aa9a349c368b4 assets/create/models/item/minecart_contraption.json +5f44acb8a784611c17913ddf64fb4098b3a8aee9 assets/create/models/item/minecart_coupling.json dc43c88dc8ae1f425e1c10f422b09d97719af5bc assets/create/models/item/mossy_andesite.json 4ce9aabf9fa9e9e6af6b4339291e635708bdbcdf assets/create/models/item/mossy_dark_scoria.json d084f03d068d0b8c3b7c4d00014c168f61836770 assets/create/models/item/mossy_diorite.json @@ -1483,7 +1419,7 @@ b5c73d353fbe1d073f6a2901f221f178b858e385 assets/create/models/item/natural_scori bafe601f186e868819da3d29f7be7dc96f9ba790 assets/create/models/item/nixie_tube.json 366a60447bbbd61eb25aecf191a01e8d9417ad61 assets/create/models/item/nozzle.json 7a336a340f3e4927d7a35f9d79e8a03693b802aa assets/create/models/item/oak_window.json -d0a6219860420f910300e86cbec1b08d4b47f436 assets/create/models/item/oak_window_pane.json +f274fe391ac584656c9817a5650b1c1e38e44c58 assets/create/models/item/oak_window_pane.json 25dfcc8b6f085722f6b2a0c686b77d437e61542e assets/create/models/item/orange_seat.json 62ac36250e2505f23ea4d2c3b4630239c049f276 assets/create/models/item/orange_valve_handle.json 0ffe242e3165d9a0e3fe16ad4c4ca91c7e9828b2 assets/create/models/item/ornate_iron_window.json @@ -1500,107 +1436,107 @@ a64a649428a2e130059f3f1f8de81b907621589f assets/create/models/item/overgrown_sco 014530344c8b7e53531e3c09095b6ed4839d5ab8 assets/create/models/item/paved_andesite.json bd81aa53b83c2f9683c024989d0305807cf28f5a assets/create/models/item/paved_andesite_slab.json c61f409eb1a24cf76017b677579cb0423a1951c6 assets/create/models/item/paved_andesite_stairs.json -2d34a7fc24f4204a840fc3ea23bd1c9c7d833c6f assets/create/models/item/paved_andesite_wall.json +e4b6edfe2be4af6bd9324ad5ba66d2fc0b93ff45 assets/create/models/item/paved_andesite_wall.json 1e2eba674fed91fe83e55bc8cb3310c8c0ce5a01 assets/create/models/item/paved_dark_scoria.json 2150e84cd4d14e97ef7a0976a01089195a682a6c assets/create/models/item/paved_dark_scoria_slab.json 9e63939b6eb8d9b2e77bbc2258ca20de27322e18 assets/create/models/item/paved_dark_scoria_stairs.json -66058a289970d5275973ac0fa2bccbe4bb6d3c87 assets/create/models/item/paved_dark_scoria_wall.json +c0fb691421c1eac99c0e22abcd9a753673825ddc assets/create/models/item/paved_dark_scoria_wall.json 134fb828fb2f4d0d5de6b2cefbe406766c42da2a assets/create/models/item/paved_diorite.json 085769d715a8f27341915a7df1713428090d918a assets/create/models/item/paved_diorite_slab.json ad0b1dedcc63c77271804b8af6cd0e9594b28558 assets/create/models/item/paved_diorite_stairs.json -bc93e2eb2aa83f5c41c53454392d0417492d7547 assets/create/models/item/paved_diorite_wall.json +9b6db6994f16d4e0d327716004663068ddd5e5de assets/create/models/item/paved_diorite_wall.json 326e2cd1f8d3d5ea46ea915dcae30f4f6fbbce72 assets/create/models/item/paved_dolomite.json 7b7ade8c8fffbcda014c415831298ba8726e01ee assets/create/models/item/paved_dolomite_slab.json adca0341816b1d9d691d1bfcc0495bd15d5ebdeb assets/create/models/item/paved_dolomite_stairs.json -cc13a426ad0ed2f8f7d898e590bec98fac432e16 assets/create/models/item/paved_dolomite_wall.json +9e7c423ca9c27f84cbbb352ff950dc1dd57b1bd6 assets/create/models/item/paved_dolomite_wall.json 5aa6212b6b351de46befbe00767953fde8a45c9b assets/create/models/item/paved_gabbro.json 5311533b6285592fe6307c6538ffd3a01235643a assets/create/models/item/paved_gabbro_slab.json 6b2d1f94720eac18bb8e42634692a7984649470e assets/create/models/item/paved_gabbro_stairs.json -c24fd6905652045a26c3a0d15e33d7c7aad1107e assets/create/models/item/paved_gabbro_wall.json +d442e64d7c147ecfdde1b0d851be7ad93b3e478a assets/create/models/item/paved_gabbro_wall.json af3ec306551a5de6dc7ff53cb734fff656de805d assets/create/models/item/paved_granite.json d231c92be80f3897a944709a0d7745943b250930 assets/create/models/item/paved_granite_slab.json a2d3f2188637b329d62450485f2fd35cc1f2c7e0 assets/create/models/item/paved_granite_stairs.json -d23eb87b4bdb40eaa74294242e87d0123cb56dfc assets/create/models/item/paved_granite_wall.json +a72d76045cffeefcb490be6b6e8c667ebc1a8d93 assets/create/models/item/paved_granite_wall.json d60c4fb6e0e68d8f6c137a0c601145c342236c18 assets/create/models/item/paved_limestone.json 25d090c53a7ce13b08be2dfb741cc1cead225498 assets/create/models/item/paved_limestone_slab.json 0eb5aee18a1f4bf64bae7d777f5521cd6ae2dd2e assets/create/models/item/paved_limestone_stairs.json -0618e54f9ac95c8921f93025111d801c809e7043 assets/create/models/item/paved_limestone_wall.json +50edbd411b8998088d5b1e35fece468ad6c95ca5 assets/create/models/item/paved_limestone_wall.json 577490fcf3c1247d2cfc44b3595a704166c8de27 assets/create/models/item/paved_scoria.json 1a31883ef9c3a178d5682e45a9d91deacf60abf0 assets/create/models/item/paved_scoria_slab.json 8fe179c54c4f3dc24736f66889c971b5876448b5 assets/create/models/item/paved_scoria_stairs.json -484bcc00367dceb1c6f090f54f41c08b43b4e170 assets/create/models/item/paved_scoria_wall.json +65f1999459e25bb9f91b3da987184da8f1ec6de2 assets/create/models/item/paved_scoria_wall.json 2040945217d8c3077745812de07ce7444d4904e5 assets/create/models/item/paved_weathered_limestone.json 5ec22c676e301a7004ff7d127d20b46f49063c64 assets/create/models/item/paved_weathered_limestone_slab.json d81f85aea5e683539a0f3c805c154b76a9d88a9d assets/create/models/item/paved_weathered_limestone_stairs.json -910eaf2f571bae883b888d13f305bd848d278577 assets/create/models/item/paved_weathered_limestone_wall.json +25eaccadfbabb60301f487807b0e839d525f2c80 assets/create/models/item/paved_weathered_limestone_wall.json 9664f171c7856661776c5c4ef0b6880a77db648e assets/create/models/item/pink_seat.json 7d12cc24b86fcb3f0ca6fee650d1dee683859c0d assets/create/models/item/pink_valve_handle.json 04ce23dc141bedccc75b4512263da8b498f13205 assets/create/models/item/piston_extension_pole.json 1f7846aa06c3c22614c98cbec9112cc8632fa1b8 assets/create/models/item/polished_dark_scoria.json c46f1191cfa225fa76973208646e7bd86d7fcb5f assets/create/models/item/polished_dark_scoria_slab.json db8c0604529f47f7ef50c5a91ec3eab112a649a0 assets/create/models/item/polished_dark_scoria_stairs.json -c7beae7e25d3da7768a9144684e6089a22af8e28 assets/create/models/item/polished_dark_scoria_wall.json +05327514f1059450bb51cdebd7811100ec5ea430 assets/create/models/item/polished_dark_scoria_wall.json c9e6ec5d6313e159c751d4f7eee1a1a543e74188 assets/create/models/item/polished_dolomite.json 68db13895c1a4017b036bc839bf4b4d83a4557d3 assets/create/models/item/polished_dolomite_slab.json 07aefeacec36467872e34b14ec4e1a56474decc5 assets/create/models/item/polished_dolomite_stairs.json -91eb573870e26f66bb3a1ace3b21e108dbaf2a8e assets/create/models/item/polished_dolomite_wall.json +2a9597d0831b7cc9e50a1a0590f07fb0c1845158 assets/create/models/item/polished_dolomite_wall.json bf2dd5b0f0bd6579ae6d8e07d81cb418679bf613 assets/create/models/item/polished_gabbro.json c65246c4e2a738b7049edf208325482925932315 assets/create/models/item/polished_gabbro_slab.json 183e007e97155fae8dfd897d2f56bde07e915908 assets/create/models/item/polished_gabbro_stairs.json -b750f063dbf91429101a9f82ba68a60c6089dcc7 assets/create/models/item/polished_gabbro_wall.json +cee4881472e679583d4ab8c2b3d21280093926af assets/create/models/item/polished_gabbro_wall.json 3ee599a9b8e46e5b6f759eace8d1dca3b3d065f5 assets/create/models/item/polished_limestone.json 6c899db964025a4e61245063ba2b917c5e14e5c0 assets/create/models/item/polished_limestone_slab.json 7b7e357c0d9abd524d267b197c3c7c8a031da493 assets/create/models/item/polished_limestone_stairs.json -c8fca98a07ed0cb03cf195c0fdde0f7671f70bd1 assets/create/models/item/polished_limestone_wall.json -06a29cabc9def019ad5fc663f64bfaba0eed81ad assets/create/models/item/polished_rose_quartz.json +64119ad6c26e988b3c0886e572b3a6cd16617d8e assets/create/models/item/polished_limestone_wall.json +c2cf33c3b01db2403193c0f187e90d0268d7e82d assets/create/models/item/polished_rose_quartz.json 7f4ada06f5fc6647e6ba7fe3195efc116bfb2189 assets/create/models/item/polished_scoria.json 143139799880ed94c0b41bacfe3dc0a821d96c49 assets/create/models/item/polished_scoria_slab.json e95125318055b8557afd7d108488cf0bdd81fe49 assets/create/models/item/polished_scoria_stairs.json -4d2da954c66883cd1e41f8c06e1af9c21a11fd12 assets/create/models/item/polished_scoria_wall.json +2ccb8f2eda89345221ec2a103702ee54de1a3b96 assets/create/models/item/polished_scoria_wall.json 8197d4494ff1d8d81be8fac9285246cc1c6bcf54 assets/create/models/item/polished_weathered_limestone.json 68fb04f7a89c8117bb641e347df9bfc1f1248335 assets/create/models/item/polished_weathered_limestone_slab.json 6d92ee7112aa20e8a1adfe73d8933031c299bed1 assets/create/models/item/polished_weathered_limestone_stairs.json -d98a1d479dff88d7a6f084f2c9de8fbbf80961ef assets/create/models/item/polished_weathered_limestone_wall.json +b4995fb4799f33508cd6bf2ded80c0b3e866ad43 assets/create/models/item/polished_weathered_limestone_wall.json 0e5638cdbf04d7af2222ec15fbe1d960385ea237 assets/create/models/item/portable_fluid_interface.json 3bc60b0d9884c2ee0f1dd530e90fceb699eea737 assets/create/models/item/portable_storage_interface.json -417c301eb7e54f14c564975570f59d048cc88987 assets/create/models/item/powdered_obsidian.json +d3cfc1a1137c4bc98848947d425d2972df144c95 assets/create/models/item/powdered_obsidian.json 1e501c1f2e9250aaaadcf17db62646d08177d4e1 assets/create/models/item/powered_latch.json 3a6dfc7f36e31ebfcd650c3144a7f2210e8a4f9f assets/create/models/item/powered_toggle_latch.json -4a3c3d81097d56bbd3aefeeb9eb7db87f514b5b4 assets/create/models/item/propeller.json +16f363038d5afeae34e0724a6a9f0b8f6e65424a assets/create/models/item/propeller.json 4b8a27ff05ed5331889dfc4b0b4562f3e94b0dfe assets/create/models/item/pulse_repeater.json a598b2f5eb34b061e81efb8a55267a02f8e08a61 assets/create/models/item/purple_seat.json e5138f9e37ca4d24cda2eb7b24a021eb7c8ae21c assets/create/models/item/purple_valve_handle.json -efbda15b53084acdac2d36b8e0a764a9ab34d723 assets/create/models/item/radial_chassis.json -fc05c4492da3d17add7e410323a47456c0d21e0e assets/create/models/item/red_sand_paper.json +469652eb5baa92008dbfc4deec232c3381684af6 assets/create/models/item/radial_chassis.json +ba99e2fdb64892f4f479a8ac51c226cb5f71f659 assets/create/models/item/red_sand_paper.json 3e251514aa698076b73fdbfef720b78b21d3bd93 assets/create/models/item/red_seat.json b959a1b35105c2c21933418bd29ce12a090716f8 assets/create/models/item/red_valve_handle.json b9a4ac219a27e60a82f55129f2df5ae6183981e2 assets/create/models/item/redstone_contact.json 52e561abeb954d0349e640566de92ef80ccbf919 assets/create/models/item/redstone_link.json -81c7f4381cbda69aebcb07700cb998f49c38c8c1 assets/create/models/item/refined_radiance.json +d9dd4546f4f4c6ed5fef66de9d272d469db4e81f assets/create/models/item/refined_radiance.json ef52b3734a47e96c5f83d60da73110e925737933 assets/create/models/item/refined_radiance_casing.json 901f7ad587dd07c9494d95bf7f08f93bb20db774 assets/create/models/item/reinforced_rail.json 6daff6b82b33374d7add65e352e05ecb2fd9ebdd assets/create/models/item/rope_pulley.json -0817505d2d3ee516424100b985ca3fe2d2e7f01e assets/create/models/item/rose_quartz.json +fc54acc37695f21ef650c8310110407647e9a023 assets/create/models/item/rose_quartz.json acfbf487ee65c2c58d89cb2644e33fda75751fde assets/create/models/item/rotation_speed_controller.json 171c343f7f536008f79ea1d63e0a443d064e9ef1 assets/create/models/item/sail_frame.json -5fa0bfe8642e2614a7e97d27af1a95dd2e012097 assets/create/models/item/sand_paper.json -3202829de06e9c532dc8a61c955458648b70d645 assets/create/models/item/schematic.json -3f07bc7d4587d78de463ae2ce236e4f363b923cd assets/create/models/item/schematic_and_quill.json +be86c8156d55d2f128feb66abd70923b3be765cc assets/create/models/item/sand_paper.json +69196df5122a27573112dad49b334dea96aafed0 assets/create/models/item/schematic.json +533483999f61e3b091af567a473875247edaedb3 assets/create/models/item/schematic_and_quill.json 8dd5caa4d7a0ee45bd9b39e09c4503159933d089 assets/create/models/item/schematic_table.json 0a1c4080ca572106c19a0ba6e2df4baba5f45d35 assets/create/models/item/schematicannon.json 22a6dfdc3cbb1b6ac20ec123b490e15c72dfbfcf assets/create/models/item/scoria.json 44a99d0a4ec37dd33ea184e0f4b4bd54289eb19f assets/create/models/item/scoria_bricks.json 403c205f6f253b26287fd4479a1ff4ead3a2c229 assets/create/models/item/scoria_bricks_slab.json 74125ed1dff40e71c796b80ddfff7bfab57c33ae assets/create/models/item/scoria_bricks_stairs.json -4457fd21744229c45678e58ec4f511f2eed363af assets/create/models/item/scoria_bricks_wall.json +845527eaba40dc65c609ea092f5b8a5c685f730a assets/create/models/item/scoria_bricks_wall.json ff235540c1632a34751bd76e66b2a517f7cbfae9 assets/create/models/item/scoria_cobblestone.json f4107d5e5a573810873e1a52aaacda674d371e1b assets/create/models/item/scoria_cobblestone_slab.json fe8c7476b1386fc05a57a93319f71455ba4cf29b assets/create/models/item/scoria_cobblestone_stairs.json -9bd8d8ad10aee5b411d69d8ec9d65c479179876a assets/create/models/item/scoria_cobblestone_wall.json +b0061419cf7b7bd2dd548ff00ee28f1227ee2663 assets/create/models/item/scoria_cobblestone_wall.json 1f0cfa084107c05b010556f609371285295a0d12 assets/create/models/item/scoria_pillar.json 083b9fc316cef1d24ea20f06a6aaa4cb52f1ef94 assets/create/models/item/secondary_linear_chassis.json 0df94333da5700f01dcf4ffa46e3f3bf26bb8cf7 assets/create/models/item/sequenced_gearshift.json -8d114060ee1b55dc4bd9edaf2c5b55999c535b35 assets/create/models/item/shadow_steel.json +da72ccdc893fbdd3efa9c22143b88eb756c20e44 assets/create/models/item/shadow_steel.json 081326d6666cfcfe34c45c1b74bfceba0b01ae6e assets/create/models/item/shadow_steel_casing.json 106ae694f7e03a218c37003dca8291b1d39b3c55 assets/create/models/item/shaft.json 0f6bc6a4328ef317d50903c7b50ab5f78fce37eb assets/create/models/item/smart_chute.json @@ -1608,34 +1544,34 @@ fe8c7476b1386fc05a57a93319f71455ba4cf29b assets/create/models/item/scoria_cobble d6fb0d38b1b5bcc199b52ac8889eaecd167f6725 assets/create/models/item/speedometer.json b9abe1331d49871838231f3a8e5d2973634e9325 assets/create/models/item/spout.json b305e81f1dc5272634745b6e822af40955a2ef28 assets/create/models/item/spruce_window.json -f3ec8df2ee1690353ae1ec687b822d0fd962160e assets/create/models/item/spruce_window_pane.json +5f622bca8386b8dd077310647e39ac3abb80c6a1 assets/create/models/item/spruce_window_pane.json +bb546e5342c6d1a6b4040cf7ccdd2f10c6f79965 assets/create/models/item/sticker.json 891abc24593d53d282773eca5534065056d89b4c assets/create/models/item/sticky_mechanical_piston.json bbb5773adc23128c70174bfc531af936e6e063e3 assets/create/models/item/stockpile_switch.json bab8f78c319b2a79ed55c5d2a94b521ddaa44996 assets/create/models/item/stressometer.json -67cbfc1413ad5201f462c618a8fc6265edb3b8ad assets/create/models/item/super_glue.json +29d571a061e3addf92ee51bfc55d96edc3a517a5 assets/create/models/item/super_glue.json +9be61d209d2219ca00d35de7cd57c2c87b297379 assets/create/models/item/sweet_roll.json b1d3d00ff05908feacad06a86800da96cc9bc65d assets/create/models/item/tiled_glass.json -a7d0b746637897209bd86b1a6501ecbfb46d8270 assets/create/models/item/tiled_glass_pane.json -f8a4fa1ccecb16a3941cc46db7481ed8e8429a5e assets/create/models/item/tree_fertilizer.json +8a2a81a8cbc52b6021e57107d79a32f73b82d8fe assets/create/models/item/tiled_glass_pane.json +c081317f106a2b04700aafde12c57445844c20ab assets/create/models/item/tree_fertilizer.json fb24881c4e92bbb7ffa54a71e0af6b1c66d84829 assets/create/models/item/turntable.json -2a6be52ddedd614dc3b8a6b659bfbd7a4be54252 assets/create/models/item/vertical_framed_glass.json +32f49b724af10c8d7e2ed5a3c82280e83b75f789 assets/create/models/item/vertical_framed_glass.json 5e331da9d4086412f5722923e3008246ed286a00 assets/create/models/item/vertical_framed_glass_pane.json 00c2929de9b7171656bea74e1a6d694c6a45b075 assets/create/models/item/vertical_gearbox.json 2d4a31321cc13f62f5fd73aabdc5fd97e635bfbc assets/create/models/item/wand_of_symmetry.json -89493fa0691453d6c604e3ed9ae077fe43648d18 assets/create/models/item/warped_window.json -5f169d526b4697c85e6d113be4ff81a2b45b6e6a assets/create/models/item/warped_window_pane.json ae20383b0b0806431d0fdd8ffdd16fe2b0cc61ad assets/create/models/item/water_wheel.json 1d097a315c2817d16c241c86f66bd48e5e52f4b4 assets/create/models/item/weathered_limestone.json fcc8ab312989ec485e2d86b856d81dbafaf0e930 assets/create/models/item/weathered_limestone_bricks.json 7e7abcb63aa5fc0dee50e116c93f8544768d4d95 assets/create/models/item/weathered_limestone_bricks_slab.json def7382f3216c59d835ab64f534678f3d31ecc51 assets/create/models/item/weathered_limestone_bricks_stairs.json -f2cd30c585a25e336868ee4f8dd80799ecb986c6 assets/create/models/item/weathered_limestone_bricks_wall.json +8b96d6b4be585890211269018ab3814a32f17618 assets/create/models/item/weathered_limestone_bricks_wall.json 015479be1e6b8de4af6c14cc0e9ced5b6e7c1b07 assets/create/models/item/weathered_limestone_cobblestone.json 377fffa39af11eb195b73310efd4b53b8c618c92 assets/create/models/item/weathered_limestone_cobblestone_slab.json 3d26cb5616182ba6926d0bf703119ebfbeacbe31 assets/create/models/item/weathered_limestone_cobblestone_stairs.json -ea1d735b557a71bbb2b35e5f03ba571d54c38dbe assets/create/models/item/weathered_limestone_cobblestone_wall.json +62cba55cef305e8fcbc545363919f75d702a617b assets/create/models/item/weathered_limestone_cobblestone_wall.json 40bed7f5e9e97da45c5d9cebc3fcf87b2b13a808 assets/create/models/item/weathered_limestone_pillar.json -30c449f637e8d56b7670b81ec2a90942e2972739 assets/create/models/item/wheat_flour.json -9502a51ed2f6a110b6d41731a5948be4d70c8af8 assets/create/models/item/whisk.json +8914910270736f8f15364c623cd08d4638383cc5 assets/create/models/item/wheat_flour.json +0cc80844db689404d4722c93f1002b0bed05edcd assets/create/models/item/whisk.json c6253e0f8db3c3992d3f78fe5045e276d39d5b22 assets/create/models/item/white_sail.json 69328eb4f91c4407fbcad5e3c4b88363f1a9572c assets/create/models/item/white_seat.json be7a2d59d43083d7f2427193dcb9d68004224dd3 assets/create/models/item/white_valve_handle.json @@ -1645,82 +1581,79 @@ d080b1b25e5bc8baf5aee68691b08c7f12ece3b0 assets/create/models/item/windmill_bear 4b49bc2418410cded5f0b7da3430f1a22e049f18 assets/create/models/item/yellow_seat.json 790daf016f980801e7587b548a325082c65f6f03 assets/create/models/item/yellow_valve_handle.json 9365b5cf29e35d070d077c54520f6cc780aeb842 assets/create/models/item/zinc_block.json -866fbb0ce2878a73e0440d1caf6534c8bd7c384f assets/create/models/item/zinc_ingot.json -a80fb25a0b655e76be986b5b49fcb0f03461a1ab assets/create/models/item/zinc_nugget.json +9dfaa12884667458f8f727ae7666e7e4e50181d9 assets/create/models/item/zinc_ingot.json +9f9455ccb5fc9e3cbfce73862b46078346a522a5 assets/create/models/item/zinc_nugget.json b1689617190c05ef34bd18456b0c7ae09bb3210f assets/create/models/item/zinc_ore.json e76041b7ae829fdd7dc0524f6ca4d2f89fca51bb assets/create/sounds.json 5d0cc4c0255dc241e61c173b31ddca70c88d08e4 data/create/advancements/aesthetics.json 187921fa131b06721bfaf63f2623a28c141aae9a data/create/advancements/andesite_alloy.json 0ea2db7173b5be28b289ea7c9a6a0cf5805c60c7 data/create/advancements/andesite_casing.json -83c046bd200623933545c9e4326f782fb02c87fa data/create/advancements/arm_blaze_burner.json -b243e73ea26c5c8c8c57570d7d91a50d035653a4 data/create/advancements/arm_many_targets.json -6c16fbae3b4e74be38ca91441412a467ec21ffe2 data/create/advancements/basin.json -56e2a988aeb23421811f87cf7fe014985a70dc40 data/create/advancements/belt.json -7a551856f64bb73eacf05e4d4d2e1a539aae2c5d data/create/advancements/belt_funnel.json -66f45a9e3058f5363cde280383b094440f268963 data/create/advancements/belt_funnel_kiss.json +356f4855a2a6c65be3fb51d7d1aabf2ca6034d42 data/create/advancements/arm_blaze_burner.json +34ef8876c9c13960981bb946ff3adbf44d9a78a4 data/create/advancements/arm_many_targets.json +de37aa79135d560adf1cc5404f86761f97335314 data/create/advancements/basin.json +c7f56a4aca398eabe1c59404ebfabdc0c5e3edc0 data/create/advancements/belt.json +26ec9a0743fa7416f94b0a0551497a5e964cb5e9 data/create/advancements/belt_funnel.json +5d026fe611d4cc76e7015164da5d68e943f980b4 data/create/advancements/belt_funnel_kiss.json 057bb9f72827dd31126ed9db5aa8f63def66ef18 data/create/advancements/blaze_burner.json 1c887715949eb179553a62c6ae360741fc19eefb data/create/advancements/blaze_cake.json 5ba8eb22d8bcb3e90c7a8f84cf909d5f78b83eb9 data/create/advancements/brass.json de13a091928d5ab539d567411dd5c522cdcdd668 data/create/advancements/brass_casing.json -88adc39840259e79e46c4f33abb8eeaeb41dcdc8 data/create/advancements/chained_item_drain.json +b6a5d97765454fc66183e6afd8d7241029eec5cb data/create/advancements/chained_item_drain.json 13c848e1422dcbd0a35a559e362a3f54a12d5543 data/create/advancements/chocolate.json -0c84fe24f49330a7491016235afd8fad02b560fe data/create/advancements/chocolate_wheel.json +422a356a2794f14529cabb966386a8043bdaf218 data/create/advancements/chocolate_wheel.json 34739e1dcaddcb8e24fbd6d6d61d8d1d8a6d7413 data/create/advancements/chromatic_compound.json 9531baa67bb3aee5e2723b1ab0578ff87bcb42b0 data/create/advancements/chromatic_eob.json f37551a788dfb3ff3d65db97a03c0420edf2c041 data/create/advancements/chute.json -0ffacd497176afdb26670783b65d383ac6236c19 data/create/advancements/clockwork_bearing.json -870ca791c418a1bc24f7b12284f5788c84911b92 data/create/advancements/compact.json +6654057ac1bc9dc461fc2b895c397218f6ffb587 data/create/advancements/clockwork_bearing.json +6d57b060b0ac92d0dc4109cbe0194d5536204978 data/create/advancements/compact.json d1015e059a2f2008a364b6d045a011a6d671f20d data/create/advancements/copper_casing.json 8e2a12a26218a46665c46f350ef9c3418a901988 data/create/advancements/crafter.json d1fbc14303c7327e9fc02e505e7e434591b7f785 data/create/advancements/crushing_wheel.json -e9e1789de5cd5577a801a09d489a13f2c98779dc data/create/advancements/cuckoo.json +70de97e8601e762a7c197a49af0c3a8f96309f6d data/create/advancements/cuckoo.json 0761f3e12d587fec7a2ddf326b43969d262771e3 data/create/advancements/deforester.json 2a96fad5b44b62f233c9af5b4a637faf32ce24af data/create/advancements/deployer.json -eb8e7c13163923d2f88c999c6eb5afa4b7d2426e data/create/advancements/dual_extendo_grip.json +77edd30e3d60b4d492662c673387910f66b5a276 data/create/advancements/dual_extendo_grip.json 04eaf829696d735244c0e4798dd3bdeb26e13a32 data/create/advancements/electron_tube.json -36622ff02345cdc2404230c48de9ed42b1b9bd1d data/create/advancements/extendo_grip.json +b78fe4e539fef1b3419f2eb4d1db47cb4a201992 data/create/advancements/extendo_grip.json b1699baaadaac7ebce642c09428519d156e21594 data/create/advancements/fan.json 5aa76cba3b40a1c234ffa84a89ecca630990fc0f data/create/advancements/fan_lava.json 716a9816558300a3652ed8d8d568517017813f5c data/create/advancements/fan_smoke.json a61eb63d02604e88836519f89f74b252a640d485 data/create/advancements/fan_water.json -7e639be7a98d1d99bc2f996d817477a426ca8b61 data/create/advancements/fist_bump.json -bc65c06352607d2e2f2abb6a66bc761011e1e720 data/create/advancements/flywheel.json -380087d7c540232bb0b4a47be339dd96c3d2725b data/create/advancements/glass_pipe.json +69e96e926a4d72e59cc6390c25f064166ddb62d2 data/create/advancements/fist_bump.json +99ee1bf5390b9a4f2a2419c78f259ff5d2ab9ae9 data/create/advancements/flywheel.json +489c58a0508a2a41cc0849dfb933eb5ac96ef364 data/create/advancements/glass_pipe.json 62f3610188f7dbd3900ab305edc2d06282705a38 data/create/advancements/goggles.json -ea0f8acb7c3692b569269e62927725d968a65251 data/create/advancements/hose_pulley.json +10c8686da9cec2ae30c10f434836ac15a1b88666 data/create/advancements/hose_pulley.json 9f642faf92b75a28c564e90be8448b9a4328af5e data/create/advancements/infinite_chocolate.json a933fa5e7217e2ffe123ae035cfbc9210ba69fd5 data/create/advancements/infinite_lava.json a8ab0e4ffba358d23f9efaa9f51245b6d490a8be data/create/advancements/infinite_water.json 9beb622c79e9f5ce2397c22222cac0faf272f388 data/create/advancements/integrated_circuit.json 316bed3d8985d0a371200967d7edd2936f1b9f94 data/create/advancements/integrated_circuit_eob.json -4d7cb129877d6cd68fda66159818e47ca44db078 data/create/advancements/item_drain.json -b61d958815f1c2530c11c88c9081d5c794d7f807 data/create/advancements/its_alive.json -9d68fed495a37fc78184e43e432c3181da84d19c data/create/advancements/lava_wheel.json -786b2bdb9e552160c01e5cb748b729b3ff7f6738 data/create/advancements/maxed_windmill.json -28686d74d162dd35b9bf91da2da654d3b79e6622 data/create/advancements/mechanical_arm.json +a80eea863bfdc7777b8bade39a81655b2f99e02f data/create/advancements/item_drain.json +7e12b7ccb198ef0db7964b8cbef152d8347e333c data/create/advancements/its_alive.json +3d0fc63191ef507a018ef996ebf9406a523f3976 data/create/advancements/lava_wheel.json +82e4fee1e20713e1a3e47672410bb464dacc0023 data/create/advancements/maxed_windmill.json +03389885be3d616054d418587fd2acc202127c5c data/create/advancements/mechanical_arm.json 218568a4e416c5fa559c55a5c92aa4e93f88b837 data/create/advancements/mechanical_drill.json 6dc84ad2f0512495fe3f01f99d3c547849351e33 data/create/advancements/mechanical_saw.json 3bc549c06dc6d9568f92e1abc9654c9b4c33f035 data/create/advancements/millstone.json -ee834796d3d05d097048338ca946c5509fada0be data/create/advancements/mixer.json -bee2c19d730936e34ee61fe04af13e2b031ecffa data/create/advancements/musical_arm.json +238ac410eb4de16a82ae05cc16fef80e55a4b61b data/create/advancements/mixer.json +325d4cef263ce301b143ee0498fb15afdb2c125b data/create/advancements/musical_arm.json c9c4060ed207226b69fada2d61e01a97d7077eae data/create/advancements/nixie_tube.json -0b0a7f5b7f30ab75e4ca790c850b1eb50944a3aa data/create/advancements/overstress_flywheel.json -7f0847247a80ee930c23f551bce00bda74f81b0e data/create/advancements/overstressed.json -449eb8a9e6102bb342c96eb8b19e743eb6979bfa data/create/advancements/pipe_collision.json -4b621e5bb48fbb120853ec02c05c915d86bd6dd8 data/create/advancements/pipe_spill.json +9329cb210a954c0de1dcf517e7dff1ece77c19c0 data/create/advancements/overstress_flywheel.json +a135eec618e448f440d9f42cc7a3e6c63fc45a71 data/create/advancements/overstressed.json +b31bca0b9719040ebe769e8bf09d1978ea0bf901 data/create/advancements/pipe_collision.json +70f0e06143e24e9c1ea7ccd142b10d5cd227ab3d data/create/advancements/pipe_spill.json 72025d8bf73ab8096c29f12d0c8d9a346f09cd64 data/create/advancements/polished_rose_quartz.json -62d29ec01eff5d21968636a0479361ecdc11ae30 data/create/advancements/press.json +1e3cd82e36fd4bcd053d652a0eead4458ed7f315 data/create/advancements/press.json 5012e9d559439d0d62d0b34c2e39de048e8c7699 data/create/advancements/recipes/building_blocks/blasting/aluminum_ingot_compat_silents_mechanisms.json 2e253226c408dffb9dfb828b846f70ebd1cfb16e data/create/advancements/recipes/building_blocks/blasting/ingot_aluminum_compat_immersiveengineering.json 3f022f89aeb5034f2292ca71daa9f311e8af40ff data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_immersiveengineering.json -fb73858cc12c9898a95121407100777da70fb514 data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_mekanism.json b7232d0e659de3f227289a5275f76a5a2ec578bb data/create/advancements/recipes/building_blocks/blasting/ingot_nickel_compat_immersiveengineering.json 1f527bbe24e79f3f149c06dd8be7016eea42b4e9 data/create/advancements/recipes/building_blocks/blasting/ingot_osmium_compat_mekanism.json bf68b12cf828b64f5bb407bba6cf6ced8578327c data/create/advancements/recipes/building_blocks/blasting/ingot_silver_compat_immersiveengineering.json fc07b75f81782fa06990c7eb7febc635621df91a data/create/advancements/recipes/building_blocks/blasting/ingot_tin_compat_mekanism.json 84963b1e8eb81dd20df6a9680028f8b76fef2bae data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_immersiveengineering.json -d8edb7b810ba30aa7b5d281e283ccfd4bcc8af4f data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_mekanism.json -24c7db24ea02b66bac7de0cb508485488b755aea data/create/advancements/recipes/building_blocks/blasting/lead_ingot_compat_eidolon.json 744d8831fde05ee2598ccde10f9289512c45d55b data/create/advancements/recipes/building_blocks/blasting/lead_ingot_compat_mysticalworld.json 4ef0ac97acddee1c49a0deb402b43feb40af1dc6 data/create/advancements/recipes/building_blocks/blasting/lead_ingot_compat_silents_mechanisms.json 25c6e6736da3a529c4cfb384a2dba707f946ce22 data/create/advancements/recipes/building_blocks/blasting/lead_ingot_compat_thermal.json @@ -1743,14 +1676,11 @@ d192e3f2185ad3cd8cd64f639dd6395aaec89563 data/create/advancements/recipes/buildi 98fe15c805f1d228f1db6a2b35426ef01e9747a8 data/create/advancements/recipes/building_blocks/smelting/glass_from_vertical_framed_glass.json 43d3d2c952f54fdf73e4df422554451ceff899d3 data/create/advancements/recipes/building_blocks/smelting/ingot_aluminum_compat_immersiveengineering.json 48439dd60a0a79f0ab6accc3773a3a8b64b7396e data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_immersiveengineering.json -9dede27b23de5aeafec509a5b232fb83ef7d87fa data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_mekanism.json 7d8325768f249a1ac5d79d60eb58b6eb32c51234 data/create/advancements/recipes/building_blocks/smelting/ingot_nickel_compat_immersiveengineering.json c2a565459bc3a2b6aa1770e36295373f886b27b3 data/create/advancements/recipes/building_blocks/smelting/ingot_osmium_compat_mekanism.json d192714def52e54a58ae96f7592055e925d88bb8 data/create/advancements/recipes/building_blocks/smelting/ingot_silver_compat_immersiveengineering.json e922be59fa4cb031020041f54d06d361f090e6a8 data/create/advancements/recipes/building_blocks/smelting/ingot_tin_compat_mekanism.json 6f0b67b3f49da5c3102a48e68e6c4f834d08b0e2 data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_immersiveengineering.json -2c10ff7aea86bec54b5b84a8fa89e51aba9c771e data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_mekanism.json -ab46ab7914bd3f35b242a987fa58c90cc22a0636 data/create/advancements/recipes/building_blocks/smelting/lead_ingot_compat_eidolon.json 847dc1a0bd2275a11ff02624b98cf7fdf0d8f47b data/create/advancements/recipes/building_blocks/smelting/lead_ingot_compat_mysticalworld.json 79d5f852e9e48e9e8ff5cd42890fbc9ad29e9712 data/create/advancements/recipes/building_blocks/smelting/lead_ingot_compat_silents_mechanisms.json cdf4697b74e4a6add2ea41825733f4d9ff2b83e6 data/create/advancements/recipes/building_blocks/smelting/lead_ingot_compat_thermal.json @@ -1814,7 +1744,7 @@ b42213bffce4e51618e1bba481959208d247c120 data/create/advancements/recipes/create 11d89eca0ccb0f1a8cd27acc9fc0c10d7bf83285 data/create/advancements/recipes/create.base/crafting/kinetics/fluid_pipe.json a2b33e972c7130cbf105f34d88dd7a9a53d5465c data/create/advancements/recipes/create.base/crafting/kinetics/fluid_tank.json a91b11ae44d9b1f479c6dee1f1a4580104059287 data/create/advancements/recipes/create.base/crafting/kinetics/fluid_valve.json -e17c45fc17e1a8e1e618b6eae02fa0aba3247495 data/create/advancements/recipes/create.base/crafting/kinetics/gantry_pinion.json +b2a73fc7e0e4e764c2af400a6e093c2d78d7d37d data/create/advancements/recipes/create.base/crafting/kinetics/gantry_carriage.json d1d2fc2f5c4e89393808c65e015917eabb50dffe data/create/advancements/recipes/create.base/crafting/kinetics/gantry_shaft.json dae9e65a089955c0367dc1453e104c3153ebad79 data/create/advancements/recipes/create.base/crafting/kinetics/gearbox.json 8f9819912605cb2499cb3e79ecb0e709b0e38c19 data/create/advancements/recipes/create.base/crafting/kinetics/gearboxfrom_conversion.json @@ -1888,6 +1818,7 @@ cd8cefee21a1690f9158b8e8661a92d20ad0f535 data/create/advancements/recipes/create e8a5d924ccf30b6eae4b9ec0a8040e31f0eb165b data/create/advancements/recipes/create.base/crafting/kinetics/speedometer.json 90ff137eb1533695d9d17296ed180c0a88ddd891 data/create/advancements/recipes/create.base/crafting/kinetics/speedometerfrom_conversion.json 44867af16ec6d960268747effcd578ab55e3a366 data/create/advancements/recipes/create.base/crafting/kinetics/spout.json +8c7fd72b8b4d414a61859dd08857e8538d84f88b data/create/advancements/recipes/create.base/crafting/kinetics/sticker.json 3859abc8839e92b01461d3e9ef853a4934c3256b data/create/advancements/recipes/create.base/crafting/kinetics/sticky_mechanical_piston.json 9a4dad31370d9e71308afe5c3f9349b67f749635 data/create/advancements/recipes/create.base/crafting/kinetics/stressometerfrom_conversion.json f3fc3d4fee0712906f833aa17185f0bacb21922f data/create/advancements/recipes/create.base/crafting/kinetics/super_glue.json @@ -1981,8 +1912,6 @@ c31a4d1eacc892a0248315270a12c0b49f5edc63 data/create/advancements/recipes/create b873bd961cd865866a6f5035bee583a400073a3c data/create/advancements/recipes/create.palettes/chiseled_scoria_from_scoria_stonecutting.json 0ace6bef40eab8e365959e529a16cd04d15adfe6 data/create/advancements/recipes/create.palettes/chiseled_weathered_limestone_from_weathered_limestone_stonecutting.json b4651c8202331483e82b28b04edc6cd97e62ad1d data/create/advancements/recipes/create.palettes/crafting/palettes/dark_scoria.json -9a587cd39af620df5bf25ff0143108c6be9597f5 data/create/advancements/recipes/create.palettes/crimson_window.json -b2813566e6715c2d377dd4ef461b012cae7eb190 data/create/advancements/recipes/create.palettes/crimson_window_pane.json 25991d5667252d551e02c4fbbfa27ebf4353d28d data/create/advancements/recipes/create.palettes/dark_oak_window.json 4819383b1a7885b4401fdc25955d2c51f75b6236 data/create/advancements/recipes/create.palettes/dark_oak_window_pane.json ebd6413d530325eef6fcf42a0ee0ac840c1f7366 data/create/advancements/recipes/create.palettes/dark_scoria_bricks_from_dark_scoria_stonecutting.json @@ -2319,8 +2248,6 @@ ab0cacba05f8def9cc91b993d464c297babf6fc3 data/create/advancements/recipes/create d40c7ce6b79630ace624d17b92667286998d93bc data/create/advancements/recipes/create.palettes/tiled_glass_pane.json 24fafe59013a3e0439a73ea4e0cef114fc9a8e4b data/create/advancements/recipes/create.palettes/vertical_framed_glass_from_glass_colorless_stonecutting.json cd5ee73117872ee98434be1d24b4f271f7e94a48 data/create/advancements/recipes/create.palettes/vertical_framed_glass_pane.json -f26d1a1ee183b1b19d018fbdefc70f0bf29b41d0 data/create/advancements/recipes/create.palettes/warped_window.json -faf33c9c630eecab88bb969e3b9f7fd9e9f6ccf6 data/create/advancements/recipes/create.palettes/warped_window_pane.json ef0d351d13f7e9c633581b537c59bddc1fa4c3a4 data/create/advancements/recipes/create.palettes/weathered_limestone_bricks_from_weathered_limestone_stonecutting.json 1c931e15af3e5b5f78a0a62b8c159fdf9f0d7f3e data/create/advancements/recipes/create.palettes/weathered_limestone_bricks_slab.json bba639941526cc23570e328e0b5e2a5545667219 data/create/advancements/recipes/create.palettes/weathered_limestone_bricks_slab_from_weathered_limestone_bricks_stonecutting.json @@ -2352,22 +2279,22 @@ ea72626febe23b0c8c6e03518a9486ce94c88b12 data/create/advancements/recipes/misc/s c8a2f6594042a3205e675349ccef97873a9e91b2 data/create/advancements/recipes/transportation/crafting/kinetics/furnace_minecart_from_contraption_cart.json e35aa0e435dc3640c78c4687dd7130fe62c55ea3 data/create/advancements/recipes/transportation/crafting/kinetics/minecart_from_contraption_cart.json e0b9edc5e59647e7dd99be17369b263dadf407d4 data/create/advancements/refined_radiance.json -67edd7bd314a85a1fddc2aa9f6b2207879aa5c3e data/create/advancements/reinforced.json +5052d3b97ba0a9ef4ff82084e2720a4f46c0de13 data/create/advancements/reinforced.json fc12b590ab8f5ac901db21c67ba3850f157e1421 data/create/advancements/root.json c1f162e773518f6b1481221e3e63f9ba33fed647 data/create/advancements/shadow_steel.json -6c1a67e193a4c5af356b31a1d5b5e9d3faeca87e data/create/advancements/shifting_gears.json +290e1248254abcfd7f1e73906be25662331378ec data/create/advancements/shifting_gears.json a7d278d8ce8e2769c0b9c89f547d4775eabe671b data/create/advancements/speed_controller.json a203d509a6038f0bad707e232a425388e62e1ae1 data/create/advancements/speedometer.json -f7bb8f08a08e22ec1e6bb098d65d06233e8fbcec data/create/advancements/splitter_tunnel.json -b69d174d7a5e9eab8ca013b66bc9d02244d7f9a3 data/create/advancements/spout.json -15f73da913c54cd2f945e4d7402fb8d587cbaa9f data/create/advancements/spout_potion.json +1b95903e1883a701305bb734d54a9d3f6ba89333 data/create/advancements/splitter_tunnel.json +b9064e9796e316bcd6c4f525b5a1f5969e492476 data/create/advancements/spout.json +e8ab91b7305367bd49480a6f1bab0591051ba7b3 data/create/advancements/spout_potion.json 0efdaf483d84791044f085f79197b6bab3e15872 data/create/advancements/stressometer.json -1aceaa6e47709aa03f3d4f606fa5dcaacc899835 data/create/advancements/tunnel.json -42461143b64112fdf6f123b9fcd44b5457df3915 data/create/advancements/upgraded_zapper.json -4fef92dce84fa1a075db31fb33081f5fb8ec7e9e data/create/advancements/upward_chute.json +a015cad8d909c7b9369864368706fbb323a8f4ec data/create/advancements/tunnel.json +6b815a2e05e3cd09354e05578515a0060675b67a data/create/advancements/upgraded_zapper.json +f519522955a51998eb81e20f24a4ab86a3b57027 data/create/advancements/upward_chute.json fe37896bb804d2be9b8abf3744c5b9b7bc1c086e data/create/advancements/wand_of_symmetry.json -2c278dc6e6e4c12c0cfce22b5192844586a2d5c1 data/create/advancements/water_wheel.json -d6b94fd499cb4fb0ae587b0e9e7088832f67fe01 data/create/advancements/windmill.json +50935316d27336ef0858d5a7c5ccc563d288a494 data/create/advancements/water_wheel.json +73d63d8a06f91f3edd59a025043305f5d0d4c209 data/create/advancements/windmill.json 4513d0c4dd40c948028a3fc8e6f3b4d0356c0a90 data/create/advancements/wrench.json 33c1224f4f6a7bb0a3439eb0f8b8af9341b62574 data/create/advancements/zapper.json 054392b614e410c6d1b37c546b4bfd36f50aec4a data/create/loot_tables/blocks/acacia_window.json @@ -2433,8 +2360,6 @@ c013613df278f6e8b4c9dad5f16e0ec6c3e992e3 data/create/loot_tables/blocks/copper_t b160899aa785dc54d8c6cc095337f70b81f3e44f data/create/loot_tables/blocks/creative_crate.json 51d66e32581b87beb871d99b93cb45d45eada8dd data/create/loot_tables/blocks/creative_fluid_tank.json d8f2f8921b9200b1d9476a77ee1be32c25308ac3 data/create/loot_tables/blocks/creative_motor.json -08b427aea85e467d7fe58d0e691de428dd64da7f data/create/loot_tables/blocks/crimson_window.json -ba084fc3c680c9dea0d03fc664a831dfed18e52e data/create/loot_tables/blocks/crimson_window_pane.json c28fa42746a4d5ca2f824001b67e58673810169e data/create/loot_tables/blocks/crushing_wheel.json 205f5899101262f31f5c1a88bb7d954918d08d04 data/create/loot_tables/blocks/crushing_wheel_controller.json d370ee874b5b6b98e9a8c368218fe61f644d956d data/create/loot_tables/blocks/cuckoo_clock.json @@ -2530,7 +2455,7 @@ e51893e1601c470da466b35b17251238e15d0361 data/create/loot_tables/blocks/gabbro_b 54879fe6ca3b7271fbb94ec26bef1c3031942d4d data/create/loot_tables/blocks/gabbro_cobblestone_stairs.json ae19749df10663efc51b8b27af310164f250ed38 data/create/loot_tables/blocks/gabbro_cobblestone_wall.json e8d09c919e3b8125d7da0f38383c01bcfc61c7a8 data/create/loot_tables/blocks/gabbro_pillar.json -04e42ba63002ed8ba67780123413f6ff3fb85b02 data/create/loot_tables/blocks/gantry_pinion.json +0ea37ff1af6c6a884670cd12ff1d8fdf223519c5 data/create/loot_tables/blocks/gantry_carriage.json f2883656e417a78e5e4093002eb1e36ffa1157e9 data/create/loot_tables/blocks/gantry_shaft.json b0109b4a4f0f738cbbe6b5911e8c3c0310b76f99 data/create/loot_tables/blocks/gearbox.json 5f39461c5c9d3ad8d84195b06b9468fe2b0fb269 data/create/loot_tables/blocks/gearshift.json @@ -2743,6 +2668,7 @@ b127cb6920e6d7d9c8b2402cb186402a9a8dd3fc data/create/loot_tables/blocks/shaft.js f6c497d625de67ea9377e840208b1be539d13b73 data/create/loot_tables/blocks/spout.json a23a1e332c9ba84474e3c0588e8a0857afe346e0 data/create/loot_tables/blocks/spruce_window.json 3ee2350936ea82fef716bc58e4cd088a384616f0 data/create/loot_tables/blocks/spruce_window_pane.json +111a3bb893abb899652a923b10ca7dc5ea424e5f data/create/loot_tables/blocks/sticker.json 8d2970acd61b96844a4308d87e858b1612d5862e data/create/loot_tables/blocks/sticky_mechanical_piston.json ec2889e712702644092197a4b41a682fb953817d data/create/loot_tables/blocks/stockpile_switch.json 3479775008a256bc35f98b31655975f7d5c836b2 data/create/loot_tables/blocks/stressometer.json @@ -2751,8 +2677,6 @@ e999969f05d2625e61757aa82092d232b99f6e0a data/create/loot_tables/blocks/tiled_gl 7b66ad2c48449bafd0cdbd086ac41218cb73a814 data/create/loot_tables/blocks/turntable.json 028e293b5cd694017962f67dc80dba719f904e28 data/create/loot_tables/blocks/vertical_framed_glass.json d0156602dd5f4a274c293df67e19374820c72890 data/create/loot_tables/blocks/vertical_framed_glass_pane.json -1afc5ede08e72221e33910603fa7acd0b3c7a2ee data/create/loot_tables/blocks/warped_window.json -f334fd2b9a92b0646674239e7e34e142fe2c5fad data/create/loot_tables/blocks/warped_window_pane.json 2883c63ceb1273009dbf91cb0693756cadf79a1a data/create/loot_tables/blocks/water_wheel.json 611d6195db52c074de484ec52d7ac9eb96b4ff10 data/create/loot_tables/blocks/weathered_limestone.json c1f379baad36a20fc767be094db10480a0378184 data/create/loot_tables/blocks/weathered_limestone_bricks.json @@ -2801,15 +2725,12 @@ c6f0509618f703f1a48313e46d934bd862096699 data/create/recipes/blasting/copper_ing d9021504be855cd2d4d91503a82b84233052adb0 data/create/recipes/blasting/gold_ingot_from_crushed.json f2307aa01ddf7accb3fe19c4d3f9b46dec1acf97 data/create/recipes/blasting/ingot_aluminum_compat_immersiveengineering.json 8315c188802bd64f7226a9e942be45173112c7ac data/create/recipes/blasting/ingot_lead_compat_immersiveengineering.json -a000546cea7ea3fcf7fdd741d367d3d2da744871 data/create/recipes/blasting/ingot_lead_compat_mekanism.json 368fd45a8e9d5d2fc0e1f8af1ffb48984b85601c data/create/recipes/blasting/ingot_nickel_compat_immersiveengineering.json d167828a4fe3a20d765831c1df433fc3c8efeab8 data/create/recipes/blasting/ingot_osmium_compat_mekanism.json 9b5a388f0f8a3a8fae9e6bbf6460913b7c1f6fe7 data/create/recipes/blasting/ingot_silver_compat_immersiveengineering.json 7997e66e5e7aebe2c6da764902d78e3bf5f4c530 data/create/recipes/blasting/ingot_tin_compat_mekanism.json ba7498521a1e07b9bd46ec230d952fb232eaaba0 data/create/recipes/blasting/ingot_uranium_compat_immersiveengineering.json -ee290750b334b7996ba856a8f66f4948346c99f6 data/create/recipes/blasting/ingot_uranium_compat_mekanism.json 69cda0f54c47cd44c296608cc379db855602410f data/create/recipes/blasting/iron_ingot_from_crushed.json -0fae477ff5d1852ed7c36d5a94aa25c96604da5d data/create/recipes/blasting/lead_ingot_compat_eidolon.json 65a44735ffa0c3e471a1df30b987d8c3cf1764fc data/create/recipes/blasting/lead_ingot_compat_mysticalworld.json aeb345e5b4c266ac9e2ef6929b153cb535468d01 data/create/recipes/blasting/lead_ingot_compat_silents_mechanisms.json 606b46f5af59d7bd71462807ceb95edebb09a07e data/create/recipes/blasting/lead_ingot_compat_thermal.json @@ -2884,7 +2805,7 @@ f4ae37f736d06ccda5fbba7831a7a174ec916a05 data/create/recipes/crafting/kinetics/f 86ad4d2820e8e2b01de8d977af7796119dfb7430 data/create/recipes/crafting/kinetics/fluid_tank.json 3dad2a849796df268cd3a06ed37376f2cc529957 data/create/recipes/crafting/kinetics/fluid_valve.json 84153bd478c0e63a04c77579d6595043f604b7ab data/create/recipes/crafting/kinetics/furnace_minecart_from_contraption_cart.json -5299a12e9272089e64073c8e151b70a5bc57b53c data/create/recipes/crafting/kinetics/gantry_pinion.json +9e75756423b7f9372a2330a7140f80b1b87bd30e data/create/recipes/crafting/kinetics/gantry_carriage.json 21095a156547d4a7d215964be793f1e960b81c09 data/create/recipes/crafting/kinetics/gantry_shaft.json 5eb05cdf88bccdaddfe7ebfbd8b70d1196d422a6 data/create/recipes/crafting/kinetics/gearbox.json b5da8c58f6b8aba525ae8a12ad906db37b78a566 data/create/recipes/crafting/kinetics/gearboxfrom_conversion.json @@ -2959,6 +2880,7 @@ a17db27e61baa45f8a6ecb46a6d2a5a464704f8b data/create/recipes/crafting/kinetics/s b1a74f0b51fa37ca1ed814266b3d69b8b7e69fa3 data/create/recipes/crafting/kinetics/speedometer.json 8d632845deeb723e1a56083536ee5f9d60de2fcb data/create/recipes/crafting/kinetics/speedometerfrom_conversion.json eea9d4066cd2fafef40b50b79323dcc603fa6388 data/create/recipes/crafting/kinetics/spout.json +e532a5c405e48b415e3fcd4f7c6183ea335cb915 data/create/recipes/crafting/kinetics/sticker.json 3be40664acfd150d0617bc138dc2dd9d54a21b3a data/create/recipes/crafting/kinetics/sticky_mechanical_piston.json af5854ee2fa3be195ad9abcdeebe6ed7306b651c data/create/recipes/crafting/kinetics/stressometerfrom_conversion.json 21f885a674603367b67e1e993c175638cbda9ea3 data/create/recipes/crafting/kinetics/super_glue.json @@ -3021,8 +2943,6 @@ fe95f8f5f15edb0a5ff8da5a4757c9f8910b51bd data/create/recipes/crafting/palettes/d 5c47ac2e2b596439a684126fef7265f13de2379b data/create/recipes/crafting/schematics/schematic_and_quill.json 9fb943be76c51a24aa9d8a09de5b7bd17b44ab08 data/create/recipes/crafting/schematics/schematic_table.json 1a810338ea15ab5ac2f37e87579c56f72b2b371b data/create/recipes/crafting/schematics/schematicannon.json -4629d9a1a8a98a6b5b8b82c4507ca9e321c3a210 data/create/recipes/crimson_window.json -72cffde4281a1e34d77aa91c847e811833b68f21 data/create/recipes/crimson_window_pane.json 18ece8e366b73d19950f9a5a5c93a92c857da2e9 data/create/recipes/crushing/aluminum_ore.json 3da7a3cdb84f44e259b5399a94ddfbf94ebebd37 data/create/recipes/crushing/blaze_rod.json 5878767e89be5a522b8f28d6a2d7b2f8566cf0dd data/create/recipes/crushing/brass_block.json @@ -3042,7 +2962,8 @@ a7c97582bae243ab04ff5ff9914b24af25d40d59 data/create/recipes/crushing/iron_horse 62e2768ae8f0de8d2e50a0916d4961f7836b5f04 data/create/recipes/crushing/lead_ore.json e870d049abc5cd5f389f70414c67e76ddc14060d data/create/recipes/crushing/leather_horse_armor.json 2bc66f89a751a440c93de5f1d28d54f9b5a0da77 data/create/recipes/crushing/nether_quartz_ore.json -6e424d7e9f7d8b585384053a713db28f9d36448b data/create/recipes/crushing/nether_wart_block.json +2b9b8e1ab81f47c4f7fb79a007aef214af12a342 data/create/recipes/crushing/nether_wart_block_no_quark.json +70116a5a9d1f93ae377e1526ca99582190cf2e3e data/create/recipes/crushing/nether_wart_block_quark.json 8003e7db3ee11066b365c251f04f84028820de94 data/create/recipes/crushing/netherrack.json 7b4c7587374fb77088f226187771de520ada548b data/create/recipes/crushing/nickel_ore.json dd4b9e88a723f6c3f2456f36ef2354cd86d85433 data/create/recipes/crushing/obsidian.json @@ -3063,8 +2984,6 @@ b6b97f139ee0a06a4ec1ed9f43e1f845b3c502d3 data/create/recipes/crushing/wool.json 68687da80b9dc7ea69729b0e16d3e75efed8679a data/create/recipes/cutting/andesite_alloy.json 08e2da1149421b9edffdd227f40f6023d7e8ff0e data/create/recipes/cutting/birch_log.json f3e6a435ccdfac3da0482e0eee825f75485370dd data/create/recipes/cutting/birch_wood.json -7d9e56b0dc595052fbdcca6bad0375cf937146f6 data/create/recipes/cutting/crimson_hyphae.json -0c877153c4e080cf1c9a07247e7f5b59e7cfc9a8 data/create/recipes/cutting/crimson_stem.json 8d71bb2524538a0d8fd044427cf7134bc2b31d8b data/create/recipes/cutting/dark_oak_log.json bb4c6b1ef57e5aceeaf8c1840e880e671788256f data/create/recipes/cutting/dark_oak_wood.json f0eb32c6d9f7a5a78f08ee6ac3b97f70747c89f9 data/create/recipes/cutting/jungle_log.json @@ -3077,8 +2996,6 @@ fd565e84aff897968be805c03623757c11ea57ed data/create/recipes/cutting/oak_log.jso c7f0e3b7a46676ede1ed775ec8aa8b969e1fe598 data/create/recipes/cutting/stripped_acacia_wood.json 4c657d8ff753789853c8d705fb5ae01caeef5cc1 data/create/recipes/cutting/stripped_birch_log.json 53f47375955f65844c077c8bb06a9eeb67e0b53f data/create/recipes/cutting/stripped_birch_wood.json -c2d6c83bb3144c6013e169de8f54c5f380ad094f data/create/recipes/cutting/stripped_crimson_hyphae.json -affb6d0e171d77a6a27fc83b1a916eb95ed89516 data/create/recipes/cutting/stripped_crimson_stem.json 9cab5363d43559823d4679da0a64a0a603983cb6 data/create/recipes/cutting/stripped_dark_oak_log.json c63bc7d8a81b3499390de84fc49d726c9018896d data/create/recipes/cutting/stripped_dark_oak_wood.json e923bfbc5d9b02e020693378723b4d55fc60f79a data/create/recipes/cutting/stripped_jungle_log.json @@ -3087,10 +3004,6 @@ ff68462a712267db1f1124d37a4877217edd5c85 data/create/recipes/cutting/stripped_oa 84ffcff96d79f88012bceae0e346da6be4da9802 data/create/recipes/cutting/stripped_oak_wood.json 2b5f34ba42521004f999140056c997b07acde4e9 data/create/recipes/cutting/stripped_spruce_log.json 6c3776c4d4190dba4f70d1f6995715002b37b3a8 data/create/recipes/cutting/stripped_spruce_wood.json -135e9d58965c5715eb6c34a637714f61b38714f7 data/create/recipes/cutting/stripped_warped_hyphae.json -f3c2cd996214e92e95e452d0f6e86ada59e65c78 data/create/recipes/cutting/stripped_warped_stem.json -a022f2d541f04a9e2bed6b72af4e74703076fcbe data/create/recipes/cutting/warped_hyphae.json -1bd01df5540df7db06afde28a3f9ebe4d25e4001 data/create/recipes/cutting/warped_stem.json f2c317e03ac4d42fb631e1625607061e10c480fe data/create/recipes/dark_oak_window.json d9dbae6e237eb38e53a619a0f1b339fca7c59b4d data/create/recipes/dark_oak_window_pane.json 55596a590962e3ddd40949917661f0bd94408274 data/create/recipes/dark_scoria_bricks_from_dark_scoria_stonecutting.json @@ -3209,12 +3122,15 @@ d2ab9ce73636773165564506580f2ec13bd1fc50 data/create/recipes/fancy_weathered_lim 1d0e41ca98e48073c72adf4077610c96e592f9a5 data/create/recipes/fancy_weathered_limestone_bricks_wall_from_fancy_weathered_limestone_bricks_stonecutting.json 133e79f78a7f2c2f63ac7695d2be57d56e8955f4 data/create/recipes/filling/blaze_cake.json 642e96ce5dd2f31e7a33c6ef4060eecb0bf2aa86 data/create/recipes/filling/builders_tea.json +1367357fc36adc4b67467d90589ef91e657380a4 data/create/recipes/filling/chocolate_glazed_berries.json 5bec6c2068a3c1005810d18bd45ce916389b5423 data/create/recipes/filling/glowstone.json 5eb6227ccb6fa940b662d3ec029c3bd61fe61c8d data/create/recipes/filling/grass_block.json 244f27eadefefbc966ac384ac087c57d19484321 data/create/recipes/filling/gunpowder.json c8ca74a6cd071308a1750a2ad1153e79422598a0 data/create/recipes/filling/honey_bottle.json +d20703b67dd5e4c9b75718db02d575b1c7415c12 data/create/recipes/filling/honeyed_apple.json c83e77a9799b6ca34dd73aa76b56159f2103c48c data/create/recipes/filling/milk_bucket.json 08ce1420d1551ecfef5988977436c087123851a6 data/create/recipes/filling/redstone.json +fb8e4378cd2240644a4b5c0d06e27ad772ec7695 data/create/recipes/filling/sweet_roll.json 5b8bbde7f8b270ab75fac18d6858f2fadbc0efa3 data/create/recipes/framed_glass_from_glass_colorless_stonecutting.json d697de0c9b706ca4e18da7a2d769e7e5fe8d769d data/create/recipes/framed_glass_pane.json a0dae50faaa1b7142bb4309675e3084c68daa547 data/create/recipes/gabbro_bricks_from_gabbro_stonecutting.json @@ -3521,15 +3437,12 @@ daaa640dbfaa86685de636b89afe2fdd74cd0cf9 data/create/recipes/smelting/glass_pane b032c79090adad2262ae94609e0b3747327d51a2 data/create/recipes/smelting/gold_ingot_from_crushed.json 5cd79470a32c77fc7347a04ad2096df08769a59f data/create/recipes/smelting/ingot_aluminum_compat_immersiveengineering.json ce34f496dca15378b5e4b21c70505e9d1184848d data/create/recipes/smelting/ingot_lead_compat_immersiveengineering.json -7a9e989c963ebbb286eb8d7a291e8b6a7a96408c data/create/recipes/smelting/ingot_lead_compat_mekanism.json 428b3981a13c63381115384496d89375e3d20837 data/create/recipes/smelting/ingot_nickel_compat_immersiveengineering.json 36a8f88fe3a9b09674bbba99a8f41c8ac5542cdb data/create/recipes/smelting/ingot_osmium_compat_mekanism.json 456ec25989f6d882fc931764341d8217386cf9ab data/create/recipes/smelting/ingot_silver_compat_immersiveengineering.json d2ab440819e4534f717315b7a737bcc2883072ed data/create/recipes/smelting/ingot_tin_compat_mekanism.json 7ca0d75c667e171f2abc5faeb96ef17282b130ac data/create/recipes/smelting/ingot_uranium_compat_immersiveengineering.json -6179556218ef8de57e7a7093498b5c810af9bd7f data/create/recipes/smelting/ingot_uranium_compat_mekanism.json fe3e4c244c34aa6948243fabd6b42f04f80d4992 data/create/recipes/smelting/iron_ingot_from_crushed.json -e558e9ca1460f081972ad8f7fb98c148548cbb57 data/create/recipes/smelting/lead_ingot_compat_eidolon.json 4a1e8041f44bb36d29ec624fc78bdfd0ac875953 data/create/recipes/smelting/lead_ingot_compat_mysticalworld.json 76433e1605c03dec670d95e9541770c53f4a5aaf data/create/recipes/smelting/lead_ingot_compat_silents_mechanisms.json 5247ec83241f698e363d676ad1f19070c736f150 data/create/recipes/smelting/lead_ingot_compat_thermal.json @@ -3560,7 +3473,6 @@ a1112c785f4571c0a9900288081eb216c729a17b data/create/recipes/splashing/crushed_g f3b03dd4532086a785d6bbc9de081ab8adf58146 data/create/recipes/splashing/crushed_iron_ore.json d2d6137fd7a3155263cfffef45f760b99f26f26b data/create/recipes/splashing/crushed_zinc_ore.json 42cee25fabf4f0f9fb4815a98134eaf38ae197d0 data/create/recipes/splashing/cyan_concrete_powder.json -2705d04043f39e4604dd89d8a0ff34ed01548849 data/create/recipes/splashing/eidolon/crushed_lead_ore.json c4d680eed98791fe45fa93aeeae9e8dbd508d6f5 data/create/recipes/splashing/gravel.json 7af4d9ae50af13da0d4fc814687f9586ff872798 data/create/recipes/splashing/gray_concrete_powder.json 23fb61c0e4bcca58fa7241db9cbef07bf4bd9a9b data/create/recipes/splashing/green_concrete_powder.json @@ -3577,10 +3489,8 @@ a43d7c9a6369a48ef7d1396f2c11dc1f3704a61e data/create/recipes/splashing/lime_conc 67d97de29a9075a7ba8edb6e47c997b02600557e data/create/recipes/splashing/limestone.json 862f7b68bb107d7c4ecc82ddd10c788eb0a07b03 data/create/recipes/splashing/magenta_concrete_powder.json 004e05fed3684de8603905d9c9381cbbd789a882 data/create/recipes/splashing/magma_block.json -1ac44e66e1999b7127156492008e08e9607b158e data/create/recipes/splashing/mekanism/crushed_lead_ore.json f627573eefe0353b32d7c48abd7dcbcf13613004 data/create/recipes/splashing/mekanism/crushed_osmium_ore.json a1828cb3c934c4146008d1d10d04adb80a80ac94 data/create/recipes/splashing/mekanism/crushed_tin_ore.json -751c1d11d19054d514eb99d24a73945236dc9116 data/create/recipes/splashing/mekanism/crushed_uranium_ore.json ea4a295149091e3b4b8388cb9d4dd2ab509d666e data/create/recipes/splashing/mysticalworld/crushed_lead_ore.json 1ecac82da1ccc381e303dc64e8033c13cf66fb59 data/create/recipes/splashing/mysticalworld/crushed_quicksilver_ore.json fd1751c804bfc156c7bd97955fabb19f9a4b94ec data/create/recipes/splashing/mysticalworld/crushed_silver_ore.json @@ -3615,8 +3525,6 @@ e2c1774577aeb0756fb1d092245d9d77e40ba5f8 data/create/recipes/splashing/yellow_co 39bd4bcaad003edbe035c91ffde61c51ee1edb87 data/create/recipes/tiled_glass_pane.json 7c6778a30bb670762c3a410cb19d1effc55a7063 data/create/recipes/vertical_framed_glass_from_glass_colorless_stonecutting.json dc6093427210bd7034a0e2184f6a1630c7b33b3e data/create/recipes/vertical_framed_glass_pane.json -40ec72d571002206c276aec5de72459155e043ce data/create/recipes/warped_window.json -8f4b0a3cfb0073f1414bf18c0d4e5e751c4a9185 data/create/recipes/warped_window_pane.json f75f25d3259dd51c29bee6ada2a4540a7a2bbeab data/create/recipes/weathered_limestone_bricks_from_weathered_limestone_stonecutting.json f58ef5eb552fc7dcd89f30aa4231286ecef5e00a data/create/recipes/weathered_limestone_bricks_slab.json ca9b163b3aaa526d6c3b070c2a7e50a56a38c6f4 data/create/recipes/weathered_limestone_bricks_slab_from_weathered_limestone_bricks_stonecutting.json @@ -3634,22 +3542,20 @@ d3fdb8ece6cb072a93ddb64a0baad5ac952117a4 data/create/recipes/weathered_limestone 6eceb25fabbb6b389ca35de3b829ad061c9c456a data/create/recipes/weathered_limestone_pillar.json 11667414f73bc2d00bda7c5c1a7d2934bf6e9165 data/create/recipes/weathered_limestone_pillar_from_weathered_limestone_stonecutting.json eedf31af7134d03656c5fa57229982f9c5bed07c data/create/tags/blocks/brittle.json -330bfb3850ba3964b10b1bccbc3cbb9b012cae54 data/create/tags/blocks/fan_heaters.json +13b55d6e905a02403d2e95e9ba2357f99c5f2241 data/create/tags/blocks/fan_heaters.json 3bc64e3a1e7980237435b1770a9ba2102d57fcd4 data/create/tags/blocks/fan_transparent.json -74700d556ca80c7a1db5fd4efb09c3ddb26cad66 data/create/tags/blocks/non_movable.json c81ea194e808985847159b201140d4aa4cbcca65 data/create/tags/blocks/safe_nbt.json c9ac7e3e5ec18554e7184168d65e9b8e44ef5610 data/create/tags/blocks/sails.json 6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json 50936b211d94167a35ec78c89954082a336b6269 data/create/tags/blocks/valve_handles.json eac71740fb12bdb38b5dfaa2268613d7ba82b809 data/create/tags/blocks/windmill_sails.json -74700d556ca80c7a1db5fd4efb09c3ddb26cad66 data/create/tags/blocks/windowable.json 081f5aa35602fc27af2ca01ea9f2fd5e7eb284dc data/create/tags/items/create_ingots.json 94c62bf22678ef55b2b8a5398a7960e5b00682dc data/create/tags/items/crushed_ores.json 6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/items/seats.json -43ae6f21db7b43984e163af11f4e6cc80459803a data/create/tags/items/upright_on_belt.json +c7efc23c08d5e3602c84ff43dac18f72b1cfced3 data/create/tags/items/upright_on_belt.json 50936b211d94167a35ec78c89954082a336b6269 data/create/tags/items/valve_handles.json 16bcb8fcbe9170c2c11f1ca8d99d8b36cd812bbd data/forge/tags/blocks/glass/colorless.json -81d3eb40b048160fcc2d6bb7ff12b49276297efd data/forge/tags/blocks/glass_panes.json +81ced867d24ec814942909965dd4576eff1db685 data/forge/tags/blocks/glass_panes.json 4b700ee8aa748c2ec70c29ef1589844879c0deae data/forge/tags/blocks/ores.json 4a0b13a9835106de9a1dd0a71a02372abb48e7b6 data/forge/tags/blocks/ores/copper.json d5ea262a0f5fb210612d22521818e26cf08e591a data/forge/tags/blocks/ores/zinc.json @@ -3664,7 +3570,7 @@ d6a4e4fe1204b718010543a28a9b9ec4e0977bd7 data/forge/tags/fluids/tea.json d9ffc62a496946fc4848934e7c0a6e917337f8be data/forge/tags/items/beacon_payment.json 05ca51cdc60a5e109b5a0e3b782de13d34ebcb24 data/forge/tags/items/cobblestone.json 16bcb8fcbe9170c2c11f1ca8d99d8b36cd812bbd data/forge/tags/items/glass/colorless.json -81d3eb40b048160fcc2d6bb7ff12b49276297efd data/forge/tags/items/glass_panes.json +81ced867d24ec814942909965dd4576eff1db685 data/forge/tags/items/glass_panes.json d9ffc62a496946fc4848934e7c0a6e917337f8be data/forge/tags/items/ingots.json 2dfd21017cb51d4bdc18d977a7d16f103cc3a985 data/forge/tags/items/ingots/brass.json 8e0ca32df10a50544f54fbe3dbfe485971b23315 data/forge/tags/items/ingots/copper.json @@ -3687,8 +3593,7 @@ ff1900963bc4cd8ceffa78d58ef1952ceacb2fb7 data/forge/tags/items/storage_blocks/br f6c8f34ceb475546dba5cc6ff288863ea795d20b data/forge/tags/items/storage_blocks/copper.json 7f71a774800111e50b42de0e6159ed2d2a807d32 data/forge/tags/items/storage_blocks/zinc.json 1376cd1f92903a1c4e1422719b1aa102438a216e data/minecraft/advancements/createchromatic_age.json -508730d3822c54d355329bf6a33d58071653afad data/minecraft/tags/blocks/beacon_base_blocks.json -69f596fcb065e26b02ce246760432b5174191b76 data/minecraft/tags/blocks/impermeable.json +31424fe956db0354a9f24c61baf977a2961c8db6 data/minecraft/tags/blocks/impermeable.json 378b01e288301e0835d3d25167889077a2070780 data/minecraft/tags/blocks/rails.json 29e6f7e3d4be9a9b0af1fca5d32fa55e29905ce2 data/minecraft/tags/blocks/slabs.json 0d188ad2c33d10ee8f0d455c4e63a4460a8302fb data/minecraft/tags/blocks/stairs.json diff --git a/src/generated/resources/assets/create/blockstates/andesite_funnel.json b/src/generated/resources/assets/create/blockstates/andesite_funnel.json index 708f98831..9ea4b09ee 100644 --- a/src/generated/resources/assets/create/blockstates/andesite_funnel.json +++ b/src/generated/resources/assets/create/blockstates/andesite_funnel.json @@ -1,216 +1,100 @@ { "variants": { - "extracting=false,face=floor,facing=north,powered=false": { - "model": "create:block/andesite_funnel_floor_pull" - }, - "extracting=true,face=floor,facing=north,powered=false": { - "model": "create:block/andesite_funnel_floor_push" - }, - "extracting=false,face=wall,facing=north,powered=false": { - "model": "create:block/andesite_funnel_wall_pull", - "x": 90 - }, - "extracting=true,face=wall,facing=north,powered=false": { - "model": "create:block/andesite_funnel_wall_push", - "x": 90 - }, - "extracting=false,face=ceiling,facing=north,powered=false": { - "model": "create:block/andesite_funnel_ceiling_pull", + "extracting=false,facing=down,powered=false": { + "model": "create:block/andesite_funnel_vertical_filterless_pull", "x": 180, "y": 180 }, - "extracting=true,face=ceiling,facing=north,powered=false": { - "model": "create:block/andesite_funnel_ceiling_push", + "extracting=true,facing=down,powered=false": { + "model": "create:block/andesite_funnel_vertical_filterless_push", "x": 180, "y": 180 }, - "extracting=false,face=floor,facing=south,powered=false": { - "model": "create:block/andesite_funnel_floor_pull", + "extracting=false,facing=up,powered=false": { + "model": "create:block/andesite_funnel_vertical_filterless_pull", "y": 180 }, - "extracting=true,face=floor,facing=south,powered=false": { - "model": "create:block/andesite_funnel_floor_push", + "extracting=true,facing=up,powered=false": { + "model": "create:block/andesite_funnel_vertical_filterless_push", "y": 180 }, - "extracting=false,face=wall,facing=south,powered=false": { - "model": "create:block/andesite_funnel_wall_pull", - "x": 90, + "extracting=false,facing=north,powered=false": { + "model": "create:block/andesite_funnel_horizontal_pull" + }, + "extracting=true,facing=north,powered=false": { + "model": "create:block/andesite_funnel_horizontal_push" + }, + "extracting=false,facing=south,powered=false": { + "model": "create:block/andesite_funnel_horizontal_pull", "y": 180 }, - "extracting=true,face=wall,facing=south,powered=false": { - "model": "create:block/andesite_funnel_wall_push", - "x": 90, + "extracting=true,facing=south,powered=false": { + "model": "create:block/andesite_funnel_horizontal_push", "y": 180 }, - "extracting=false,face=ceiling,facing=south,powered=false": { - "model": "create:block/andesite_funnel_ceiling_pull", - "x": 180 - }, - "extracting=true,face=ceiling,facing=south,powered=false": { - "model": "create:block/andesite_funnel_ceiling_push", - "x": 180 - }, - "extracting=false,face=floor,facing=west,powered=false": { - "model": "create:block/andesite_funnel_floor_pull", + "extracting=false,facing=west,powered=false": { + "model": "create:block/andesite_funnel_horizontal_pull", "y": 270 }, - "extracting=true,face=floor,facing=west,powered=false": { - "model": "create:block/andesite_funnel_floor_push", + "extracting=true,facing=west,powered=false": { + "model": "create:block/andesite_funnel_horizontal_push", "y": 270 }, - "extracting=false,face=wall,facing=west,powered=false": { - "model": "create:block/andesite_funnel_wall_pull", - "x": 90, - "y": 270 - }, - "extracting=true,face=wall,facing=west,powered=false": { - "model": "create:block/andesite_funnel_wall_push", - "x": 90, - "y": 270 - }, - "extracting=false,face=ceiling,facing=west,powered=false": { - "model": "create:block/andesite_funnel_ceiling_pull", - "x": 180, + "extracting=false,facing=east,powered=false": { + "model": "create:block/andesite_funnel_horizontal_pull", "y": 90 }, - "extracting=true,face=ceiling,facing=west,powered=false": { - "model": "create:block/andesite_funnel_ceiling_push", - "x": 180, + "extracting=true,facing=east,powered=false": { + "model": "create:block/andesite_funnel_horizontal_push", "y": 90 }, - "extracting=false,face=floor,facing=east,powered=false": { - "model": "create:block/andesite_funnel_floor_pull", - "y": 90 - }, - "extracting=true,face=floor,facing=east,powered=false": { - "model": "create:block/andesite_funnel_floor_push", - "y": 90 - }, - "extracting=false,face=wall,facing=east,powered=false": { - "model": "create:block/andesite_funnel_wall_pull", - "x": 90, - "y": 90 - }, - "extracting=true,face=wall,facing=east,powered=false": { - "model": "create:block/andesite_funnel_wall_push", - "x": 90, - "y": 90 - }, - "extracting=false,face=ceiling,facing=east,powered=false": { - "model": "create:block/andesite_funnel_ceiling_pull", - "x": 180, - "y": 270 - }, - "extracting=true,face=ceiling,facing=east,powered=false": { - "model": "create:block/andesite_funnel_ceiling_push", - "x": 180, - "y": 270 - }, - "extracting=false,face=floor,facing=north,powered=true": { - "model": "create:block/andesite_funnel_floor_pull_powered" - }, - "extracting=true,face=floor,facing=north,powered=true": { - "model": "create:block/andesite_funnel_floor_push_powered" - }, - "extracting=false,face=wall,facing=north,powered=true": { - "model": "create:block/andesite_funnel_wall_pull_powered", - "x": 90 - }, - "extracting=true,face=wall,facing=north,powered=true": { - "model": "create:block/andesite_funnel_wall_push_powered", - "x": 90 - }, - "extracting=false,face=ceiling,facing=north,powered=true": { - "model": "create:block/andesite_funnel_ceiling_pull_powered", + "extracting=false,facing=down,powered=true": { + "model": "create:block/andesite_funnel_vertical_filterless_pull_powered", "x": 180, "y": 180 }, - "extracting=true,face=ceiling,facing=north,powered=true": { - "model": "create:block/andesite_funnel_ceiling_push_powered", + "extracting=true,facing=down,powered=true": { + "model": "create:block/andesite_funnel_vertical_filterless_push_powered", "x": 180, "y": 180 }, - "extracting=false,face=floor,facing=south,powered=true": { - "model": "create:block/andesite_funnel_floor_pull_powered", + "extracting=false,facing=up,powered=true": { + "model": "create:block/andesite_funnel_vertical_filterless_pull_powered", "y": 180 }, - "extracting=true,face=floor,facing=south,powered=true": { - "model": "create:block/andesite_funnel_floor_push_powered", + "extracting=true,facing=up,powered=true": { + "model": "create:block/andesite_funnel_vertical_filterless_push_powered", "y": 180 }, - "extracting=false,face=wall,facing=south,powered=true": { - "model": "create:block/andesite_funnel_wall_pull_powered", - "x": 90, + "extracting=false,facing=north,powered=true": { + "model": "create:block/andesite_funnel_horizontal_pull_powered" + }, + "extracting=true,facing=north,powered=true": { + "model": "create:block/andesite_funnel_horizontal_push_powered" + }, + "extracting=false,facing=south,powered=true": { + "model": "create:block/andesite_funnel_horizontal_pull_powered", "y": 180 }, - "extracting=true,face=wall,facing=south,powered=true": { - "model": "create:block/andesite_funnel_wall_push_powered", - "x": 90, + "extracting=true,facing=south,powered=true": { + "model": "create:block/andesite_funnel_horizontal_push_powered", "y": 180 }, - "extracting=false,face=ceiling,facing=south,powered=true": { - "model": "create:block/andesite_funnel_ceiling_pull_powered", - "x": 180 - }, - "extracting=true,face=ceiling,facing=south,powered=true": { - "model": "create:block/andesite_funnel_ceiling_push_powered", - "x": 180 - }, - "extracting=false,face=floor,facing=west,powered=true": { - "model": "create:block/andesite_funnel_floor_pull_powered", + "extracting=false,facing=west,powered=true": { + "model": "create:block/andesite_funnel_horizontal_pull_powered", "y": 270 }, - "extracting=true,face=floor,facing=west,powered=true": { - "model": "create:block/andesite_funnel_floor_push_powered", + "extracting=true,facing=west,powered=true": { + "model": "create:block/andesite_funnel_horizontal_push_powered", "y": 270 }, - "extracting=false,face=wall,facing=west,powered=true": { - "model": "create:block/andesite_funnel_wall_pull_powered", - "x": 90, - "y": 270 - }, - "extracting=true,face=wall,facing=west,powered=true": { - "model": "create:block/andesite_funnel_wall_push_powered", - "x": 90, - "y": 270 - }, - "extracting=false,face=ceiling,facing=west,powered=true": { - "model": "create:block/andesite_funnel_ceiling_pull_powered", - "x": 180, + "extracting=false,facing=east,powered=true": { + "model": "create:block/andesite_funnel_horizontal_pull_powered", "y": 90 }, - "extracting=true,face=ceiling,facing=west,powered=true": { - "model": "create:block/andesite_funnel_ceiling_push_powered", - "x": 180, + "extracting=true,facing=east,powered=true": { + "model": "create:block/andesite_funnel_horizontal_push_powered", "y": 90 - }, - "extracting=false,face=floor,facing=east,powered=true": { - "model": "create:block/andesite_funnel_floor_pull_powered", - "y": 90 - }, - "extracting=true,face=floor,facing=east,powered=true": { - "model": "create:block/andesite_funnel_floor_push_powered", - "y": 90 - }, - "extracting=false,face=wall,facing=east,powered=true": { - "model": "create:block/andesite_funnel_wall_pull_powered", - "x": 90, - "y": 90 - }, - "extracting=true,face=wall,facing=east,powered=true": { - "model": "create:block/andesite_funnel_wall_push_powered", - "x": 90, - "y": 90 - }, - "extracting=false,face=ceiling,facing=east,powered=true": { - "model": "create:block/andesite_funnel_ceiling_pull_powered", - "x": 180, - "y": 270 - }, - "extracting=true,face=ceiling,facing=east,powered=true": { - "model": "create:block/andesite_funnel_ceiling_push_powered", - "x": 180, - "y": 270 } } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/brass_funnel.json b/src/generated/resources/assets/create/blockstates/brass_funnel.json index 23193c4df..19a543d73 100644 --- a/src/generated/resources/assets/create/blockstates/brass_funnel.json +++ b/src/generated/resources/assets/create/blockstates/brass_funnel.json @@ -1,216 +1,100 @@ { "variants": { - "extracting=false,face=floor,facing=north,powered=false": { - "model": "create:block/brass_funnel_floor_pull" - }, - "extracting=true,face=floor,facing=north,powered=false": { - "model": "create:block/brass_funnel_floor_push" - }, - "extracting=false,face=wall,facing=north,powered=false": { - "model": "create:block/brass_funnel_wall_pull", - "x": 90 - }, - "extracting=true,face=wall,facing=north,powered=false": { - "model": "create:block/brass_funnel_wall_push", - "x": 90 - }, - "extracting=false,face=ceiling,facing=north,powered=false": { - "model": "create:block/brass_funnel_ceiling_pull", + "extracting=false,facing=down,powered=false": { + "model": "create:block/brass_funnel_vertical_pull", "x": 180, "y": 180 }, - "extracting=true,face=ceiling,facing=north,powered=false": { - "model": "create:block/brass_funnel_ceiling_push", + "extracting=true,facing=down,powered=false": { + "model": "create:block/brass_funnel_vertical_push", "x": 180, "y": 180 }, - "extracting=false,face=floor,facing=south,powered=false": { - "model": "create:block/brass_funnel_floor_pull", + "extracting=false,facing=up,powered=false": { + "model": "create:block/brass_funnel_vertical_pull", "y": 180 }, - "extracting=true,face=floor,facing=south,powered=false": { - "model": "create:block/brass_funnel_floor_push", + "extracting=true,facing=up,powered=false": { + "model": "create:block/brass_funnel_vertical_push", "y": 180 }, - "extracting=false,face=wall,facing=south,powered=false": { - "model": "create:block/brass_funnel_wall_pull", - "x": 90, + "extracting=false,facing=north,powered=false": { + "model": "create:block/brass_funnel_horizontal_pull" + }, + "extracting=true,facing=north,powered=false": { + "model": "create:block/brass_funnel_horizontal_push" + }, + "extracting=false,facing=south,powered=false": { + "model": "create:block/brass_funnel_horizontal_pull", "y": 180 }, - "extracting=true,face=wall,facing=south,powered=false": { - "model": "create:block/brass_funnel_wall_push", - "x": 90, + "extracting=true,facing=south,powered=false": { + "model": "create:block/brass_funnel_horizontal_push", "y": 180 }, - "extracting=false,face=ceiling,facing=south,powered=false": { - "model": "create:block/brass_funnel_ceiling_pull", - "x": 180 - }, - "extracting=true,face=ceiling,facing=south,powered=false": { - "model": "create:block/brass_funnel_ceiling_push", - "x": 180 - }, - "extracting=false,face=floor,facing=west,powered=false": { - "model": "create:block/brass_funnel_floor_pull", + "extracting=false,facing=west,powered=false": { + "model": "create:block/brass_funnel_horizontal_pull", "y": 270 }, - "extracting=true,face=floor,facing=west,powered=false": { - "model": "create:block/brass_funnel_floor_push", + "extracting=true,facing=west,powered=false": { + "model": "create:block/brass_funnel_horizontal_push", "y": 270 }, - "extracting=false,face=wall,facing=west,powered=false": { - "model": "create:block/brass_funnel_wall_pull", - "x": 90, - "y": 270 - }, - "extracting=true,face=wall,facing=west,powered=false": { - "model": "create:block/brass_funnel_wall_push", - "x": 90, - "y": 270 - }, - "extracting=false,face=ceiling,facing=west,powered=false": { - "model": "create:block/brass_funnel_ceiling_pull", - "x": 180, + "extracting=false,facing=east,powered=false": { + "model": "create:block/brass_funnel_horizontal_pull", "y": 90 }, - "extracting=true,face=ceiling,facing=west,powered=false": { - "model": "create:block/brass_funnel_ceiling_push", - "x": 180, + "extracting=true,facing=east,powered=false": { + "model": "create:block/brass_funnel_horizontal_push", "y": 90 }, - "extracting=false,face=floor,facing=east,powered=false": { - "model": "create:block/brass_funnel_floor_pull", - "y": 90 - }, - "extracting=true,face=floor,facing=east,powered=false": { - "model": "create:block/brass_funnel_floor_push", - "y": 90 - }, - "extracting=false,face=wall,facing=east,powered=false": { - "model": "create:block/brass_funnel_wall_pull", - "x": 90, - "y": 90 - }, - "extracting=true,face=wall,facing=east,powered=false": { - "model": "create:block/brass_funnel_wall_push", - "x": 90, - "y": 90 - }, - "extracting=false,face=ceiling,facing=east,powered=false": { - "model": "create:block/brass_funnel_ceiling_pull", - "x": 180, - "y": 270 - }, - "extracting=true,face=ceiling,facing=east,powered=false": { - "model": "create:block/brass_funnel_ceiling_push", - "x": 180, - "y": 270 - }, - "extracting=false,face=floor,facing=north,powered=true": { - "model": "create:block/brass_funnel_floor_pull_powered" - }, - "extracting=true,face=floor,facing=north,powered=true": { - "model": "create:block/brass_funnel_floor_push_powered" - }, - "extracting=false,face=wall,facing=north,powered=true": { - "model": "create:block/brass_funnel_wall_pull_powered", - "x": 90 - }, - "extracting=true,face=wall,facing=north,powered=true": { - "model": "create:block/brass_funnel_wall_push_powered", - "x": 90 - }, - "extracting=false,face=ceiling,facing=north,powered=true": { - "model": "create:block/brass_funnel_ceiling_pull_powered", + "extracting=false,facing=down,powered=true": { + "model": "create:block/brass_funnel_vertical_pull_powered", "x": 180, "y": 180 }, - "extracting=true,face=ceiling,facing=north,powered=true": { - "model": "create:block/brass_funnel_ceiling_push_powered", + "extracting=true,facing=down,powered=true": { + "model": "create:block/brass_funnel_vertical_push_powered", "x": 180, "y": 180 }, - "extracting=false,face=floor,facing=south,powered=true": { - "model": "create:block/brass_funnel_floor_pull_powered", + "extracting=false,facing=up,powered=true": { + "model": "create:block/brass_funnel_vertical_pull_powered", "y": 180 }, - "extracting=true,face=floor,facing=south,powered=true": { - "model": "create:block/brass_funnel_floor_push_powered", + "extracting=true,facing=up,powered=true": { + "model": "create:block/brass_funnel_vertical_push_powered", "y": 180 }, - "extracting=false,face=wall,facing=south,powered=true": { - "model": "create:block/brass_funnel_wall_pull_powered", - "x": 90, + "extracting=false,facing=north,powered=true": { + "model": "create:block/brass_funnel_horizontal_pull_powered" + }, + "extracting=true,facing=north,powered=true": { + "model": "create:block/brass_funnel_horizontal_push_powered" + }, + "extracting=false,facing=south,powered=true": { + "model": "create:block/brass_funnel_horizontal_pull_powered", "y": 180 }, - "extracting=true,face=wall,facing=south,powered=true": { - "model": "create:block/brass_funnel_wall_push_powered", - "x": 90, + "extracting=true,facing=south,powered=true": { + "model": "create:block/brass_funnel_horizontal_push_powered", "y": 180 }, - "extracting=false,face=ceiling,facing=south,powered=true": { - "model": "create:block/brass_funnel_ceiling_pull_powered", - "x": 180 - }, - "extracting=true,face=ceiling,facing=south,powered=true": { - "model": "create:block/brass_funnel_ceiling_push_powered", - "x": 180 - }, - "extracting=false,face=floor,facing=west,powered=true": { - "model": "create:block/brass_funnel_floor_pull_powered", + "extracting=false,facing=west,powered=true": { + "model": "create:block/brass_funnel_horizontal_pull_powered", "y": 270 }, - "extracting=true,face=floor,facing=west,powered=true": { - "model": "create:block/brass_funnel_floor_push_powered", + "extracting=true,facing=west,powered=true": { + "model": "create:block/brass_funnel_horizontal_push_powered", "y": 270 }, - "extracting=false,face=wall,facing=west,powered=true": { - "model": "create:block/brass_funnel_wall_pull_powered", - "x": 90, - "y": 270 - }, - "extracting=true,face=wall,facing=west,powered=true": { - "model": "create:block/brass_funnel_wall_push_powered", - "x": 90, - "y": 270 - }, - "extracting=false,face=ceiling,facing=west,powered=true": { - "model": "create:block/brass_funnel_ceiling_pull_powered", - "x": 180, + "extracting=false,facing=east,powered=true": { + "model": "create:block/brass_funnel_horizontal_pull_powered", "y": 90 }, - "extracting=true,face=ceiling,facing=west,powered=true": { - "model": "create:block/brass_funnel_ceiling_push_powered", - "x": 180, + "extracting=true,facing=east,powered=true": { + "model": "create:block/brass_funnel_horizontal_push_powered", "y": 90 - }, - "extracting=false,face=floor,facing=east,powered=true": { - "model": "create:block/brass_funnel_floor_pull_powered", - "y": 90 - }, - "extracting=true,face=floor,facing=east,powered=true": { - "model": "create:block/brass_funnel_floor_push_powered", - "y": 90 - }, - "extracting=false,face=wall,facing=east,powered=true": { - "model": "create:block/brass_funnel_wall_pull_powered", - "x": 90, - "y": 90 - }, - "extracting=true,face=wall,facing=east,powered=true": { - "model": "create:block/brass_funnel_wall_push_powered", - "x": 90, - "y": 90 - }, - "extracting=false,face=ceiling,facing=east,powered=true": { - "model": "create:block/brass_funnel_ceiling_pull_powered", - "x": 180, - "y": 270 - }, - "extracting=true,face=ceiling,facing=east,powered=true": { - "model": "create:block/brass_funnel_ceiling_push_powered", - "x": 180, - "y": 270 } } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/gantry_pinion.json b/src/generated/resources/assets/create/blockstates/gantry_carriage.json similarity index 53% rename from src/generated/resources/assets/create/blockstates/gantry_pinion.json rename to src/generated/resources/assets/create/blockstates/gantry_carriage.json index 1280e18d4..06cac5b0c 100644 --- a/src/generated/resources/assets/create/blockstates/gantry_pinion.json +++ b/src/generated/resources/assets/create/blockstates/gantry_carriage.json @@ -1,51 +1,51 @@ { "variants": { "axis_along_first=false,facing=down": { - "model": "create:block/gantry_pinion/horizontal", + "model": "create:block/gantry_carriage/horizontal", "x": 270, "y": 90 }, "axis_along_first=true,facing=down": { - "model": "create:block/gantry_pinion/horizontal", + "model": "create:block/gantry_carriage/horizontal", "x": 270 }, "axis_along_first=false,facing=up": { - "model": "create:block/gantry_pinion/horizontal", + "model": "create:block/gantry_carriage/horizontal", "x": 90, "y": 90 }, "axis_along_first=true,facing=up": { - "model": "create:block/gantry_pinion/horizontal", + "model": "create:block/gantry_carriage/horizontal", "x": 90 }, "axis_along_first=false,facing=north": { - "model": "create:block/gantry_pinion/vertical", + "model": "create:block/gantry_carriage/vertical", "y": 180 }, "axis_along_first=true,facing=north": { - "model": "create:block/gantry_pinion/horizontal", + "model": "create:block/gantry_carriage/horizontal", "y": 180 }, "axis_along_first=false,facing=south": { - "model": "create:block/gantry_pinion/vertical" + "model": "create:block/gantry_carriage/vertical" }, "axis_along_first=true,facing=south": { - "model": "create:block/gantry_pinion/horizontal" + "model": "create:block/gantry_carriage/horizontal" }, "axis_along_first=false,facing=west": { - "model": "create:block/gantry_pinion/horizontal", + "model": "create:block/gantry_carriage/horizontal", "y": 90 }, "axis_along_first=true,facing=west": { - "model": "create:block/gantry_pinion/vertical", + "model": "create:block/gantry_carriage/vertical", "y": 90 }, "axis_along_first=false,facing=east": { - "model": "create:block/gantry_pinion/horizontal", + "model": "create:block/gantry_carriage/horizontal", "y": 270 }, "axis_along_first=true,facing=east": { - "model": "create:block/gantry_pinion/vertical", + "model": "create:block/gantry_carriage/vertical", "y": 270 } } diff --git a/src/generated/resources/assets/create/blockstates/sticker.json b/src/generated/resources/assets/create/blockstates/sticker.json new file mode 100644 index 000000000..1949f8b4e --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/sticker.json @@ -0,0 +1,108 @@ +{ + "variants": { + "extended=false,facing=down,powered=false": { + "model": "create:block/sticker/block", + "x": 180 + }, + "extended=true,facing=down,powered=false": { + "model": "create:block/sticker/block", + "x": 180 + }, + "extended=false,facing=up,powered=false": { + "model": "create:block/sticker/block" + }, + "extended=true,facing=up,powered=false": { + "model": "create:block/sticker/block" + }, + "extended=false,facing=north,powered=false": { + "model": "create:block/sticker/block", + "x": 90 + }, + "extended=true,facing=north,powered=false": { + "model": "create:block/sticker/block", + "x": 90 + }, + "extended=false,facing=south,powered=false": { + "model": "create:block/sticker/block", + "x": 90, + "y": 180 + }, + "extended=true,facing=south,powered=false": { + "model": "create:block/sticker/block", + "x": 90, + "y": 180 + }, + "extended=false,facing=west,powered=false": { + "model": "create:block/sticker/block", + "x": 90, + "y": 270 + }, + "extended=true,facing=west,powered=false": { + "model": "create:block/sticker/block", + "x": 90, + "y": 270 + }, + "extended=false,facing=east,powered=false": { + "model": "create:block/sticker/block", + "x": 90, + "y": 90 + }, + "extended=true,facing=east,powered=false": { + "model": "create:block/sticker/block", + "x": 90, + "y": 90 + }, + "extended=false,facing=down,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 180 + }, + "extended=true,facing=down,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 180 + }, + "extended=false,facing=up,powered=true": { + "model": "create:block/sticker/block_powered" + }, + "extended=true,facing=up,powered=true": { + "model": "create:block/sticker/block_powered" + }, + "extended=false,facing=north,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 90 + }, + "extended=true,facing=north,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 90 + }, + "extended=false,facing=south,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 90, + "y": 180 + }, + "extended=true,facing=south,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 90, + "y": 180 + }, + "extended=false,facing=west,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 90, + "y": 270 + }, + "extended=true,facing=west,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 90, + "y": 270 + }, + "extended=false,facing=east,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 90, + "y": 90 + }, + "extended=true,facing=east,powered=true": { + "model": "create:block/sticker/block_powered", + "x": 90, + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/en_ud.json b/src/generated/resources/assets/create/lang/en_ud.json index 905c6be34..d836963e4 100644 --- a/src/generated/resources/assets/create/lang/en_ud.json +++ b/src/generated/resources/assets/create/lang/en_ud.json @@ -160,7 +160,7 @@ "block.create.gabbro_cobblestone_stairs": "s\u0279\u0131\u0250\u0287S \u01DDuo\u0287s\u01DD\u05DFqqo\u0186 o\u0279qq\u0250\u2141", "block.create.gabbro_cobblestone_wall": "\u05DF\u05DF\u0250M \u01DDuo\u0287s\u01DD\u05DFqqo\u0186 o\u0279qq\u0250\u2141", "block.create.gabbro_pillar": "\u0279\u0250\u05DF\u05DF\u0131\u0500 o\u0279qq\u0250\u2141", - "block.create.gantry_pinion": "uo\u0131u\u0131\u0500 \u028E\u0279\u0287u\u0250\u2141", + "block.create.gantry_carriage": "\u01DDb\u0250\u0131\u0279\u0279\u0250\u0186 \u028E\u0279\u0287u\u0250\u2141", "block.create.gantry_shaft": "\u0287\u025F\u0250\u0265S \u028E\u0279\u0287u\u0250\u2141", "block.create.gearbox": "xoq\u0279\u0250\u01DD\u2141", "block.create.gearshift": "\u0287\u025F\u0131\u0265s\u0279\u0250\u01DD\u2141", @@ -374,6 +374,7 @@ "block.create.spout": "\u0287nodS", "block.create.spruce_window": "\u028Dopu\u0131M \u01DD\u0254n\u0279dS", "block.create.spruce_window_pane": "\u01DDu\u0250\u0500 \u028Dopu\u0131M \u01DD\u0254n\u0279dS", + "block.create.sticker": "\u0279\u01DD\u029E\u0254\u0131\u0287S", "block.create.sticky_mechanical_piston": "uo\u0287s\u0131\u0500 \u05DF\u0250\u0254\u0131u\u0250\u0265\u0254\u01DDW \u028E\u029E\u0254\u0131\u0287S", "block.create.stockpile_switch": "\u0265\u0254\u0287\u0131\u028DS \u01DD\u05DF\u0131d\u029E\u0254o\u0287S", "block.create.stressometer": "\u0279\u01DD\u0287\u01DD\u026Foss\u01DD\u0279\u0287S", @@ -426,6 +427,7 @@ "item.create.builders_tea": "\u0250\u01DD\u27D8 s,\u0279\u01DDp\u05DF\u0131n\u15FA", "item.create.chest_minecart_contraption": "uo\u0131\u0287d\u0250\u0279\u0287uo\u0186 \u0287\u0279\u0250\u0254\u01DDu\u0131W \u0287s\u01DD\u0265\u0186", "item.create.chocolate_bucket": "\u0287\u01DD\u029E\u0254n\u15FA \u01DD\u0287\u0250\u05DFo\u0254o\u0265\u0186", + "item.create.chocolate_glazed_berries": "s\u01DD\u0131\u0279\u0279\u01DD\u15FA p\u01DDz\u0250\u05DF\u2141 \u01DD\u0287\u0250\u05DFo\u0254o\u0265\u0186", "item.create.chromatic_compound": "punod\u026Fo\u0186 \u0254\u0131\u0287\u0250\u026Fo\u0279\u0265\u0186", "item.create.cinder_flour": "\u0279no\u05DF\u2132 \u0279\u01DDpu\u0131\u0186", "item.create.copper_ingot": "\u0287obuI \u0279\u01DDddo\u0186", @@ -459,6 +461,7 @@ "item.create.handheld_blockzapper": "\u0279\u01DDdd\u0250z\u029E\u0254o\u05DF\u15FA p\u05DF\u01DD\u0265pu\u0250H", "item.create.handheld_worldshaper": "\u0279\u01DDd\u0250\u0265sp\u05DF\u0279oM p\u05DF\u01DD\u0265pu\u0250H", "item.create.honey_bucket": "\u0287\u01DD\u029E\u0254n\u15FA \u028E\u01DDuoH", + "item.create.honeyed_apple": "\u01DD\u05DFdd\u2C6F p\u01DD\u028E\u01DDuoH", "item.create.integrated_circuit": "\u0287\u0131n\u0254\u0279\u0131\u0186 p\u01DD\u0287\u0250\u0279b\u01DD\u0287uI", "item.create.iron_sheet": "\u0287\u01DD\u01DD\u0265S uo\u0279I", "item.create.lapis_sheet": "\u0287\u01DD\u01DD\u0265S s\u0131d\u0250\uA780", @@ -475,6 +478,7 @@ "item.create.schematic_and_quill": "\u05DF\u05DF\u0131n\u1F49 pu\u2C6F \u0254\u0131\u0287\u0250\u026F\u01DD\u0265\u0254S", "item.create.shadow_steel": "\u05DF\u01DD\u01DD\u0287S \u028Dop\u0250\u0265S", "item.create.super_glue": "\u01DDn\u05DF\u2141 \u0279\u01DDdnS", + "item.create.sweet_roll": "\u05DF\u05DFo\u1D1A \u0287\u01DD\u01DD\u028DS", "item.create.tree_fertilizer": "\u0279\u01DDz\u0131\u05DF\u0131\u0287\u0279\u01DD\u2132 \u01DD\u01DD\u0279\u27D8", "item.create.vertical_gearbox": "xoq\u0279\u0250\u01DD\u2141 \u05DF\u0250\u0254\u0131\u0287\u0279\u01DD\u039B", "item.create.wand_of_symmetry": "\u028E\u0279\u0287\u01DD\u026F\u026F\u028ES \u025FO pu\u0250M", diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index f8f2a0ff6..8e4b1ef27 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -163,7 +163,7 @@ "block.create.gabbro_cobblestone_stairs": "Gabbro Cobblestone Stairs", "block.create.gabbro_cobblestone_wall": "Gabbro Cobblestone Wall", "block.create.gabbro_pillar": "Gabbro Pillar", - "block.create.gantry_pinion": "Gantry Pinion", + "block.create.gantry_carriage": "Gantry Carriage", "block.create.gantry_shaft": "Gantry Shaft", "block.create.gearbox": "Gearbox", "block.create.gearshift": "Gearshift", @@ -377,6 +377,7 @@ "block.create.spout": "Spout", "block.create.spruce_window": "Spruce Window", "block.create.spruce_window_pane": "Spruce Window Pane", + "block.create.sticker": "Sticker", "block.create.sticky_mechanical_piston": "Sticky Mechanical Piston", "block.create.stockpile_switch": "Stockpile Switch", "block.create.stressometer": "Stressometer", @@ -432,6 +433,7 @@ "item.create.builders_tea": "Builder's Tea", "item.create.chest_minecart_contraption": "Chest Minecart Contraption", "item.create.chocolate_bucket": "Chocolate Bucket", + "item.create.chocolate_glazed_berries": "Chocolate Glazed Berries", "item.create.chromatic_compound": "Chromatic Compound", "item.create.cinder_flour": "Cinder Flour", "item.create.copper_ingot": "Copper Ingot", @@ -465,6 +467,7 @@ "item.create.handheld_blockzapper": "Handheld Blockzapper", "item.create.handheld_worldshaper": "Handheld Worldshaper", "item.create.honey_bucket": "Honey Bucket", + "item.create.honeyed_apple": "Honeyed Apple", "item.create.integrated_circuit": "Integrated Circuit", "item.create.iron_sheet": "Iron Sheet", "item.create.lapis_sheet": "Lapis Sheet", @@ -481,6 +484,7 @@ "item.create.schematic_and_quill": "Schematic And Quill", "item.create.shadow_steel": "Shadow Steel", "item.create.super_glue": "Super Glue", + "item.create.sweet_roll": "Sweet Roll", "item.create.tree_fertilizer": "Tree Fertilizer", "item.create.vertical_gearbox": "Vertical Gearbox", "item.create.wand_of_symmetry": "Wand Of Symmetry", @@ -827,12 +831,15 @@ "create.gui.goggles.kinetic_stats": "Kinetic Stats:", "create.gui.goggles.at_current_speed": "at current speed", "create.gui.goggles.pole_length": "Pole Length:", + "create.gui.goggles.fluid_container": "Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "Capacity: ", "create.gui.assembly.exception": "This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "Gauge Information:", "create.gui.speedometer.title": "Rotation Speed", "create.gui.stressometer.title": "Network Stress", @@ -1449,6 +1456,8 @@ "item.create.goggles.tooltip.behaviour1": "Shows _colored indicators_ corresponding to the _Speed Level_ of a placed kinetic component as well as _Stress Impact_ and _Capacity_ of individual components.", "item.create.goggles.tooltip.condition2": "When looking at gauge", "item.create.goggles.tooltip.behaviour2": "Shows detailed information about _Speed_ or _Stress_ of the network to which the gauge is connected.", + "item.create.goggles.tooltip.condition3": "When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "WRENCH", "item.create.wrench.tooltip.summary": "A useful tool for working on kinetic contraptions. Can be used to _Rotate_, _Dismantle_ and to _Configure_ components.", @@ -1803,6 +1812,480 @@ "create.tooltip.randomWipDescription7": "This one maybe isn't for you. What about that one?", "create.tooltip.randomWipDescription8": "Use it and regret your decision immediately.", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "Hold [%1$s] to Ponder", + "create.ponder.subject": "Subject of this scene", + "create.ponder.pondering": "Pondering about...", + "create.ponder.identify_mode": "Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "Associated Entries", + "create.ponder.close": "Close", + "create.ponder.identify": "Identify", + "create.ponder.next": "Next Scene", + "create.ponder.previous": "Previous Scene", + "create.ponder.replay": "Replay", + "create.ponder.think_back": "Think Back", + "create.ponder.shared.movement_anchors": "With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "32 RPM", + "create.ponder.shared.sneak_and": "Sneak +", + "create.ponder.shared.storage_on_contraption": "Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "8 RPM", + "create.ponder.shared.ctrl_and": "Ctrl +", + "create.ponder.shared.rpm16_source": "Source: 16 RPM", + "create.ponder.shared.rpm16": "16 RPM", + "create.ponder.tag.kinetic_sources": "Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "Contraption Actors", + "create.ponder.tag.contraption_actor.description": "Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "Item Transportation", + "create.ponder.tag.logistics.description": "Components which help moving items around", + "create.ponder.tag.movement_anchor": "Movement Anchors", + "create.ponder.tag.movement_anchor.description": "Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "Aesthetics", + "create.ponder.tag.decoration.description": "Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "Components which make use of Rotational Force", + "create.ponder.tag.redstone": "Logic Components", + "create.ponder.tag.redstone.description": "Components which help with redstone engineering", + "create.ponder.tag.creative": "Creative Mode", + "create.ponder.tag.creative.description": "Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "Fluid Manipulators", + "create.ponder.tag.fluids.description": "Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "Encasing Belts", + "create.ponder.belt_casing.text_1": "Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "3. They can connect vertically", + "create.ponder.belt_directions.text_5": "4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "The Brass Funnel", + "create.ponder.brass_funnel.text_1": "Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "12 RPM", + + "create.ponder.clockwork_bearing.header": "Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "3:00", + "create.ponder.clockwork_bearing.text_4": "4:00", + "create.ponder.clockwork_bearing.text_5": "Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "Using the Deployer", + "create.ponder.deployer.text_1": "Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "Items can also be inserted automatically", + "create.ponder.deployer.text_12": "Deployers carry a filter slot", + "create.ponder.deployer.text_13": "When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "Deployers can:", + "create.ponder.deployer.text_5": "Place Blocks,", + "create.ponder.deployer.text_6": "Use Items,", + "create.ponder.deployer.text_7": "Activate Blocks,", + "create.ponder.deployer.text_8": "Harvest blocks", + "create.ponder.deployer.text_9": "and Attack Mobs", + + "create.ponder.deployer_contraption.header": "Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "Funnel compatibility", + "create.ponder.funnel_compat.text_1": "Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "Vertical Saws", + "create.ponder.funnel_compat.text_3": "Depots", + "create.ponder.funnel_compat.text_4": "Item Drains", + + "create.ponder.funnel_direction.header": "Direction of Transfer", + "create.ponder.funnel_direction.text_1": "Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "Using funnels", + "create.ponder.funnel_intro.text_1": "Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "Redstone control", + "create.ponder.funnel_redstone.text_1": "Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "Direct transfer", + "create.ponder.funnel_transfer.text_1": "Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "Straight connections will be reversed", + + "create.ponder.gearshift.header": "Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "Piston Extension Poles", + "create.ponder.piston_pole.text_1": "Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "...on and back off", + "create.ponder.powered_toggle_latch.text_4": "Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "Redstone Contacts", + "create.ponder.redstone_contact.text_1": "Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "Using Redstone Links", + "create.ponder.redstone_link.text_1": "Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "Encasing Shafts", + "create.ponder.shaft_casing.text_1": "Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/de_de.json b/src/generated/resources/assets/create/lang/unfinished/de_de.json index 10a6a4897..82ea9ce8f 100644 --- a/src/generated/resources/assets/create/lang/unfinished/de_de.json +++ b/src/generated/resources/assets/create/lang/unfinished/de_de.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 973", + "_": "Missing Localizations: 1370", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,8 +67,6 @@ "block.create.creative_crate": "Kreative anpassbare Kiste", "block.create.creative_fluid_tank": "Kreativer Flüssigkeitstank", "block.create.creative_motor": "Kreativer Motor", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", "block.create.crushing_wheel": "Mahlwerkrad", "block.create.crushing_wheel_controller": "Mahlwerkrad Steurung", "block.create.cuckoo_clock": "Kuckucksuhr", @@ -164,7 +162,7 @@ "block.create.gabbro_cobblestone_stairs": "Gabelsteinbruchstein", "block.create.gabbro_cobblestone_wall": "Gabelsteinbruchstein", "block.create.gabbro_pillar": "Gabelsteinsäule", - "block.create.gantry_pinion": "UNLOCALIZED: Gantry Pinion", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", "block.create.gearbox": "Getriebe", "block.create.gearshift": "Gangschaltung", @@ -378,6 +376,7 @@ "block.create.spout": "UNLOCALIZED: Spout", "block.create.spruce_window": "UNLOCALIZED: Spruce Window", "block.create.spruce_window_pane": "UNLOCALIZED: Spruce Window Pane", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "Klebriger Mechanischer Kolben", "block.create.stockpile_switch": "Vorratssensor", "block.create.stressometer": "UNLOCALIZED: Stressometer", @@ -386,8 +385,6 @@ "block.create.turntable": "Drehtisch", "block.create.vertical_framed_glass": "UNLOCALIZED: Vertical Framed Glass", "block.create.vertical_framed_glass_pane": "UNLOCALIZED: Vertical Framed Glass Pane", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", "block.create.water_wheel": "Wasserrad", "block.create.weathered_limestone": "Verwitterter Kalkstein", "block.create.weathered_limestone_bricks": "Verwitterte Kalksteinziegel", @@ -433,6 +430,7 @@ "item.create.builders_tea": "UNLOCALIZED: Builder's Tea", "item.create.chest_minecart_contraption": "UNLOCALIZED: Chest Minecart Contraption", "item.create.chocolate_bucket": "UNLOCALIZED: Chocolate Bucket", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "UNLOCALIZED: Chromatic Compound", "item.create.cinder_flour": "UNLOCALIZED: Cinder Flour", "item.create.copper_ingot": "UNLOCALIZED: Copper Ingot", @@ -466,6 +464,7 @@ "item.create.handheld_blockzapper": "Blockpistole", "item.create.handheld_worldshaper": "Geländeformer", "item.create.honey_bucket": "Honigeimer", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "UNLOCALIZED: Integrated Circuit", "item.create.iron_sheet": "Eisenblech", "item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet", @@ -482,6 +481,7 @@ "item.create.schematic_and_quill": "Bauplan und Feder", "item.create.shadow_steel": "UNLOCALIZED: Shadow Steel", "item.create.super_glue": "Superkleber", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "Baumdünger", "item.create.vertical_gearbox": "UNLOCALIZED: Vertical Gearbox", "item.create.wand_of_symmetry": "Symmetriestab", @@ -828,12 +828,15 @@ "create.gui.goggles.kinetic_stats": "UNLOCALIZED: Kinetic Stats:", "create.gui.goggles.at_current_speed": "UNLOCALIZED: at current speed", "create.gui.goggles.pole_length": "UNLOCALIZED: Pole Length:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "UNLOCALIZED: Gauge Information:", "create.gui.speedometer.title": "UNLOCALIZED: Rotation Speed", "create.gui.stressometer.title": "UNLOCALIZED: Network Stress", @@ -1450,6 +1453,8 @@ "item.create.goggles.tooltip.behaviour1": "UNLOCALIZED: Shows _colored indicators_ corresponding to the _Speed Level_ of a placed kinetic component as well as _Stress Impact_ and _Capacity_ of individual components.", "item.create.goggles.tooltip.condition2": "UNLOCALIZED: When looking at gauge", "item.create.goggles.tooltip.behaviour2": "UNLOCALIZED: Shows detailed information about _Speed_ or _Stress_ of the network to which the gauge is connected.", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "UNLOCALIZED: WRENCH", "item.create.wrench.tooltip.summary": "UNLOCALIZED: A useful tool for working on kinetic contraptions. Can be used to _Rotate_, _Dismantle_ and to _Configure_ components.", @@ -1804,6 +1809,480 @@ "create.tooltip.randomWipDescription7": "UNLOCALIZED: This one maybe isn't for you. What about that one?", "create.tooltip.randomWipDescription8": "UNLOCALIZED: Use it and regret your decision immediately.", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/es_es.json b/src/generated/resources/assets/create/lang/unfinished/es_es.json index 642deb7fb..477c1075f 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_es.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_es.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 15", + "_": "Missing Localizations: 401", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,8 +67,6 @@ "block.create.creative_crate": "Caja creativa", "block.create.creative_fluid_tank": "Tanque de fluidos creativo", "block.create.creative_motor": "Motor creativo", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", "block.create.crushing_wheel": "Rueda trituradora", "block.create.crushing_wheel_controller": "Controlador de Rueda trituradora", "block.create.cuckoo_clock": "Reloj Cucú", @@ -110,7 +108,7 @@ "block.create.dolomite_pillar": "Pilar de dolomita", "block.create.encased_chain_drive": "Cadena de transmisión revestida", "block.create.encased_fan": "Ventilador revestido", - "block.create.encased_fluid_pipe": "Tubería de fluidos de cobre revestida", + "block.create.encased_fluid_pipe": "Tubería de fluidos de cobre reforzada", "block.create.fancy_andesite_bricks": "Ladrillos de andesita elegantes", "block.create.fancy_andesite_bricks_slab": "Ladrillos de andesita elegantes", "block.create.fancy_andesite_bricks_stairs": "Escaleras de ladrillos de andesita elegantes", @@ -164,11 +162,11 @@ "block.create.gabbro_cobblestone_stairs": "Escaleras de adoquínes de gabro", "block.create.gabbro_cobblestone_wall": "Pared de adoquínes de gabro", "block.create.gabbro_pillar": "Pilar de gabro", - "block.create.gantry_pinion": "Piñón de grúa", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "Eje de grúa", "block.create.gearbox": "Caja de transmisión", "block.create.gearshift": "Caja de cambios", - "block.create.glass_fluid_pipe": "Tubo de cristal para fluidos", + "block.create.glass_fluid_pipe": "Tubería de fluidos de cristal", "block.create.granite_bricks": "Ladrillos de granito", "block.create.granite_bricks_slab": "Losa de ladrillos de granito", "block.create.granite_bricks_stairs": "Escaleras de ladrillos de granito", @@ -352,7 +350,7 @@ "block.create.redstone_link": "Enlace de Redstone", "block.create.refined_radiance_casing": "Revestidor de radiante", "block.create.reinforced_rail": "Raíl reforzado", - "block.create.rope": "Soga", + "block.create.rope": "Cuerda", "block.create.rope_pulley": "Polea de cuerda", "block.create.rotation_speed_controller": "Controlador de velocidad de rotación", "block.create.sail_frame": "Marco de vela", @@ -378,6 +376,7 @@ "block.create.spout": "Surtidor", "block.create.spruce_window": "Ventana de abeto", "block.create.spruce_window_pane": "Panel de ventana de abeto", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "Pistón mecánico pegajoso", "block.create.stockpile_switch": "Interruptor de acopio", "block.create.stressometer": "Estresómetro", @@ -386,8 +385,6 @@ "block.create.turntable": "Plataforma giratoria mecánica", "block.create.vertical_framed_glass": "Vidrio esmaltado vertical", "block.create.vertical_framed_glass_pane": "Panel de vidrio esmaltado vertical", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", "block.create.water_wheel": "Rueda hidráulica mecánica", "block.create.weathered_limestone": "Piedra caliza erosionada", "block.create.weathered_limestone_bricks": "Ladrillos de piedra caliza erosionada", @@ -433,6 +430,7 @@ "item.create.builders_tea": "Té del Constructor", "item.create.chest_minecart_contraption": "Artilugio de vagoneta con cofre", "item.create.chocolate_bucket": "Cubo de chocolate", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "Compuesto cromático", "item.create.cinder_flour": "Harina de ceniza", "item.create.copper_ingot": "Lingote de cobre", @@ -466,6 +464,7 @@ "item.create.handheld_blockzapper": "Blockzapper", "item.create.handheld_worldshaper": "Worldshaper", "item.create.honey_bucket": "Cubo de miel", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "Chip de circuito integrado", "item.create.iron_sheet": "Lámina de hierro", "item.create.lapis_sheet": "Lámina de lapislázuli", @@ -482,6 +481,7 @@ "item.create.schematic_and_quill": "Esquema y Pluma", "item.create.shadow_steel": "Acero sombrío", "item.create.super_glue": "Super Pegamento", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "Fertilizador de árboles", "item.create.vertical_gearbox": "Caja de transmisión vertical", "item.create.wand_of_symmetry": "Varita de simetría", @@ -511,7 +511,7 @@ "advancement.create.splitter_tunnel": "Divide y vencerás", "advancement.create.splitter_tunnel.desc": "Crear un divisor con un grupo de túneles de latón.", "advancement.create.chute": "Caída en picado", - "advancement.create.chute.desc": "Coloque un ducto, la contrapartida vertical de la correa.", + "advancement.create.chute.desc": "Coloque un ducto, la contrapartida vertical de la cinta.", "advancement.create.upward_chute": "Abducción aérea", "advancement.create.upward_chute.desc": "Observe cómo un objeto lanzado vuela hacia un paracaídas impulsado por un ventilador.", "advancement.create.belt_funnel": "Colgantes con forma de embudo", @@ -537,7 +537,7 @@ "advancement.create.aesthetics": "Boom, Estética!", "advancement.create.aesthetics.desc": "Colocar los soportes en un eje, tubo y rueda dentada.", "advancement.create.reinforced": "Boom, Reforzado!", - "advancement.create.reinforced.desc": "Utilizar bloques de revestimiento en un eje, un tubo y una correa.", + "advancement.create.reinforced.desc": "Utilizar bloques de revestimiento en un eje, un tubo y una cinta.", "advancement.create.water_wheel": "Aprovechar la hidráulica", "advancement.create.water_wheel.desc": "Coloca una Rueda hidráulica e intenta hacerla girar.", "advancement.create.chocolate_wheel": "Potencia de buen gusto", @@ -689,7 +689,7 @@ "create.recipe.mechanical_crafting": "Elaboración mecánica", "create.recipe.automatic_shaped": "Elaboración automatizada de productos con forma", "create.recipe.block_cutting": "Corte de bloques", - "create.recipe.wood_cutting": "UNLOCALIZED: Wood Cutting", + "create.recipe.wood_cutting": "Corte de maderas", "create.recipe.blockzapper_upgrade": "Blockzapper", "create.recipe.sandpaper_polishing": "Pulido con papel de lija", "create.recipe.mystery_conversion": "Conversión misteriosa", @@ -828,12 +828,15 @@ "create.gui.goggles.kinetic_stats": "Estadísticas cinéticas:", "create.gui.goggles.at_current_speed": "con la velocidad actual", "create.gui.goggles.pole_length": "Longitud del poste:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "Este artilugio no se pudo montar:", - "create.gui.assembly.exception.unmovableBlock": "Bloque inamovible (%4$s) en [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "El bloque en [%1$s %2$s %3$s] no estaba en un chunk cargado", + "create.gui.assembly.exception.unmovableBlock": "Bloque inamovible (%4$s) en [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "El bloque en [%1$s,%2$s,%3$s] no estaba en un chunk cargado", "create.gui.assembly.exception.structureTooLarge": "Hay demasiados bloques incluídos en el artilugio.\nEl máximo configurado es: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "Hay demasiadas Pértigas de extensión conectadas a este Pistón.\nEl máximo configurado es: %1$s", "create.gui.assembly.exception.noPistonPoles": "Faltan pértigas de extensión para el Pistón", + "create.gui.assembly.exception.not_enough_sails": "La estructura adjunta no incluye suficientes bloques tipo vela: %1$s\nSe requiere un mínimo de %2$s", "create.gui.gauge.info_header": "Información sobre el medidor:", "create.gui.speedometer.title": "Velocidad de rotación", "create.gui.stressometer.title": "Estrés de la red", @@ -850,19 +853,19 @@ "create.gui.stockpile_switch.move_to_upper_at": "Pasar al carril superior en %1$s%%", "create.gui.sequenced_gearshift.title": "Cambio de marchas secuenciado", "create.gui.sequenced_gearshift.instruction": "Instrucción", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "UNLOCALIZED: Turn by angle", + "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Giro por ángulo", "create.gui.sequenced_gearshift.instruction.turn_angle": "Giro", "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Ángulo", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "UNLOCALIZED: Turn to move Piston/Pulley/Gantry", + "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Giro para mover el pistón/polea/grúa", "create.gui.sequenced_gearshift.instruction.turn_distance": "Pistón", "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distancia", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "UNLOCALIZED: Timed Delay", - "create.gui.sequenced_gearshift.instruction.delay": "UNLOCALIZED: Delay", - "create.gui.sequenced_gearshift.instruction.delay.duration": "UNLOCALIZED: Duration", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "UNLOCALIZED: End", + "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Tiempo de retraso", + "create.gui.sequenced_gearshift.instruction.delay": "Retraso", + "create.gui.sequenced_gearshift.instruction.delay.duration": "Duración", + "create.gui.sequenced_gearshift.instruction.end.descriptive": "Fin", "create.gui.sequenced_gearshift.instruction.end": "Fin", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "UNLOCALIZED: Await new Redstone Pulse", - "create.gui.sequenced_gearshift.instruction.await": "UNLOCALIZED: Await", + "create.gui.sequenced_gearshift.instruction.await.descriptive": "En espera de un Pulso de Redstone", + "create.gui.sequenced_gearshift.instruction.await": "En espera", "create.gui.sequenced_gearshift.speed": "Velocidad, Dirección", "create.gui.sequenced_gearshift.speed.forward": "Velocidad de entrada, hacia adelante", "create.gui.sequenced_gearshift.speed.forward_fast": "Doble velocidad, hacia adelante", @@ -1171,19 +1174,19 @@ "block.create.metal_bracket.tooltip.summary": "Decora tus _Ejes_, _Ruedas dentadas_ y _Ductos_ con un poco de refuerzo industrial robusto.", "block.create.andesite_casing.tooltip": "REVESTIDOR DE ANDESITA", - "block.create.andesite_casing.tooltip.summary": "Máquina de revestimiento simple con una variedad de usos. Seguro para la decoración. Puede utilizarse para _encastrar ejes_ y _correas._", + "block.create.andesite_casing.tooltip.summary": "Máquina de revestimiento simple con una variedad de usos. Seguro para la decoración. Puede utilizarse para _revestir ejes_ y _cintas._", "block.create.andesite_funnel.tooltip": "EMBUDO DE ANDESITA", "block.create.andesite_funnel.tooltip.summary": "Un componente de transferencia de elementos en general, que hace la transición de éstos entre los medios de transporte. Se puede controlar con una _señal de Redstone_.", "block.create.andesite_funnel.tooltip.condition1": "Comportamiento general", "block.create.andesite_funnel.tooltip.behaviour1": "La cara _abierta_ _recogerá los objetos molidos_ en el espacio del bloque que tiene delante y los _insertará_ en cualquier contenedor del lado opuesto del embudo", - "block.create.andesite_funnel.tooltip.condition2": "Cuando se montan en correas, depósitos y similares", + "block.create.andesite_funnel.tooltip.condition2": "Cuando se montan en cintas, depósitos y similares", "block.create.andesite_funnel.tooltip.behaviour2": "_Recoge_ o _Coloca_ los elementos en el componente montado, desde o hacia el inventario _detrás_ de sí mismo. Siempre que el embudo tenga una direccionalidad específica, puede invertirse utilizando una Llave.", "block.create.andesite_funnel.tooltip.condition3": "Cuando se encuentra verticalmente entre dos inventarios", "block.create.andesite_funnel.tooltip.behaviour3": "Transferirá los artículos hacia abajo, como una tolva sin búfer.", "block.create.andesite_tunnel.tooltip": "TÚNEL DE ANDESITA", - "block.create.andesite_tunnel.tooltip.summary": "¡Una cubierta protectora para sus _correas_!. El _Túnel de Andesita_ puede separar un elemento de una pila cuando se coloca otra correa o depósito al lado de la correa principal.", + "block.create.andesite_tunnel.tooltip.summary": "¡Una cubierta protectora para sus _cintas_!. El _Túnel de Andesita_ puede separar un elemento de una pila cuando se coloca otra cinta o depósito al lado de la cinta principal.", "block.create.andesite_tunnel.tooltip.control1": "Click derecho con la Llave Inglesa en el lateral", "block.create.andesite_tunnel.tooltip.action1": "_Ajusta las persianas de las ventanas_ si el túnel tiene una ventana en esa cara.", @@ -1191,15 +1194,15 @@ "block.create.brass_funnel.tooltip.summary": "Un componente de transferencia de elementos en general, que hace la transición de éstos entre los medios de transporte. Se puede controlar con una _señal de Redstone_. Viene con un práctico _filtro_.", "block.create.brass_funnel.tooltip.condition1": "Comportamiento General", "block.create.brass_funnel.tooltip.behaviour1": "La cara _abierta_ _recogerá los objetos molidos_ en el espacio del bloque que tiene delante y los _insertará_ en cualquier contenedor del lado opuesto del embudo.", - "block.create.brass_funnel.tooltip.condition2": "Cuando se montan en correas, depósitos y similares", + "block.create.brass_funnel.tooltip.condition2": "Cuando se montan en cintas, depósitos y similares", "block.create.brass_funnel.tooltip.behaviour2": "_Recoge_ o _Coloca_ los elementos en el componente montado, desde o hacia el inventario _detrás_ de sí mismo. Siempre que el embudo tenga una direccionalidad específica, puede invertirse utilizando una Llave Inglesa.", "block.create.brass_funnel.tooltip.condition3": "Cuando se encuentra verticalmente entre dos inventarios", "block.create.brass_funnel.tooltip.behaviour3": "Transfiere los artículos hacia abajo, como una tolva sin búfer.", "block.create.brass_tunnel.tooltip": "TÚNEL DE LATÓN", - "block.create.brass_tunnel.tooltip.summary": "Una cubierta protectora elegante para sus _correas_. Los _Túneles de latón_ también vienen con una serie de opciones de _Filtración_ y _División_ para sus artículos.", + "block.create.brass_tunnel.tooltip.summary": "Una cubierta protectora elegante para sus _cintas_. Los _Túneles de latón_ también vienen con una serie de opciones de _Filtración_ y _División_ para sus artículos.", "block.create.brass_tunnel.tooltip.condition1": "Cuando se colocan uno al lado del otro", - "block.create.brass_tunnel.tooltip.behaviour1": "Los túneles de latón se conectan entre sí y permiten redirigir el contenido de una correa a otra.", + "block.create.brass_tunnel.tooltip.behaviour1": "Los túneles de latón se conectan entre sí y permiten redirigir el contenido de una cinta a otra.", "block.create.brass_tunnel.tooltip.condition2": "Filtrado", "block.create.brass_tunnel.tooltip.behaviour2": "Los _Túneles de latón_ vienen con filtros tanto para la _Entrada_ como para la _Salida_. Si un _Elemento_ no está permitido desde la salida filtrada de un _Túnel_ será transferido a la salida de un _Túnel_ conectado.", "block.create.brass_tunnel.tooltip.condition3": "Dividiendo", @@ -1214,8 +1217,8 @@ "block.create.copper_casing.tooltip.condition1": "Cuando se utiliza en una tubería de fluidos", "block.create.copper_casing.tooltip.behaviour1": "_Reviste_ la _Tubería de fluidos_ con _Revestimiento de cobre_. Las tuberías de fluidos revestidas _bloquean sus conexiones_ en su lugar, dejando de reaccionar a los cambios en las tuberías vecinas.", - "block.create.encased_fluid_pipe.tooltip": "TUBO DE FLUIDOS REVESTIDO", - "block.create.encased_fluid_pipe.tooltip.summary": "Un tubo de fluidos revestido con cobre.", + "block.create.encased_fluid_pipe.tooltip": "TUBO DE FLUIDOS REFORZADO", + "block.create.encased_fluid_pipe.tooltip.summary": "Un tubo de fluidos reforzado con más cobre.", "block.create.copper_valve_handle.tooltip": "ASA DE VÁLVULA DE COBRE", "block.create.copper_valve_handle.tooltip.summary": "Una precisa _fuente_ de _fuerza de rotación_ que requiere la interacción de los jugadores. ¡Ten cuidado de no agotarte!", @@ -1230,12 +1233,12 @@ "block.create.chute.tooltip": "DUCTO", "block.create.chute.tooltip.summary": "_Recoge_ y _Transporta_ elementos en vertical o en diagonal. Puede tanto coger como colocar objetos en _contenedores de objetos_. También puede interactuar con los ductos desde el lateral utilizando _tolvas_ o _embudos montados_.", "block.create.chute.tooltip.condition1": "Cuando se alimenta con un ventilador", - "block.create.chute.tooltip.behaviour1": "Los ductos accionados por ventilador pueden transportar _elementos_ hacia arriba, y aspirar _elementos_ de los _depósitos_ y de las _correas_.", + "block.create.chute.tooltip.behaviour1": "Los ductos accionados por ventilador pueden transportar _elementos_ hacia arriba, y aspirar _elementos_ de los _depósitos_ y de las _cintas_.", "block.create.depot.tooltip": "DEPÓSITO", "block.create.depot.tooltip.summary": "Un lugar práctico para colocar sus _elementos_. Proporciona un punto de interacción para varias máquinas", "block.create.depot.tooltip.condition1": "Click derecho en el depósito", - "block.create.depot.tooltip.behaviour1": "Coloca o toma un _Elemento_ del _Depósito_. Los _Bloques_ y los _Artilugios_ que interactúan con una _Correa_ también funcionan en un _Depósito_.", + "block.create.depot.tooltip.behaviour1": "Coloca o toma un _Elemento_ del _Depósito_. Los _Bloques_ y los _Artilugios_ que interactúan con una _cinta_ también funcionan en un _Depósito_.", "item.create.blaze_cake.tooltip": "PASTEL DE BLAZE", "item.create.blaze_cake.tooltip.summary": "Un delicioso regalo para sus esforzados _Quemadores de blaze_. Los pone en marcha!.", @@ -1297,7 +1300,7 @@ "block.create.spout.tooltip.condition1": "Transferencia de fluidos", "block.create.spout.tooltip.behaviour1": "Cuando se coloca un _contenedor de fluidos_ como un _cubo_ o una _botella_ debajo, el caño intentará rellenarlo con su propio _fluido_ almacenado", "block.create.spout.tooltip.condition2": "Automatización de fluidos", - "block.create.spout.tooltip.behaviour2": "El caño colocado encima de una _correa_ o _depósito_ reaccionará automáticamente con un contenedor de fluidos_ que pase por debajo", + "block.create.spout.tooltip.behaviour2": "El caño colocado encima de una _cinta_ o _depósito_ reaccionará automáticamente con un contenedor de fluidos_ que pase por debajo", "block.create.item_drain.tooltip": "DRENADOR DE ELEMENTOS", "block.create.item_drain.tooltip.summary": "Un depósito rallado para vaciar tus _artículos fluidos._", @@ -1307,7 +1310,7 @@ "block.create.mechanical_arm.tooltip": "BRAZO MECÁNICO", "block.create.mechanical_arm.tooltip.summary": "Artilugio avanzado para reubicar _elementos_", "block.create.mechanical_arm.tooltip.condition1": "Transferencia de elementos", - "block.create.mechanical_arm.tooltip.behaviour1": "Puede tomar o colocar objetos en cualquier _inventario_ accesible_, como _Correas_, _Depósitos_, _Embudos_ y _Autoensambladores_", + "block.create.mechanical_arm.tooltip.behaviour1": "Puede tomar o colocar objetos en cualquier _inventario_ accesible_, como _Cintas_, _Depósitos_, _Embudos_ y _Autoensambladores_", "block.create.mechanical_arm.tooltip.control1": "Mientras está en la mano", "block.create.mechanical_arm.tooltip.action1": "Haz clic con el botón derecho en un _objeto accesible del inventario_ para establecerlo como _fuente_ para el _brazo mecánico_. Haz clic con el botón derecho del ratón dos veces para establecerlo como _destino_", "block.create.mechanical_arm.tooltip.control2": "Usa la rueda del ratón con la Llave Inglesa", @@ -1422,7 +1425,7 @@ "block.create.gearshift.tooltip.condition1": "Cuando se alimenta", "block.create.gearshift.tooltip.behaviour1": "_Invierte_ la rotación de salida", - "block.create.clutch.tooltip": "UNLOCALIZED: CLUTCH", + "block.create.clutch.tooltip": "Embrague", "block.create.clutch.tooltip.summary": "Un control para conectar/desconectar la rotación de los ejes conectados", "block.create.clutch.tooltip.condition1": "Cuando se acciona", "block.create.clutch.tooltip.behaviour1": "_Detiene_ el transporte de la rotación al otro lado", @@ -1450,6 +1453,8 @@ "item.create.goggles.tooltip.behaviour1": "Muestra _indicadores de color_ correspondientes al _Nivel de velocidad_ de un componente cinético colocado, así como el _Impacto de estrés_ y la _Capacidad_ de los componentes individuales.", "item.create.goggles.tooltip.condition2": "Al mirar el medidor", "item.create.goggles.tooltip.behaviour2": "Muestra información detallada sobre _Velocidad_ o _Estrés_ de la red a la que está conectado el medidor", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "LLAVE INGLESA", "item.create.wrench.tooltip.summary": "Una herramienta útil para trabajar en artilugios cinéticos. Se puede utilizar para _Rotar_, _Desmantelar_ y para _Configurar_ componentes", @@ -1505,8 +1510,8 @@ "block.create.mechanical_press.tooltip.summary": "Un pistón de fuerza para comprimir los objetos que tiene debajo. Requiere una _fuerza de rotación_ constante", "block.create.mechanical_press.tooltip.condition1": "Cuando es impulsado por Redstone", "block.create.mechanical_press.tooltip.behaviour1": "Comienza a _comprimir_ los objetos que caen debajo", - "block.create.mechanical_press.tooltip.condition2": "Cuando está por encima de una correa", - "block.create.mechanical_press.tooltip.behaviour2": "Comprime _automáticamente_ los elementos de derivación en la correa", + "block.create.mechanical_press.tooltip.condition2": "Cuando está por encima de una cinta", + "block.create.mechanical_press.tooltip.behaviour2": "Comprime _automáticamente_ los elementos de derivación en la cinta", "block.create.mechanical_press.tooltip.condition3": "Cuando está por encima de la Cuenca", "block.create.mechanical_press.tooltip.behaviour3": "Comienza a _compactar artículos_ en la cuenca siempre que estén presentes todos los ingredientes necesarios", @@ -1531,13 +1536,13 @@ "block.create.mechanical_mixer.tooltip.behaviour1": "Comienza a mezclar los elementos en la cuenca siempre que estén presentes todos los ingredientes necesarios. Para evitar recetas no deseadas, utilice la ranura del filtro de la cuenca o reduzca la fuerza de rotación hasta que se hayan añadido todos los ingredientes deseados", "block.create.mechanical_crafter.tooltip": "AUTOENSAMBLADOR MECÁNICO", - "block.create.mechanical_crafter.tooltip.summary": "Un ensamblador cinético para _automatizar_ cualquier receta de _crafteo_ con forma. Coloca _múltiples en una cuadrícula_ correspondiente a tu receta, y _organiza sus correas_ para crear un _flujo_ que salga de la cuadrícula en uno de los Autoensambladores", + "block.create.mechanical_crafter.tooltip.summary": "Un ensamblador cinético para _automatizar_ cualquier receta de _crafteo_ con forma. Coloca _múltiples en una cuadrícula_ correspondiente a tu receta, y _organiza sus cintas_ para crear un _flujo_ que salga de la cuadrícula en uno de los Autoensambladores", "block.create.mechanical_crafter.tooltip.condition1": "Cuando es impulsado por la cinética", "block.create.mechanical_crafter.tooltip.behaviour1": "_Empieza el proceso de creación_ en cuanto _todos los crafters_ de la parrilla hayan recibido un objeto_", "block.create.mechanical_crafter.tooltip.condition2": "Con pulso de Redstone", "block.create.mechanical_crafter.tooltip.behaviour2": "_Fuerza_ el inicio del proceso de _creación_ con todos los _artículos_ dados actualmente en la parrilla", "block.create.mechanical_crafter.tooltip.control1": "Cuando se arranca por delante", - "block.create.mechanical_crafter.tooltip.action1": "_Circula la dirección_ hacia la que un autoensamblador individual _mueve sus objetos_. Para formar una cuadrícula de trabajo, _organiza las correas en un flujo_ que mueva todos los objetos hacia un autoensamblador final. El autoensamblador final debe _apuntar hacia fuera_ de la rejilla", + "block.create.mechanical_crafter.tooltip.action1": "_Circula la dirección_ hacia la que un autoensamblador individual _mueve sus objetos_. Para formar una cuadrícula de trabajo, _organiza las cintas en un flujo_ que mueva todos los objetos hacia un autoensamblador final. El autoensamblador final debe _apuntar hacia fuera_ de la rejilla", "block.create.mechanical_crafter.tooltip.control2": "Cuando se arranca hacia atrás", "block.create.mechanical_crafter.tooltip.action2": "Conecta_ el _inventario de entrada_ de los autoensambladores adyacentes. Usa esto para _combinar ranuras_ en la cuadrícula de trabajo y _guardar el la entrada de trabajo_", @@ -1642,7 +1647,7 @@ "block.create.secondary_linear_chassis.tooltip": "CHASIS LINEAL SECUNDARIO", "block.create.secondary_linear_chassis.tooltip.summary": "Un segundo tipo de _Chasis lineal_ que no se conecta al otro", - "block.create.radial_chassis.tooltip": "UNLOCALIZED: ROTATION CHASSIS", + "block.create.radial_chassis.tooltip": "CHASIS RADIAL", "block.create.radial_chassis.tooltip.summary": "Bloque base configurable que conecta estructuras para el movimiento", "block.create.radial_chassis.tooltip.condition1": "Cuando se mueve", "block.create.radial_chassis.tooltip.behaviour1": "_Mueve_ todos los _Chasis_ adjuntos en una columna, y un cilindro de bloques a su alrededor. Los bloques que lo rodean sólo se mueven cuando están dentro del rango y están adheridos a un lado pegajoso (Ver [Ctrl]).", @@ -1728,7 +1733,7 @@ "block.create.deployer.tooltip.behaviour3": "El desplegador no se activará a menos que el elemento retenido _coincida_ con el _filtro._ Los elementos que no coincidan no podrán ser insertados; los elementos retenidos que coincidan con el filtro no podrán ser extraídos.", "block.create.brass_casing.tooltip": "REVESTIDOR DE LATÓN", - "block.create.brass_casing.tooltip.summary": "Resistente máquina revestidora con una gran variedad de usos. Segura para la decoración. Se puede utilizar para _revestir ejes_ y _correas._", + "block.create.brass_casing.tooltip.summary": "Resistente máquina revestidora con una gran variedad de usos. Segura para la decoración. Se puede utilizar para _revestir ejes_ y _cintas._", "block.create.pulse_repeater.tooltip": "REPETIDOR DE PULSOS DE REDSTONE", "block.create.pulse_repeater.tooltip.summary": "Un circuito sencillo para cortar las señales de Redstone que pasan a una longitud de _1 tick_", @@ -1804,6 +1809,480 @@ "create.tooltip.randomWipDescription7": "Este quizás no es para ti. ¿Qué tal ese?", "create.tooltip.randomWipDescription8": "Úsalo y arrepiéntete de tu decisión inmediatamente", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/es_mx.json b/src/generated/resources/assets/create/lang/unfinished/es_mx.json index 881695d98..999520272 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_mx.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_mx.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 899", + "_": "Missing Localizations: 1300", "_": "->------------------------] Game Elements [------------------------<-", @@ -164,7 +164,7 @@ "block.create.gabbro_cobblestone_stairs": "Escaleras de Piedra Labrada de Gabro", "block.create.gabbro_cobblestone_wall": "Pared de Piedra Labrada de Gabro", "block.create.gabbro_pillar": "Pilar de Gabro", - "block.create.gantry_pinion": "UNLOCALIZED: Gantry Pinion", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", "block.create.gearbox": "Transmisión", "block.create.gearshift": "Cambio de Marcha", @@ -378,6 +378,7 @@ "block.create.spout": "Canaleta", "block.create.spruce_window": "Ventana de Abeto", "block.create.spruce_window_pane": "Panel de Ventana de Abeto", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "Pistón Mecánico Pegajoso", "block.create.stockpile_switch": "Interruptor de Pila", "block.create.stressometer": "Estresómetro", @@ -433,6 +434,7 @@ "item.create.builders_tea": "Té del Constructor", "item.create.chest_minecart_contraption": "Artefacto de Vagón con Cofre", "item.create.chocolate_bucket": "Cubeta de Chocolate", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "Compuesto Cromático", "item.create.cinder_flour": "Ceniza Molida", "item.create.copper_ingot": "Lingote de Cobre", @@ -466,6 +468,7 @@ "item.create.handheld_blockzapper": "Pistola de Manipulación de Bloques", "item.create.handheld_worldshaper": "Pistola de Manipulación de Mundo", "item.create.honey_bucket": "Cubeta de Miel", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "Circuito Integrado", "item.create.iron_sheet": "Lámina de Hierro", "item.create.lapis_sheet": "Lámina de Lapislázuli", @@ -482,6 +485,7 @@ "item.create.schematic_and_quill": "Esquema y Pluma", "item.create.shadow_steel": "Acero Sombrío", "item.create.super_glue": "Super Pegamento", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "Fertilizador de Árboles", "item.create.vertical_gearbox": "Transmisión Vertical", "item.create.wand_of_symmetry": "Vara de la Simetria", @@ -828,12 +832,15 @@ "create.gui.goggles.kinetic_stats": "UNLOCALIZED: Kinetic Stats:", "create.gui.goggles.at_current_speed": "UNLOCALIZED: at current speed", "create.gui.goggles.pole_length": "UNLOCALIZED: Pole Length:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "UNLOCALIZED: Gauge Information:", "create.gui.speedometer.title": "UNLOCALIZED: Rotation Speed", "create.gui.stressometer.title": "UNLOCALIZED: Network Stress", @@ -1450,6 +1457,8 @@ "item.create.goggles.tooltip.behaviour1": "Muestra _indicadores_ _con_ _colores_ correspondientes al _Nivel_ _de_ _Velocidad_ de un componente cinético colocado, así como _Impacto_ _de_ _Estrés_ y _Capacidad_ de los componentes individuales.", "item.create.goggles.tooltip.condition2": "Al mirar el medidor", "item.create.goggles.tooltip.behaviour2": "Muestra información detallada sobre la _velocidad_ o el _estrés_ de la red a la que está conectado el medidor.", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "WRENCH", "item.create.wrench.tooltip.summary": "Una herramienta útil para trabajar en artefactos cinéticos. Se puede utilizar para _Rotar,_ _Desmantelar_ y _Configurar_ componentes.", @@ -1804,6 +1813,480 @@ "create.tooltip.randomWipDescription7": "UNLOCALIZED: This one maybe isn't for you. What about that one?", "create.tooltip.randomWipDescription8": "UNLOCALIZED: Use it and regret your decision immediately.", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json index a83a8258d..54fec9d1c 100644 --- a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json +++ b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 685", + "_": "Missing Localizations: 1082", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,8 +67,6 @@ "block.create.creative_crate": "Créateur de schémacanon", "block.create.creative_fluid_tank": "Réservoir créatif", "block.create.creative_motor": "Moteur", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", "block.create.crushing_wheel": "Roue de concassage", "block.create.crushing_wheel_controller": "Contrôleur de roue de concassage", "block.create.cuckoo_clock": "Horloge à coucou", @@ -164,7 +162,7 @@ "block.create.gabbro_cobblestone_stairs": "UNLOCALIZED: Gabbro Cobblestone Stairs", "block.create.gabbro_cobblestone_wall": "UNLOCALIZED: Gabbro Cobblestone Wall", "block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar", - "block.create.gantry_pinion": "UNLOCALIZED: Gantry Pinion", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", "block.create.gearbox": "Boîte à roue dentée", "block.create.gearshift": "Décaleur de rotation", @@ -378,6 +376,7 @@ "block.create.spout": "UNLOCALIZED: Spout", "block.create.spruce_window": "UNLOCALIZED: Spruce Window", "block.create.spruce_window_pane": "UNLOCALIZED: Spruce Window Pane", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "Piston mécanique collant", "block.create.stockpile_switch": "Détecteur de stockage", "block.create.stressometer": "Stressomètre", @@ -386,8 +385,6 @@ "block.create.turntable": "Plaque tournante", "block.create.vertical_framed_glass": "Fenêtre en verre verticale", "block.create.vertical_framed_glass_pane": "Vitre encadrée verticale", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", "block.create.water_wheel": "Roue à eau", "block.create.weathered_limestone": "Calcaire altéré", "block.create.weathered_limestone_bricks": "Briques de Calcaire altéré", @@ -433,6 +430,7 @@ "item.create.builders_tea": "Thé du constructeur", "item.create.chest_minecart_contraption": "Engin de wagonnet avec coffre", "item.create.chocolate_bucket": "Seau de chocolat", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "Composé chromatique", "item.create.cinder_flour": "Farine de braise", "item.create.copper_ingot": "Lingot de cuivre", @@ -466,6 +464,7 @@ "item.create.handheld_blockzapper": "Blockzappeur portable", "item.create.handheld_worldshaper": "Térraformeur portable", "item.create.honey_bucket": "Seau de miel", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "Circuit intégré", "item.create.iron_sheet": "Plaque de Fer", "item.create.lapis_sheet": "Feuille de lapis", @@ -482,6 +481,7 @@ "item.create.schematic_and_quill": "Schéma et plume", "item.create.shadow_steel": "Acier sombre", "item.create.super_glue": "Colle extra-forte", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "Engrais pour arbres", "item.create.vertical_gearbox": "Boîte de transfert verticale", "item.create.wand_of_symmetry": "Bâton de symétrie", @@ -828,12 +828,15 @@ "create.gui.goggles.kinetic_stats": "Statistiques cinétiques:", "create.gui.goggles.at_current_speed": "À la vitesse actuelle", "create.gui.goggles.pole_length": "Longueur de la barre", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "Informations sur la jauge:", "create.gui.speedometer.title": "Vitesse de rotation", "create.gui.stressometer.title": "Stress du réseau", @@ -1450,6 +1453,8 @@ "item.create.goggles.tooltip.behaviour1": "Affiche des _indicateurs_ _colorés_ correspondants au _niveau_ _de_ _vitesse_ d'un composant cinétique placé ainsi que _l'impact_ du _stress_ et la _capacité_ des composants individuels.", "item.create.goggles.tooltip.condition2": "Quand vision portée sur une jauge", "item.create.goggles.tooltip.behaviour2": "Affiche des informations détaillées sur la _vitesse_ ou le _stress_ du réseau auquel la jauge est connectée.", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "CLÉ", "item.create.wrench.tooltip.summary": "Un outil utile pour travailler sur les engins cinétiques. Peut être utilisé pour _tourner_, _démonter_ et _configurer_ les composants.", @@ -1804,6 +1809,480 @@ "create.tooltip.randomWipDescription7": "Celui-ci n'est peut-être pas pour vous. Que dire de celui-là?", "create.tooltip.randomWipDescription8": "Utilisez-le et regrettez immédiatement votre décision.", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/it_it.json b/src/generated/resources/assets/create/lang/unfinished/it_it.json index 3f82f9151..8f188d3ce 100644 --- a/src/generated/resources/assets/create/lang/unfinished/it_it.json +++ b/src/generated/resources/assets/create/lang/unfinished/it_it.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 20", + "_": "Missing Localizations: 418", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,8 +67,6 @@ "block.create.creative_crate": "Creatore cannoneschematico", "block.create.creative_fluid_tank": "Serbatoio per fluidi (creativa)", "block.create.creative_motor": "Motore (creativa)", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", "block.create.crushing_wheel": "Ruota di frantumazione", "block.create.crushing_wheel_controller": "Telecomando per ruota di frantumazione", "block.create.cuckoo_clock": "Orologio a cucù", @@ -164,7 +162,7 @@ "block.create.gabbro_cobblestone_stairs": "Scalini di pietrisco di gabbro", "block.create.gabbro_cobblestone_wall": "Muretto di pietrisco di gabbro", "block.create.gabbro_pillar": "Pilastro di gabbro", - "block.create.gantry_pinion": "Pignone a portale", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "Albero a portale", "block.create.gearbox": "Riduttore", "block.create.gearshift": "Cambio", @@ -378,6 +376,7 @@ "block.create.spout": "Spruzzo", "block.create.spruce_window": "Finestra di abete", "block.create.spruce_window_pane": "Pannello di finestra di abete", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "Pistone meccanico appiccicoso", "block.create.stockpile_switch": "Interruttore accumulatore", "block.create.stressometer": "Stressometro", @@ -386,8 +385,6 @@ "block.create.turntable": "Piatto", "block.create.vertical_framed_glass": "Finestra di vetro verticale", "block.create.vertical_framed_glass_pane": "Pannello di finestra di vetro verticale", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", "block.create.water_wheel": "Ruota idraulica", "block.create.weathered_limestone": "Calcare consumato", "block.create.weathered_limestone_bricks": "Mattoni di calcare consumato", @@ -433,6 +430,7 @@ "item.create.builders_tea": "Tè del costruttore", "item.create.chest_minecart_contraption": "Contrazione per carrello da miniera con baule", "item.create.chocolate_bucket": "Secchio di cioccolata", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "Composto cromatico", "item.create.cinder_flour": "Cenere farinosa", "item.create.copper_ingot": "Lingotto di rame", @@ -466,6 +464,7 @@ "item.create.handheld_blockzapper": "Zapper di blocchi portatile", "item.create.handheld_worldshaper": "Plasmatore del mondo portatile", "item.create.honey_bucket": "Secchio di miele", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "Circuito integrato", "item.create.iron_sheet": "Lamiera di ferro", "item.create.lapis_sheet": "Lamiera di lapislazzuli", @@ -482,6 +481,7 @@ "item.create.schematic_and_quill": "Schematica e penna d'oca", "item.create.shadow_steel": "Acciaio oscuro", "item.create.super_glue": "Super colla", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "Fertilizzante per alberi", "item.create.vertical_gearbox": "Riduttore verticale", "item.create.wand_of_symmetry": "Asta di simmetria", @@ -828,12 +828,15 @@ "create.gui.goggles.kinetic_stats": "Statistiche cinetiche:", "create.gui.goggles.at_current_speed": "Alla velocità attuale", "create.gui.goggles.pole_length": "Lunghezza palo:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "Informazioni sul calibro:", "create.gui.speedometer.title": "Velocità di rotazione", "create.gui.stressometer.title": "Stress della rete", @@ -1450,6 +1453,8 @@ "item.create.goggles.tooltip.behaviour1": "Mostra gli _indicatori_ _colorati_ corrispondenti al _livello_ _di_ _velocità_ di un componente cinetico posizionato, nonché all'_impatto_ _dello_ _stress_ e la capacità dei singoli componenti.", "item.create.goggles.tooltip.condition2": "Quando si guarda il calibro", "item.create.goggles.tooltip.behaviour2": "Mostra informazioni dettagliate sulla _velocità_ o lo _stress_ della rete a cui è collegato il misuratore.", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "CHIAVE INGLESE", "item.create.wrench.tooltip.summary": "Uno strumento utile per lavorare su congegni cinetici. Può essere usato per _ruotare_, _smontare_ e _configurare_ i componenti.", @@ -1804,6 +1809,480 @@ "create.tooltip.randomWipDescription7": "Questo forse non fa per te. Che ne dici di quello?", "create.tooltip.randomWipDescription8": "Usalo e rimpiangi immediatamente la tua decisione.", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json index 419d6691e..6a407c0a5 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json +++ b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 27", + "_": "Missing Localizations: 425", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,8 +67,6 @@ "block.create.creative_crate": "クリエティブクレート", "block.create.creative_fluid_tank": "クリエイティブ液体タンク", "block.create.creative_motor": "クリエイティブモーター", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", "block.create.crushing_wheel": "破砕ホイール", "block.create.crushing_wheel_controller": "破砕ホイールコントローラー", "block.create.cuckoo_clock": "鳩時計", @@ -164,7 +162,7 @@ "block.create.gabbro_cobblestone_stairs": "斑れい岩の丸石の階段", "block.create.gabbro_cobblestone_wall": "斑れい岩の丸石の壁", "block.create.gabbro_pillar": "斑れい岩の柱", - "block.create.gantry_pinion": "ガントリーピニオン", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "ガントリーシャフト", "block.create.gearbox": "ギアボックス", "block.create.gearshift": "ギアシフト", @@ -378,6 +376,7 @@ "block.create.spout": "アイテム注液口", "block.create.spruce_window": "マツの窓", "block.create.spruce_window_pane": "マツの窓パネル", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "粘着メカニカルピストン", "block.create.stockpile_switch": "在庫スイッチ", "block.create.stressometer": "応力メーター", @@ -386,8 +385,6 @@ "block.create.turntable": "ターンテーブル", "block.create.vertical_framed_glass": "垂直ガラス窓", "block.create.vertical_framed_glass_pane": "垂直ガラス窓板", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", "block.create.water_wheel": "水車", "block.create.weathered_limestone": "風化した石灰岩", "block.create.weathered_limestone_bricks": "風化した石灰岩レンガ", @@ -433,6 +430,7 @@ "item.create.builders_tea": "建築家のお茶", "item.create.chest_minecart_contraption": "からくりチェストトロッコ", "item.create.chocolate_bucket": "チョコレート入りバケツ", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "色彩の化合物", "item.create.cinder_flour": "ネザーラックの粉", "item.create.copper_ingot": "銅インゴット", @@ -466,6 +464,7 @@ "item.create.handheld_blockzapper": "携帯ブロックザッパー", "item.create.handheld_worldshaper": "携帯ワールドシェーパー", "item.create.honey_bucket": "ハチミツ入りバケツ", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "集積回路", "item.create.iron_sheet": "鉄板", "item.create.lapis_sheet": "ラピスラズリ板", @@ -482,6 +481,7 @@ "item.create.schematic_and_quill": "概略図と羽根ペン", "item.create.shadow_steel": "シャドウスチール", "item.create.super_glue": "接着剤", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "樹木の肥料", "item.create.vertical_gearbox": "垂直ギアボックス", "item.create.wand_of_symmetry": "対称の杖", @@ -828,12 +828,15 @@ "create.gui.goggles.kinetic_stats": "動力の統計:", "create.gui.goggles.at_current_speed": "現在の速度", "create.gui.goggles.pole_length": "ポールの長さ:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "計器の情報:", "create.gui.speedometer.title": "回転速度", "create.gui.stressometer.title": "ネットワークの応力", @@ -1450,6 +1453,8 @@ "item.create.goggles.tooltip.behaviour1": "設置された機械の_速度レベル_および、_機械_の_応力の影響_と_容量_を_色付きのインジケーター_で表示します。", "item.create.goggles.tooltip.condition2": "計器を見たとき", "item.create.goggles.tooltip.behaviour2": "計器が接続されているネットワークの_速度_または_応力_に関する詳細情報を表示します。", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "レンチ", "item.create.wrench.tooltip.summary": "動的からくりに取り組むための便利なツール。コンポーネントの_回転_、_解体_、_設定_に使用できます。", @@ -1804,6 +1809,480 @@ "create.tooltip.randomWipDescription7": "これは君に向いていないかもしれない。あれはどう??", "create.tooltip.randomWipDescription8": "それを使ったことをすぐ後悔する。", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json index 68e9583a8..735d654f7 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json +++ b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 74", + "_": "Missing Localizations: 471", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,8 +67,6 @@ "block.create.creative_crate": "크리에이티브 창고", "block.create.creative_fluid_tank": "크리에이티브 탱크", "block.create.creative_motor": "크리에이티브 모터", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", "block.create.crushing_wheel": "분쇄 휠", "block.create.crushing_wheel_controller": "분쇄 휠 컨트롤러", "block.create.cuckoo_clock": "뻐꾸기 시계", @@ -164,7 +162,7 @@ "block.create.gabbro_cobblestone_stairs": "반려암 조약돌 계단", "block.create.gabbro_cobblestone_wall": "반려암 조약돌 담장", "block.create.gabbro_pillar": "반려암 기둥", - "block.create.gantry_pinion": "UNLOCALIZED: Gantry Pinion", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", "block.create.gearbox": "기어박스", "block.create.gearshift": "기어쉬프트", @@ -378,6 +376,7 @@ "block.create.spout": "수도꼭지", "block.create.spruce_window": "가문비나무 유리창", "block.create.spruce_window_pane": "가문비나무 유리판", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "끈끈이 기계식 피스톤", "block.create.stockpile_switch": "수량 스위치", "block.create.stressometer": "피로도 계측기", @@ -386,8 +385,6 @@ "block.create.turntable": "돌림판", "block.create.vertical_framed_glass": "수직 유리", "block.create.vertical_framed_glass_pane": "수직 유리판", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", "block.create.water_wheel": "물레방아", "block.create.weathered_limestone": "풍화된 석회암", "block.create.weathered_limestone_bricks": "풍화된 석회암 벽돌", @@ -433,6 +430,7 @@ "item.create.builders_tea": "건축가의 차", "item.create.chest_minecart_contraption": "상자가 실린 광산 수레 장치", "item.create.chocolate_bucket": "초콜릿 양동이", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "색채 혼합물", "item.create.cinder_flour": "잿가루", "item.create.copper_ingot": "구리 주괴", @@ -466,6 +464,7 @@ "item.create.handheld_blockzapper": "휴대용 블록발사기", "item.create.handheld_worldshaper": "휴대용 세계편집기", "item.create.honey_bucket": "꿀 양동이", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "집적 회로", "item.create.iron_sheet": "철 판", "item.create.lapis_sheet": "청금석 판", @@ -482,6 +481,7 @@ "item.create.schematic_and_quill": "청사진과 깃펜", "item.create.shadow_steel": "그림자 강철", "item.create.super_glue": "강력 접착제", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "나무 비료", "item.create.vertical_gearbox": "수직 기어박스", "item.create.wand_of_symmetry": "대칭의 지팡이", @@ -828,12 +828,15 @@ "create.gui.goggles.kinetic_stats": "가동 상태:", "create.gui.goggles.at_current_speed": "현재 에너지량", "create.gui.goggles.pole_length": "UNLOCALIZED: Pole Length:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "게이지 정보:", "create.gui.speedometer.title": "회전 속도", "create.gui.stressometer.title": "네트워크 부하", @@ -1450,6 +1453,8 @@ "item.create.goggles.tooltip.behaviour1": "해당 장치의 _속도_, _피로도_, _용량_을 레벨에 따라 에 따라 색상 UI를 보여줍니다.", "item.create.goggles.tooltip.condition2": "계측기를 바라볼 때", "item.create.goggles.tooltip.behaviour2": "계측기가 연결된 네트워크의 _속도_나 _스트레스_의 자세한 정보를 보여줍니다.", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "WRENCH", "item.create.wrench.tooltip.summary": "장치 구성에 유용한 도구입니다. 장치를 _회전_, _설정_, _해체_하는 데 쓰입니다.", @@ -1804,6 +1809,480 @@ "create.tooltip.randomWipDescription7": "This one maybe isn't for you. What about that one?", "create.tooltip.randomWipDescription8": "Use it and regret your decision immediately.", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json index 80d9df613..f3dbea0b4 100644 --- a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json +++ b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 1172", + "_": "Missing Localizations: 1569", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,8 +67,6 @@ "block.create.creative_crate": "Bouwtekeningkannon Creatiefeerder", "block.create.creative_fluid_tank": "UNLOCALIZED: Creative Fluid Tank", "block.create.creative_motor": "UNLOCALIZED: Creative Motor", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", "block.create.crushing_wheel": "Verpulveraar", "block.create.crushing_wheel_controller": "UNLOCALIZED: Crushing Wheel Controller", "block.create.cuckoo_clock": "UNLOCALIZED: Cuckoo Clock", @@ -164,7 +162,7 @@ "block.create.gabbro_cobblestone_stairs": "UNLOCALIZED: Gabbro Cobblestone Stairs", "block.create.gabbro_cobblestone_wall": "UNLOCALIZED: Gabbro Cobblestone Wall", "block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar", - "block.create.gantry_pinion": "UNLOCALIZED: Gantry Pinion", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", "block.create.gearbox": "Versnellingsbak", "block.create.gearshift": "Versnellingspook", @@ -378,6 +376,7 @@ "block.create.spout": "UNLOCALIZED: Spout", "block.create.spruce_window": "UNLOCALIZED: Spruce Window", "block.create.spruce_window_pane": "UNLOCALIZED: Spruce Window Pane", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "Mechanische Zuiger", "block.create.stockpile_switch": "Voorraad Schakelaar", "block.create.stressometer": "Stressmeter", @@ -386,8 +385,6 @@ "block.create.turntable": "Draaischijf", "block.create.vertical_framed_glass": "UNLOCALIZED: Vertical Framed Glass", "block.create.vertical_framed_glass_pane": "UNLOCALIZED: Vertical Framed Glass Pane", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", "block.create.water_wheel": "Waterrad", "block.create.weathered_limestone": "Verweerde Kalksteen", "block.create.weathered_limestone_bricks": "Verweerde Kalksteenstenen", @@ -433,6 +430,7 @@ "item.create.builders_tea": "UNLOCALIZED: Builder's Tea", "item.create.chest_minecart_contraption": "UNLOCALIZED: Chest Minecart Contraption", "item.create.chocolate_bucket": "UNLOCALIZED: Chocolate Bucket", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "UNLOCALIZED: Chromatic Compound", "item.create.cinder_flour": "UNLOCALIZED: Cinder Flour", "item.create.copper_ingot": "Koperstaaf", @@ -466,6 +464,7 @@ "item.create.handheld_blockzapper": "Blokzapper", "item.create.handheld_worldshaper": "UNLOCALIZED: Handheld Worldshaper", "item.create.honey_bucket": "UNLOCALIZED: Honey Bucket", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "UNLOCALIZED: Integrated Circuit", "item.create.iron_sheet": "IJzeren Platen", "item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet", @@ -482,6 +481,7 @@ "item.create.schematic_and_quill": "Bouwtekening en Veer", "item.create.shadow_steel": "UNLOCALIZED: Shadow Steel", "item.create.super_glue": "UNLOCALIZED: Super Glue", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "Boom mest", "item.create.vertical_gearbox": "UNLOCALIZED: Vertical Gearbox", "item.create.wand_of_symmetry": "Symmetrie Staf", @@ -828,12 +828,15 @@ "create.gui.goggles.kinetic_stats": "UNLOCALIZED: Kinetic Stats:", "create.gui.goggles.at_current_speed": "UNLOCALIZED: at current speed", "create.gui.goggles.pole_length": "UNLOCALIZED: Pole Length:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "UNLOCALIZED: Gauge Information:", "create.gui.speedometer.title": "UNLOCALIZED: Rotation Speed", "create.gui.stressometer.title": "UNLOCALIZED: Network Stress", @@ -1450,6 +1453,8 @@ "item.create.goggles.tooltip.behaviour1": "Laat _gekleurde_ _indicaties_ zien die corresponderen met de _Snelheid_ van een geplaatst kinetisch onderdeel.", "item.create.goggles.tooltip.condition2": "UNLOCALIZED: When looking at gauge", "item.create.goggles.tooltip.behaviour2": "UNLOCALIZED: Shows detailed information about _Speed_ or _Stress_ of the network to which the gauge is connected.", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "UNLOCALIZED: WRENCH", "item.create.wrench.tooltip.summary": "UNLOCALIZED: A useful tool for working on kinetic contraptions. Can be used to _Rotate_, _Dismantle_ and to _Configure_ components.", @@ -1804,6 +1809,480 @@ "create.tooltip.randomWipDescription7": "Deze is misschien niet geschikt voor jou.", "create.tooltip.randomWipDescription8": "Gebruikt het en je zal meteen spijt hebben.", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_br.json b/src/generated/resources/assets/create/lang/unfinished/pt_br.json index 0ad6e7552..659fc213b 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pt_br.json +++ b/src/generated/resources/assets/create/lang/unfinished/pt_br.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 1238", + "_": "Missing Localizations: 1635", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,8 +67,6 @@ "block.create.creative_crate": "Criativador Esquemaannon", "block.create.creative_fluid_tank": "UNLOCALIZED: Creative Fluid Tank", "block.create.creative_motor": "UNLOCALIZED: Creative Motor", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", "block.create.crushing_wheel": "Roda de Moer", "block.create.crushing_wheel_controller": "UNLOCALIZED: Crushing Wheel Controller", "block.create.cuckoo_clock": "UNLOCALIZED: Cuckoo Clock", @@ -164,7 +162,7 @@ "block.create.gabbro_cobblestone_stairs": "UNLOCALIZED: Gabbro Cobblestone Stairs", "block.create.gabbro_cobblestone_wall": "UNLOCALIZED: Gabbro Cobblestone Wall", "block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar", - "block.create.gantry_pinion": "UNLOCALIZED: Gantry Pinion", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", "block.create.gearbox": "Caixa de Transmissão", "block.create.gearshift": "Câmbio", @@ -378,6 +376,7 @@ "block.create.spout": "UNLOCALIZED: Spout", "block.create.spruce_window": "UNLOCALIZED: Spruce Window", "block.create.spruce_window_pane": "UNLOCALIZED: Spruce Window Pane", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "Pistão Mecânico Grudento", "block.create.stockpile_switch": "Disjuntor de Armazenamento", "block.create.stressometer": "UNLOCALIZED: Stressometer", @@ -386,8 +385,6 @@ "block.create.turntable": "Mesa giratória", "block.create.vertical_framed_glass": "UNLOCALIZED: Vertical Framed Glass", "block.create.vertical_framed_glass_pane": "UNLOCALIZED: Vertical Framed Glass Pane", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", "block.create.water_wheel": "Roda de Água", "block.create.weathered_limestone": "Calcário Resistido", "block.create.weathered_limestone_bricks": "Tijolos de Calcário Resistido", @@ -433,6 +430,7 @@ "item.create.builders_tea": "UNLOCALIZED: Builder's Tea", "item.create.chest_minecart_contraption": "UNLOCALIZED: Chest Minecart Contraption", "item.create.chocolate_bucket": "UNLOCALIZED: Chocolate Bucket", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "UNLOCALIZED: Chromatic Compound", "item.create.cinder_flour": "UNLOCALIZED: Cinder Flour", "item.create.copper_ingot": "UNLOCALIZED: Copper Ingot", @@ -466,6 +464,7 @@ "item.create.handheld_blockzapper": "Blockzapper Portátil", "item.create.handheld_worldshaper": "UNLOCALIZED: Handheld Worldshaper", "item.create.honey_bucket": "UNLOCALIZED: Honey Bucket", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "UNLOCALIZED: Integrated Circuit", "item.create.iron_sheet": "Placas de Ferro", "item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet", @@ -482,6 +481,7 @@ "item.create.schematic_and_quill": "Esquema e pena", "item.create.shadow_steel": "UNLOCALIZED: Shadow Steel", "item.create.super_glue": "UNLOCALIZED: Super Glue", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "Fertilizante de Árvore", "item.create.vertical_gearbox": "UNLOCALIZED: Vertical Gearbox", "item.create.wand_of_symmetry": "Varinha de Simetria", @@ -828,12 +828,15 @@ "create.gui.goggles.kinetic_stats": "UNLOCALIZED: Kinetic Stats:", "create.gui.goggles.at_current_speed": "UNLOCALIZED: at current speed", "create.gui.goggles.pole_length": "UNLOCALIZED: Pole Length:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "UNLOCALIZED: Gauge Information:", "create.gui.speedometer.title": "UNLOCALIZED: Rotation Speed", "create.gui.stressometer.title": "UNLOCALIZED: Network Stress", @@ -1450,6 +1453,8 @@ "item.create.goggles.tooltip.behaviour1": "UNLOCALIZED: Shows _colored indicators_ corresponding to the _Speed Level_ of a placed kinetic component as well as _Stress Impact_ and _Capacity_ of individual components.", "item.create.goggles.tooltip.condition2": "UNLOCALIZED: When looking at gauge", "item.create.goggles.tooltip.behaviour2": "UNLOCALIZED: Shows detailed information about _Speed_ or _Stress_ of the network to which the gauge is connected.", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "UNLOCALIZED: WRENCH", "item.create.wrench.tooltip.summary": "UNLOCALIZED: A useful tool for working on kinetic contraptions. Can be used to _Rotate_, _Dismantle_ and to _Configure_ components.", @@ -1804,6 +1809,480 @@ "create.tooltip.randomWipDescription7": "UNLOCALIZED: This one maybe isn't for you. What about that one?", "create.tooltip.randomWipDescription8": "UNLOCALIZED: Use it and regret your decision immediately.", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json index 1b64b7410..f9e6e8209 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json +++ b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 20", + "_": "Missing Localizations: 421", "_": "->------------------------] Game Elements [------------------------<-", @@ -164,7 +164,7 @@ "block.create.gabbro_cobblestone_stairs": "Ступени из габбро-булыжника", "block.create.gabbro_cobblestone_wall": "Стена из габбро-булыжника", "block.create.gabbro_pillar": "Габбро колонна", - "block.create.gantry_pinion": "UNLOCALIZED: Gantry Pinion", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", "block.create.gearbox": "Коробка передач", "block.create.gearshift": "Реверсивный механизм", @@ -378,6 +378,7 @@ "block.create.spout": "Дозатор", "block.create.spruce_window": "Еловое окно", "block.create.spruce_window_pane": "Панель из елового окна", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "Липкий механический поршень", "block.create.stockpile_switch": "Настраиваемый компаратор", "block.create.stressometer": "Динамометр", @@ -433,6 +434,7 @@ "item.create.builders_tea": "Чай Строителя", "item.create.chest_minecart_contraption": "Сундуко-вагонеточная штуковина", "item.create.chocolate_bucket": "Ведро шоколада", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "Хроматический компаунд", "item.create.cinder_flour": "Незераковая пыль", "item.create.copper_ingot": "Медный слиток", @@ -466,6 +468,7 @@ "item.create.handheld_blockzapper": "Ручная блоковая пушка", "item.create.handheld_worldshaper": "Ручной редактор мира", "item.create.honey_bucket": "Ведро мёда", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "Интегральная схема", "item.create.iron_sheet": "Железный лист", "item.create.lapis_sheet": "Лазуритовый лист", @@ -482,6 +485,7 @@ "item.create.schematic_and_quill": "Схематика и перо", "item.create.shadow_steel": "Призрачная сталь", "item.create.super_glue": "Супер-клей", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "Удобрение для деревьев", "item.create.vertical_gearbox": "Вертикальная коробка передач", "item.create.wand_of_symmetry": "Жезл симметрии", @@ -777,7 +781,7 @@ "create.gui.terrainzapper.tool.overlay": "Наложение", "create.gui.terrainzapper.tool.flatten": "Выравнивание", - "create.terrainzapper.shiftRightClickToSet": "ПКМ крадясь, чтобы выбрать форму", + "create.terrainzapper.shiftRightClickToSet": "ПКМ крадучись, чтобы выбрать форму", "create.blockzapper.usingBlock": "С помощью: %1$s", "create.blockzapper.componentUpgrades": "Обновления компонентов:", @@ -828,12 +832,15 @@ "create.gui.goggles.kinetic_stats": "Кинетическая статистика:", "create.gui.goggles.at_current_speed": "На текущей скорости", "create.gui.goggles.pole_length": "Длина поршня", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "Калибровочная информация:", "create.gui.speedometer.title": "Скорость вращения", "create.gui.stressometer.title": "Сетевой момент", @@ -1321,7 +1328,7 @@ "item.create.wand_of_symmetry.tooltip.action1": "_Создаёт_ или _Перемещает_ зеркало", "item.create.wand_of_symmetry.tooltip.control2": "ПКМ в воздух", "item.create.wand_of_symmetry.tooltip.action2": "_Убирает_ зеркало", - "item.create.wand_of_symmetry.tooltip.control3": "ПКМ крадясь", + "item.create.wand_of_symmetry.tooltip.control3": "ПКМ крадучись", "item.create.wand_of_symmetry.tooltip.action3": "Открывает _интерфейс_ _конфигурации_", "item.create.handheld_blockzapper.tooltip": "BLOCKZAPPER", @@ -1330,7 +1337,7 @@ "item.create.handheld_blockzapper.tooltip.action1": "Устанавливает выбранный блок как материал.", "item.create.handheld_blockzapper.tooltip.control2": "ПКМ на блок", "item.create.handheld_blockzapper.tooltip.action2": "_Размещает_ или _Замещает_ блок.", - "item.create.handheld_blockzapper.tooltip.control3": "ПКМ крадясь", + "item.create.handheld_blockzapper.tooltip.control3": "ПКМ крадучись", "item.create.handheld_blockzapper.tooltip.action3": "Открывает _интерфейс_ _конфигурации_", "item.create.handheld_worldshaper.tooltip": "HANDHELD WORLDSHAPER", @@ -1339,7 +1346,7 @@ "item.create.handheld_worldshaper.tooltip.action1": "Устанавливает блоки, помещенные инструментом, в целевой блок.", "item.create.handheld_worldshaper.tooltip.control2": "ПКМ на блок", "item.create.handheld_worldshaper.tooltip.action2": "Применяет выбранную _кисть_ и _инструмент_ в выбранном месте.", - "item.create.handheld_worldshaper.tooltip.control3": "ПКМ крадясь", + "item.create.handheld_worldshaper.tooltip.control3": "ПКМ крадучись", "item.create.handheld_worldshaper.tooltip.action3": "Открывает _интерфейс_ _конфигурации_", "item.create.tree_fertilizer.tooltip": "TREE FERTILIZER", @@ -1376,7 +1383,7 @@ "item.create.schematic.tooltip.summary": "Содержит структуру, которая будет позиционироваться и помещаться в мир. Расположите голограмму по своему усмотрению и используйте _схематичную пушку_ для ее построения.", "item.create.schematic.tooltip.condition1": "При удерживании", "item.create.schematic.tooltip.behaviour1": "Может быть позиционирован с помощью инструментов на экране.", - "item.create.schematic.tooltip.control1": "ПКМ крадясь", + "item.create.schematic.tooltip.control1": "ПКМ крадучись", "item.create.schematic.tooltip.action1": "Открывает _интерфейс_ для ввода _точных_ _координат_.", "item.create.schematic_and_quill.tooltip": "SCHEMATIC AND QUILL", @@ -1389,7 +1396,7 @@ "item.create.schematic_and_quill.tooltip.action1": "Выберите угловые точки / подтвердите сохранение.", "item.create.schematic_and_quill.tooltip.control2": "Удержание Ctrl", "item.create.schematic_and_quill.tooltip.action2": "Выберите точки в воздухе. Прокрутка для настройки расстояния.", - "item.create.schematic_and_quill.tooltip.control3": "ПКМ крадясь", + "item.create.schematic_and_quill.tooltip.control3": "ПКМ крадучись", "item.create.schematic_and_quill.tooltip.action3": "_Сбрасывает_ и _удаляет_ выделение.", "block.create.schematicannon.tooltip": "SCHEMATICANNON", @@ -1441,7 +1448,7 @@ "item.create.belt_connector.tooltip.summary": "Соединяет _2_ _Вала_ с помощью _механического_ _ремня_._ Соединённые валы будут иметь одинаковые _скорость_ и _направление_ _вращения._ Лента может служить как _конвейер_ для _транспортировки._", "item.create.belt_connector.tooltip.control1": "ПКМ по валу", "item.create.belt_connector.tooltip.action1": "Выбирает вал в качестве одного шкива конвейера. Оба выбранных вала должны быть _на_ _одной_ _линии_ _вертикально,_ _горизонтально_ либо _диагонально_ по направлению конвейера.", - "item.create.belt_connector.tooltip.control2": "ПКМ крадясь", + "item.create.belt_connector.tooltip.control2": "ПКМ крадучись", "item.create.belt_connector.tooltip.action2": "_Сбрасывает_ первый выбранный шкив для конвейера.", "item.create.goggles.tooltip": "GOGGLES", @@ -1450,12 +1457,14 @@ "item.create.goggles.tooltip.behaviour1": "Показывает _цветные_ _индикаторы_, соответствующие _уровню_ _скорости_ размещённого кинетического компонента, а также воздействию момента и мощности отдельных компонентов.", "item.create.goggles.tooltip.condition2": "При взгляде на датчик", "item.create.goggles.tooltip.behaviour2": "Показывает подробную информацию о скорости или моменте сети, к которой подключён датчик.", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "WRENCH", "item.create.wrench.tooltip.summary": "Полезный _инструмент_ для работы с _кинетическими_ штуковинами. Может использоваться для _поворота_, _демонтажа_ и _настройки_ компонентов.", "item.create.wrench.tooltip.control1": "ПКМ по кинетическому блоку", "item.create.wrench.tooltip.action1": "_Поворачивает_ _компонент_ с которым вы взаимодействуете _к_ _лицу_ или _от_ _лица_.", - "item.create.wrench.tooltip.control2": "ПКМ крадясь", + "item.create.wrench.tooltip.control2": "ПКМ крадучись", "item.create.wrench.tooltip.action2": "Разбирает кинетические компоненты и помещает их обратно в ваш инвентарь.", "block.create.creative_motor.tooltip": "CREATIVE MOTOR", @@ -1688,10 +1697,10 @@ "block.create.redstone_link.tooltip": "REDSTONE LINK", "block.create.redstone_link.tooltip.summary": "_Беспроводной_ _передатчик_ сигнала красного камня. Можно выбрать _частоты_ с помощью любого предмета. Диапазон сигнала ограничен, но достаточно далёк.", "block.create.redstone_link.tooltip.condition1": "Когда приведен в действие", - "block.create.redstone_link.tooltip.behaviour1": "Приняв сигнал той-же _частоты_ выдаёт сигнал красного камня или наоборот.", + "block.create.redstone_link.tooltip.behaviour1": "Приняв сигнал той же _частоты_ выдаёт сигнал красного камня или наоборот.", "block.create.redstone_link.tooltip.control1": "При ПКМ предметом", "block.create.redstone_link.tooltip.action1": "Устанавливает частоту для этого предмета. Всего _два_ разных предмета могут быть использованы в комбинации для определения частоты.", - "block.create.redstone_link.tooltip.control2": "ПКМ крадясь", + "block.create.redstone_link.tooltip.control2": "ПКМ крадучись", "block.create.redstone_link.tooltip.action2": "Переключение между режимом _приемника_ и _передатчика_.", "block.create.nixie_tube.tooltip": "NIXIE TUBE", @@ -1804,6 +1813,480 @@ "create.tooltip.randomWipDescription7": "Этот, возможно, но не для тебя. Как насчет этого?", "create.tooltip.randomWipDescription8": "Используя его, вы немедленно пожалеете о своем решении.", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json index 12f517439..f1d61e276 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 18", + "_": "Missing Localizations: 419", "_": "->------------------------] Game Elements [------------------------<-", @@ -164,7 +164,7 @@ "block.create.gabbro_cobblestone_stairs": "辉长岩圆石楼梯", "block.create.gabbro_cobblestone_wall": "辉长岩圆石墙", "block.create.gabbro_pillar": "竖纹辉长岩", - "block.create.gantry_pinion": "UNLOCALIZED: Gantry Pinion", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", "block.create.gearbox": "十字齿轮箱", "block.create.gearshift": "反转齿轮箱", @@ -378,6 +378,7 @@ "block.create.spout": "注液器", "block.create.spruce_window": "云杉窗户", "block.create.spruce_window_pane": "云杉窗户板", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "黏性动力活塞", "block.create.stockpile_switch": "存量转换器", "block.create.stressometer": "应力表", @@ -433,6 +434,7 @@ "item.create.builders_tea": "建造工茶饮", "item.create.chest_minecart_contraption": "装配过的动力矿车", "item.create.chocolate_bucket": "巧克力桶", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "异彩化合物", "item.create.cinder_flour": "下界面粉", "item.create.copper_ingot": "铜锭", @@ -466,6 +468,7 @@ "item.create.handheld_blockzapper": "手持式方块放置器", "item.create.handheld_worldshaper": "手持式环境塑形器", "item.create.honey_bucket": "蜂蜜桶", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "集成电路板", "item.create.iron_sheet": "铁板", "item.create.lapis_sheet": "青金石板", @@ -482,6 +485,7 @@ "item.create.schematic_and_quill": "蓝图与笔", "item.create.shadow_steel": "暗影钢", "item.create.super_glue": "强力胶", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "树木肥料", "item.create.vertical_gearbox": "竖直十字齿轮箱", "item.create.wand_of_symmetry": "对称之杖", @@ -828,12 +832,15 @@ "create.gui.goggles.kinetic_stats": "动力学状态:", "create.gui.goggles.at_current_speed": "当前速度应力值", "create.gui.goggles.pole_length": "活塞杆长度:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "仪表信息:", "create.gui.speedometer.title": "旋转速度", "create.gui.stressometer.title": "网络应力", @@ -1450,6 +1457,8 @@ "item.create.goggles.tooltip.behaviour1": "根据对应动力组件的_转速等级_,显示它的_颜色指示器_,也会显示这个组件的_应力影响_以及_应力量_。", "item.create.goggles.tooltip.condition2": "当看向仪表时", "item.create.goggles.tooltip.behaviour2": "将会显示与仪表相连的网络的_转速_、_应力_等详细信息。", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "扳手", "item.create.wrench.tooltip.summary": "操控动力组件的使用工具。可用于_旋转_,_拆除_以及_配置_组件。", @@ -1804,6 +1813,480 @@ "create.tooltip.randomWipDescription7": "这玩意不是给你用的,换个吧", "create.tooltip.randomWipDescription8": "试试就逝世。", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json index 81dd8497e..e104da324 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 23", + "_": "Missing Localizations: 424", "_": "->------------------------] Game Elements [------------------------<-", @@ -164,7 +164,7 @@ "block.create.gabbro_cobblestone_stairs": "碎輝長岩樓梯", "block.create.gabbro_cobblestone_wall": "碎輝長岩牆", "block.create.gabbro_pillar": "豎紋輝長岩", - "block.create.gantry_pinion": "UNLOCALIZED: Gantry Pinion", + "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", "block.create.gearbox": "齒輪箱", "block.create.gearshift": "變速箱", @@ -378,6 +378,7 @@ "block.create.spout": "液體灌注器", "block.create.spruce_window": "雲杉木窗戶", "block.create.spruce_window_pane": "雲杉木窗戶片", + "block.create.sticker": "UNLOCALIZED: Sticker", "block.create.sticky_mechanical_piston": "黏性機械活塞", "block.create.stockpile_switch": "存量檢測器", "block.create.stressometer": "動能錶", @@ -433,6 +434,7 @@ "item.create.builders_tea": "工人茶", "item.create.chest_minecart_contraption": "裝修過的機械礦車", "item.create.chocolate_bucket": "巧克力桶", + "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", "item.create.chromatic_compound": "異彩化合物", "item.create.cinder_flour": "地獄麵粉", "item.create.copper_ingot": "銅錠", @@ -466,6 +468,7 @@ "item.create.handheld_blockzapper": "方塊放置器", "item.create.handheld_worldshaper": "地形雕塑器", "item.create.honey_bucket": "蜂蜜桶", + "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", "item.create.integrated_circuit": "IC板", "item.create.iron_sheet": "鐵板", "item.create.lapis_sheet": "青金石板", @@ -482,6 +485,7 @@ "item.create.schematic_and_quill": "藍圖與筆", "item.create.shadow_steel": "暗影鋼", "item.create.super_glue": "強力膠", + "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", "item.create.tree_fertilizer": "樹木肥料", "item.create.vertical_gearbox": "豎直齒輪箱", "item.create.wand_of_symmetry": "對稱杖", @@ -828,12 +832,15 @@ "create.gui.goggles.kinetic_stats": "機械學狀態:", "create.gui.goggles.at_current_speed": "現在速度動能值", "create.gui.goggles.pole_length": "UNLOCALIZED: Pole Length:", + "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "儀表訊息:", "create.gui.speedometer.title": "旋轉速度", "create.gui.stressometer.title": "網路動能", @@ -1450,6 +1457,8 @@ "item.create.goggles.tooltip.behaviour1": "將會展示該機械元件的_速度_、_動能_等數值", "item.create.goggles.tooltip.condition2": "當裝備後看向儀表時", "item.create.goggles.tooltip.behaviour2": "將會展示該儀表所連接網路的_速度_、_動能_等數值。", + "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "板手", "item.create.wrench.tooltip.summary": "一種常用的工具,能夠調整_動能_的_方向_、_配置_等。", @@ -1804,6 +1813,480 @@ "create.tooltip.randomWipDescription7": "這東西不是給你用的,再找找吧!", "create.tooltip.randomWipDescription8": "用了就死定了。", + + "_": "->------------------------] Ponder Content [------------------------<-", + + "create.ponder.hold_to_ponder": "UNLOCALIZED: Hold [%1$s] to Ponder", + "create.ponder.subject": "UNLOCALIZED: Subject of this scene", + "create.ponder.pondering": "UNLOCALIZED: Pondering about...", + "create.ponder.identify_mode": "UNLOCALIZED: Identify mode active.\nUnpause with [%1$s]", + "create.ponder.associated": "UNLOCALIZED: Associated Entries", + "create.ponder.close": "UNLOCALIZED: Close", + "create.ponder.identify": "UNLOCALIZED: Identify", + "create.ponder.next": "UNLOCALIZED: Next Scene", + "create.ponder.previous": "UNLOCALIZED: Previous Scene", + "create.ponder.replay": "UNLOCALIZED: Replay", + "create.ponder.think_back": "UNLOCALIZED: Think Back", + "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Chassis or Super Glue, larger structures can be moved.", + "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", + "create.ponder.shared.sneak_and": "UNLOCALIZED: Sneak +", + "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", + "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", + "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", + "create.ponder.shared.ctrl_and": "UNLOCALIZED: Ctrl +", + "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", + "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", + "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", + "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", + "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", + "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", + "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", + "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", + "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", + "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", + "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", + "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", + "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", + "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", + "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", + "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", + "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", + "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", + "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", + "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", + "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", + "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", + "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", + "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", + "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", + + "create.ponder.adjustable_pulse_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Pulse Repeaters", + "create.ponder.adjustable_pulse_repeater.text_1": "UNLOCALIZED: Adjustable Pulse Repeaters emit a short pulse at a delay", + "create.ponder.adjustable_pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.adjustable_repeater.header": "UNLOCALIZED: Controlling signals using Adjustable Repeaters", + "create.ponder.adjustable_repeater.text_1": "UNLOCALIZED: Adjustable Repeaters behave similarly to regular Repeaters", + "create.ponder.adjustable_repeater.text_2": "UNLOCALIZED: They charge up for a set time...", + "create.ponder.adjustable_repeater.text_3": "UNLOCALIZED: ...and cool down for the same duration", + "create.ponder.adjustable_repeater.text_4": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", + "create.ponder.adjustable_repeater.text_5": "UNLOCALIZED: Configured delays can range up to 30 minutes", + + "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", + "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", + "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", + "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", + + "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", + "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", + "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", + + "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", + "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", + "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", + + "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", + "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", + "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", + "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", + "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", + "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", + "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", + + "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", + "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", + "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", + "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", + "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", + "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", + "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions.\nBelts can span any Length between 2 and 20 blocks", + + "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", + "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", + "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", + + "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", + "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", + "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", + "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", + + "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", + "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", + "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", + "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", + + "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", + "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", + "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", + "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", + + "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", + "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", + "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", + + "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", + "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", + "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", + "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", + "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + + "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", + "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", + "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", + "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", + + "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", + "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exacly like Chain Drives", + "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", + "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", + "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", + "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", + "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", + + "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", + "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", + "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", + "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", + "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", + "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", + "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", + "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure the two Structures are not attached to each other through super glue or similar", + "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", + + "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", + "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", + "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", + + "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", + "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", + "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", + "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", + + "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", + "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", + "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", + + "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", + "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", + "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", + + "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", + "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", + "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", + "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", + "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", + "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", + "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", + "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", + "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", + "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", + "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", + "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", + "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", + "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", + "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", + "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", + + "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", + "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", + "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", + "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", + + "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", + "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", + "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", + + "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", + "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", + "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", + "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", + + "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", + "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", + "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", + + "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", + "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", + "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", + "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", + "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", + "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", + "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", + "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", + "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", + + "create.ponder.fan_source.header": "UNLOCALIZED: Generating Rotational Force using Encased Fans", + "create.ponder.fan_source.text_1": "UNLOCALIZED: Fans facing down into a source of heat can provide Rotational Force", + "create.ponder.fan_source.text_2": "UNLOCALIZED: When given a Redstone Signal, the Fans will start providing power", + + "create.ponder.flywheel.header": "UNLOCALIZED: Generating Rotational Force using the Flywheel", + "create.ponder.flywheel.text_1": "UNLOCALIZED: Flywheels are required for generating rotational force with the Furnace Engine", + "create.ponder.flywheel.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.flywheel.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", + "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", + "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", + "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", + "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", + + "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", + "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", + "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", + "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", + "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", + "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", + + "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", + "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", + + "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", + "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting.", + + "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", + "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", + "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", + "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement.\nA mechanical belt should help here.", + + "create.ponder.furnace_engine.header": "UNLOCALIZED: Generating Rotational Force using the Furnace Engine", + "create.ponder.furnace_engine.text_1": "UNLOCALIZED: Furnace Engines generate Rotational Force while their attached Furnace is running", + "create.ponder.furnace_engine.text_2": "UNLOCALIZED: The provided Rotational Force has a very large stress capacity", + "create.ponder.furnace_engine.text_3": "UNLOCALIZED: Using a Blast Furnace will double the efficiency of the Engine", + + "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", + "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", + "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", + "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", + "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", + "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", + + "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", + "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", + "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", + "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", + "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", + + "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", + "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", + "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", + + "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", + "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", + "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", + + "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", + "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", + "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", + "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", + "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", + + "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", + "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", + "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", + + "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", + "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", + "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", + "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + + "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", + "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", + "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", + + "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", + "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", + "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", + "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", + "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", + "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", + "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", + + "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", + "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", + "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", + + "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", + "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", + "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", + + "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", + "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", + "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", + + "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", + "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", + "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", + + "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", + "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", + "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", + + "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", + "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", + "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", + "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", + + "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", + "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", + "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", + "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", + "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", + "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", + "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", + + "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", + "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", + "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", + + "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", + "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", + "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", + + "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", + "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", + "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", + "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", + "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", + "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", + + "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", + "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", + "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", + + "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", + "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", + "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", + "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", + "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", + "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", + "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", + "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", + + "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", + "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", + + "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", + "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", + "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", + "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", + "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", + + "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", + "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", + "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", + "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", + "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", + + "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", + "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters will shorten any redstone signal to a single pulse", + + "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", + "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", + "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", + "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", + "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", + "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", + "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", + "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", + "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", + "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", + + "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", + "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", + "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", + + "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", + "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", + "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", + "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", + "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", + "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", + "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", + + "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", + "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", + "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", + + "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", + "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", + "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", + "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", + + "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", + "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", + "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", + + "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", + "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", + "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", + + "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", + "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", + "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", + "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", + "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", + "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", + + "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", + "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", + + "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", + "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", + + "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", + "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", + "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", + "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", + "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", + + "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", + "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", + "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", + "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", + "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", + + "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", + "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue can be used between any two blocks", + "create.ponder.super_glue.text_2": "UNLOCALIZED: The attached blocks will move together when assembled into a Contraption", + "create.ponder.super_glue.text_3": "UNLOCALIZED: Whenever Super Glue is held in the off-hand...", + "create.ponder.super_glue.text_4": "UNLOCALIZED: ...added blocks will be glued to the face they were placed on automatically", + "create.ponder.super_glue.text_5": "UNLOCALIZED: Super Glue can be removed with Left-Click", + + "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", + "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", + "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", + "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", + "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", + + "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", + "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", + "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", + "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", + "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", + + "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", + "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", + "create.ponder.windmill_source.text_2": "UNLOCALIZED: If enough Sail-like blocks are attached to the block, it can act as a Windmill", + "create.ponder.windmill_source.text_3": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", + "create.ponder.windmill_source.text_4": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", + "create.ponder.windmill_source.text_5": "UNLOCALIZED: Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", + + "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", + "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", + "_": "Thank you for translating Create!" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_pull.json b/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_pull.json deleted file mode 100644 index bdbb2623f..000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_pull.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_ceiling", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel", - "5": "create:block/andesite_funnel_tall", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_pull_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_pull_powered.json deleted file mode 100644 index f66c6e8f3..000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_pull_powered.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_ceiling", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel_powered", - "5": "create:block/andesite_funnel_tall_powered", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_push.json b/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_push.json deleted file mode 100644 index 8217c6b7a..000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_push.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_ceiling", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel", - "5": "create:block/andesite_funnel_tall", - "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_floor_pull_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_floor_pull_powered.json deleted file mode 100644 index 5ac3f88c7..000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_floor_pull_powered.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_floor", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel_powered", - "5": "create:block/andesite_funnel_tall_powered", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_floor_push_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_floor_push_powered.json deleted file mode 100644 index 8a8f6a8de..000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_floor_push_powered.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_floor", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel_powered", - "5": "create:block/andesite_funnel_tall_powered", - "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_floor_pull.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull.json similarity index 60% rename from src/generated/resources/assets/create/models/block/andesite_funnel_floor_pull.json rename to src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull.json index 6079531b3..4ca78f3ab 100644 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_floor_pull.json +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull.json @@ -1,11 +1,11 @@ { - "parent": "create:block/funnel/block_floor", + "parent": "create:block/funnel/block_horizontal", "textures": { "particle": "create:block/andesite_casing", "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel", "5": "create:block/andesite_funnel_tall", "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back" + "3": "create:block/andesite_funnel_back", + "6": "create:block/andesite_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_wall_pull_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_powered.json similarity index 60% rename from src/generated/resources/assets/create/models/block/andesite_funnel_wall_pull_powered.json rename to src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_powered.json index e71c4c17c..f30214bd6 100644 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_wall_pull_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_powered.json @@ -1,11 +1,11 @@ { - "parent": "create:block/funnel/block_wall", + "parent": "create:block/funnel/block_horizontal", "textures": { "particle": "create:block/andesite_casing", "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel_powered", "5": "create:block/andesite_funnel_tall_powered", "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back" + "3": "create:block/andesite_funnel_back", + "6": "create:block/andesite_funnel_powered" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_floor_push.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push.json similarity index 60% rename from src/generated/resources/assets/create/models/block/andesite_funnel_floor_push.json rename to src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push.json index 21b19aa78..090a3e964 100644 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_floor_push.json +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push.json @@ -1,11 +1,11 @@ { - "parent": "create:block/funnel/block_floor", + "parent": "create:block/funnel/block_horizontal", "textures": { "particle": "create:block/andesite_casing", "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel", "5": "create:block/andesite_funnel_tall", "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back" + "3": "create:block/andesite_funnel_back", + "6": "create:block/andesite_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_push_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_powered.json similarity index 60% rename from src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_push_powered.json rename to src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_powered.json index ff4df0493..3907df971 100644 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_ceiling_push_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_powered.json @@ -1,11 +1,11 @@ { - "parent": "create:block/funnel/block_ceiling", + "parent": "create:block/funnel/block_horizontal", "textures": { "particle": "create:block/andesite_casing", "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel_powered", "5": "create:block/andesite_funnel_tall_powered", "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back" + "3": "create:block/andesite_funnel_back", + "6": "create:block/andesite_funnel_powered" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull.json new file mode 100644 index 000000000..a05b1954a --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull.json @@ -0,0 +1,13 @@ +{ + "parent": "create:block/funnel/block_vertical_filterless", + "textures": { + "particle": "create:block/andesite_casing", + "7": "create:block/andesite_funnel_plating", + "5": "create:block/andesite_funnel_tall", + "2_2": "create:block/andesite_funnel_pull", + "3": "create:block/andesite_funnel_back", + "8": "create:block/andesite_casing", + "9": "create:block/andesite_funnel_slope", + "10": "create:block/funnel_open" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_powered.json new file mode 100644 index 000000000..979f71145 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_powered.json @@ -0,0 +1,13 @@ +{ + "parent": "create:block/funnel/block_vertical_filterless", + "textures": { + "particle": "create:block/andesite_casing", + "7": "create:block/andesite_funnel_plating", + "5": "create:block/andesite_funnel_tall_powered", + "2_2": "create:block/andesite_funnel_pull", + "3": "create:block/andesite_funnel_back", + "8": "create:block/andesite_casing", + "9": "create:block/andesite_funnel_slope", + "10": "create:block/funnel_closed" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push.json new file mode 100644 index 000000000..ef3fe4431 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push.json @@ -0,0 +1,13 @@ +{ + "parent": "create:block/funnel/block_vertical_filterless", + "textures": { + "particle": "create:block/andesite_casing", + "7": "create:block/andesite_funnel_plating", + "5": "create:block/andesite_funnel_tall", + "2_2": "create:block/andesite_funnel_push", + "3": "create:block/andesite_funnel_back", + "8": "create:block/andesite_casing", + "9": "create:block/andesite_funnel_slope", + "10": "create:block/funnel_open" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_powered.json new file mode 100644 index 000000000..4afdf8a20 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_powered.json @@ -0,0 +1,13 @@ +{ + "parent": "create:block/funnel/block_vertical_filterless", + "textures": { + "particle": "create:block/andesite_casing", + "7": "create:block/andesite_funnel_plating", + "5": "create:block/andesite_funnel_tall_powered", + "2_2": "create:block/andesite_funnel_push", + "3": "create:block/andesite_funnel_back", + "8": "create:block/andesite_casing", + "9": "create:block/andesite_funnel_slope", + "10": "create:block/funnel_closed" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_wall_pull.json b/src/generated/resources/assets/create/models/block/andesite_funnel_wall_pull.json deleted file mode 100644 index e8343d682..000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_wall_pull.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_wall", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel", - "5": "create:block/andesite_funnel_tall", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_wall_push.json b/src/generated/resources/assets/create/models/block/andesite_funnel_wall_push.json deleted file mode 100644 index 4b56f936a..000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_wall_push.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_wall", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel", - "5": "create:block/andesite_funnel_tall", - "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_wall_push_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_wall_push_powered.json deleted file mode 100644 index b9f6af0dc..000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_wall_push_powered.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_wall", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "6": "create:block/andesite_funnel_powered", - "5": "create:block/andesite_funnel_tall_powered", - "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_pull_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_pull_powered.json deleted file mode 100644 index 4a0c7c1d2..000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_pull_powered.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_ceiling", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel_powered", - "5": "create:block/brass_funnel_tall_powered", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_push.json b/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_push.json deleted file mode 100644 index c1595bbd8..000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_push.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_ceiling", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel", - "5": "create:block/brass_funnel_tall", - "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_push_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_push_powered.json deleted file mode 100644 index e4b8a8e16..000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_push_powered.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_ceiling", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel_powered", - "5": "create:block/brass_funnel_tall_powered", - "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_floor_pull.json b/src/generated/resources/assets/create/models/block/brass_funnel_floor_pull.json deleted file mode 100644 index 02c4f8743..000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_floor_pull.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_floor", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel", - "5": "create:block/brass_funnel_tall", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_floor_push.json b/src/generated/resources/assets/create/models/block/brass_funnel_floor_push.json deleted file mode 100644 index 642f3480b..000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_floor_push.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_floor", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel", - "5": "create:block/brass_funnel_tall", - "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_floor_push_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_floor_push_powered.json deleted file mode 100644 index 1e1c45148..000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_floor_push_powered.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_floor", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel_powered", - "5": "create:block/brass_funnel_tall_powered", - "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_pull.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull.json similarity index 60% rename from src/generated/resources/assets/create/models/block/brass_funnel_ceiling_pull.json rename to src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull.json index 04fb853ba..a971472b4 100644 --- a/src/generated/resources/assets/create/models/block/brass_funnel_ceiling_pull.json +++ b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull.json @@ -1,11 +1,11 @@ { - "parent": "create:block/funnel/block_ceiling", + "parent": "create:block/funnel/block_horizontal", "textures": { "particle": "create:block/brass_casing", "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel", "5": "create:block/brass_funnel_tall", "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back" + "3": "create:block/brass_funnel_back", + "6": "create:block/brass_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_floor_pull_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_powered.json similarity index 60% rename from src/generated/resources/assets/create/models/block/brass_funnel_floor_pull_powered.json rename to src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_powered.json index c16f1f997..38c8a7e7a 100644 --- a/src/generated/resources/assets/create/models/block/brass_funnel_floor_pull_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_powered.json @@ -1,11 +1,11 @@ { - "parent": "create:block/funnel/block_floor", + "parent": "create:block/funnel/block_horizontal", "textures": { "particle": "create:block/brass_casing", "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel_powered", "5": "create:block/brass_funnel_tall_powered", "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back" + "3": "create:block/brass_funnel_back", + "6": "create:block/brass_funnel_powered" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_wall_push.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push.json similarity index 60% rename from src/generated/resources/assets/create/models/block/brass_funnel_wall_push.json rename to src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push.json index f2f3bd158..85321b031 100644 --- a/src/generated/resources/assets/create/models/block/brass_funnel_wall_push.json +++ b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push.json @@ -1,11 +1,11 @@ { - "parent": "create:block/funnel/block_wall", + "parent": "create:block/funnel/block_horizontal", "textures": { "particle": "create:block/brass_casing", "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel", "5": "create:block/brass_funnel_tall", "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back" + "3": "create:block/brass_funnel_back", + "6": "create:block/brass_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_wall_push_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_powered.json similarity index 60% rename from src/generated/resources/assets/create/models/block/brass_funnel_wall_push_powered.json rename to src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_powered.json index 1a27b7333..83a796536 100644 --- a/src/generated/resources/assets/create/models/block/brass_funnel_wall_push_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_powered.json @@ -1,11 +1,11 @@ { - "parent": "create:block/funnel/block_wall", + "parent": "create:block/funnel/block_horizontal", "textures": { "particle": "create:block/brass_casing", "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel_powered", "5": "create:block/brass_funnel_tall_powered", "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back" + "3": "create:block/brass_funnel_back", + "6": "create:block/brass_funnel_powered" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull.json new file mode 100644 index 000000000..d2a1c6159 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull.json @@ -0,0 +1,13 @@ +{ + "parent": "create:block/funnel/block_vertical", + "textures": { + "particle": "create:block/brass_casing", + "7": "create:block/brass_funnel_plating", + "5": "create:block/brass_funnel_tall", + "2_2": "create:block/brass_funnel_pull", + "3": "create:block/brass_funnel_back", + "8": "create:block/brass_casing", + "9": "create:block/brass_funnel_slope", + "10": "create:block/funnel_open" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_powered.json new file mode 100644 index 000000000..e319cf39d --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_powered.json @@ -0,0 +1,13 @@ +{ + "parent": "create:block/funnel/block_vertical", + "textures": { + "particle": "create:block/brass_casing", + "7": "create:block/brass_funnel_plating", + "5": "create:block/brass_funnel_tall_powered", + "2_2": "create:block/brass_funnel_pull", + "3": "create:block/brass_funnel_back", + "8": "create:block/brass_casing", + "9": "create:block/brass_funnel_slope", + "10": "create:block/funnel_closed" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push.json new file mode 100644 index 000000000..f95cdf391 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push.json @@ -0,0 +1,13 @@ +{ + "parent": "create:block/funnel/block_vertical", + "textures": { + "particle": "create:block/brass_casing", + "7": "create:block/brass_funnel_plating", + "5": "create:block/brass_funnel_tall", + "2_2": "create:block/brass_funnel_push", + "3": "create:block/brass_funnel_back", + "8": "create:block/brass_casing", + "9": "create:block/brass_funnel_slope", + "10": "create:block/funnel_open" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_powered.json new file mode 100644 index 000000000..45ac7f48f --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_powered.json @@ -0,0 +1,13 @@ +{ + "parent": "create:block/funnel/block_vertical", + "textures": { + "particle": "create:block/brass_casing", + "7": "create:block/brass_funnel_plating", + "5": "create:block/brass_funnel_tall_powered", + "2_2": "create:block/brass_funnel_push", + "3": "create:block/brass_funnel_back", + "8": "create:block/brass_casing", + "9": "create:block/brass_funnel_slope", + "10": "create:block/funnel_closed" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_wall_pull.json b/src/generated/resources/assets/create/models/block/brass_funnel_wall_pull.json deleted file mode 100644 index 9b0bae0f1..000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_wall_pull.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_wall", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel", - "5": "create:block/brass_funnel_tall", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_wall_pull_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_wall_pull_powered.json deleted file mode 100644 index 03dc68716..000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_wall_pull_powered.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_wall", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "6": "create:block/brass_funnel_powered", - "5": "create:block/brass_funnel_tall_powered", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/chocolate_glazed_berries.json b/src/generated/resources/assets/create/models/item/chocolate_glazed_berries.json new file mode 100644 index 000000000..d556cc478 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/chocolate_glazed_berries.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/chocolate_glazed_berries" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/gantry_carriage.json b/src/generated/resources/assets/create/models/item/gantry_carriage.json new file mode 100644 index 000000000..7421b9883 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/gantry_carriage.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/gantry_carriage/item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/gantry_pinion.json b/src/generated/resources/assets/create/models/item/gantry_pinion.json deleted file mode 100644 index 55924eb15..000000000 --- a/src/generated/resources/assets/create/models/item/gantry_pinion.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "create:block/gantry_pinion/item" -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/goggles.json b/src/generated/resources/assets/create/models/item/goggles.json new file mode 100644 index 000000000..0ae90a266 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/goggles.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/goggles" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/honeyed_apple.json b/src/generated/resources/assets/create/models/item/honeyed_apple.json new file mode 100644 index 000000000..9940c5fab --- /dev/null +++ b/src/generated/resources/assets/create/models/item/honeyed_apple.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/honeyed_apple" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/sticker.json b/src/generated/resources/assets/create/models/item/sticker.json new file mode 100644 index 000000000..b1367cf86 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/sticker.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/sticker/item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/sweet_roll.json b/src/generated/resources/assets/create/models/item/sweet_roll.json new file mode 100644 index 000000000..a7cb2e8f3 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/sweet_roll.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/sweet_roll" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gantry_pinion.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gantry_carriage.json similarity index 81% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gantry_pinion.json rename to src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gantry_carriage.json index b0d383da3..736ef1b67 100644 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gantry_pinion.json +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gantry_carriage.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "rewards": { "recipes": [ - "create:crafting/kinetics/gantry_pinion" + "create:crafting/kinetics/gantry_carriage" ] }, "criteria": { @@ -19,7 +19,7 @@ "has_the_recipe": { "trigger": "minecraft:recipe_unlocked", "conditions": { - "recipe": "create:crafting/kinetics/gantry_pinion" + "recipe": "create:crafting/kinetics/gantry_carriage" } } }, diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/sticker.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/sticker.json new file mode 100644 index 000000000..65c58bb33 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/sticker.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/kinetics/sticker" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "create:andesite_alloy" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/kinetics/sticker" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/gantry_carriage.json b/src/generated/resources/data/create/loot_tables/blocks/gantry_carriage.json new file mode 100644 index 000000000..cf1d1630a --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/gantry_carriage.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "create:gantry_carriage" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/gantry_pinion.json b/src/generated/resources/data/create/loot_tables/blocks/sticker.json similarity index 86% rename from src/generated/resources/data/create/loot_tables/blocks/gantry_pinion.json rename to src/generated/resources/data/create/loot_tables/blocks/sticker.json index 9631215af..92ccdbe64 100644 --- a/src/generated/resources/data/create/loot_tables/blocks/gantry_pinion.json +++ b/src/generated/resources/data/create/loot_tables/blocks/sticker.json @@ -6,7 +6,7 @@ "entries": [ { "type": "minecraft:item", - "name": "create:gantry_pinion" + "name": "create:sticker" } ], "conditions": [ diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/gantry_pinion.json b/src/generated/resources/data/create/recipes/crafting/kinetics/gantry_carriage.json similarity index 89% rename from src/generated/resources/data/create/recipes/crafting/kinetics/gantry_pinion.json rename to src/generated/resources/data/create/recipes/crafting/kinetics/gantry_carriage.json index 9bb723b76..e4bccc262 100644 --- a/src/generated/resources/data/create/recipes/crafting/kinetics/gantry_pinion.json +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/gantry_carriage.json @@ -20,6 +20,6 @@ } }, "result": { - "item": "create:gantry_pinion" + "item": "create:gantry_carriage" } } \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/sticker.json b/src/generated/resources/data/create/recipes/crafting/kinetics/sticker.json new file mode 100644 index 000000000..71db9df8a --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/sticker.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "ISI", + "CRC" + ], + "key": { + "I": { + "item": "create:andesite_alloy" + }, + "C": { + "tag": "forge:cobblestone" + }, + "R": { + "tag": "forge:dusts/redstone" + }, + "S": { + "tag": "forge:slimeballs" + } + }, + "result": { + "item": "create:sticker" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/filling/chocolate_glazed_berries.json b/src/generated/resources/data/create/recipes/filling/chocolate_glazed_berries.json new file mode 100644 index 000000000..0ce5553a5 --- /dev/null +++ b/src/generated/resources/data/create/recipes/filling/chocolate_glazed_berries.json @@ -0,0 +1,18 @@ +{ + "type": "create:filling", + "ingredients": [ + { + "item": "minecraft:sweet_berries" + }, + { + "fluid": "create:chocolate", + "nbt": {}, + "amount": 250 + } + ], + "results": [ + { + "item": "create:chocolate_glazed_berries" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/filling/honeyed_apple.json b/src/generated/resources/data/create/recipes/filling/honeyed_apple.json new file mode 100644 index 000000000..93692da87 --- /dev/null +++ b/src/generated/resources/data/create/recipes/filling/honeyed_apple.json @@ -0,0 +1,17 @@ +{ + "type": "create:filling", + "ingredients": [ + { + "item": "minecraft:apple" + }, + { + "fluidTag": "forge:honey", + "amount": 250 + } + ], + "results": [ + { + "item": "create:honeyed_apple" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/filling/sweet_roll.json b/src/generated/resources/data/create/recipes/filling/sweet_roll.json new file mode 100644 index 000000000..b80ab581b --- /dev/null +++ b/src/generated/resources/data/create/recipes/filling/sweet_roll.json @@ -0,0 +1,17 @@ +{ + "type": "create:filling", + "ingredients": [ + { + "item": "minecraft:bread" + }, + { + "fluidTag": "forge:milk", + "amount": 250 + } + ], + "results": [ + { + "item": "create:sweet_roll" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/upright_on_belt.json b/src/generated/resources/data/create/tags/items/upright_on_belt.json index 83603f5b0..0aa3286d8 100644 --- a/src/generated/resources/data/create/tags/items/upright_on_belt.json +++ b/src/generated/resources/data/create/tags/items/upright_on_belt.json @@ -7,6 +7,7 @@ "minecraft:glass_bottle", "minecraft:potion", "minecraft:splash_potion", - "minecraft:lingering_potion" + "minecraft:lingering_potion", + "minecraft:honey_bottle" ] } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/AllBlockPartials.java b/src/main/java/com/simibubi/create/AllBlockPartials.java index 6372fe1d1..a99929580 100644 --- a/src/main/java/com/simibubi/create/AllBlockPartials.java +++ b/src/main/java/com/simibubi/create/AllBlockPartials.java @@ -16,8 +16,11 @@ import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.A import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.content.contraptions.relays.belt.BeltData; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.RenderMaterials; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; @@ -77,7 +80,7 @@ public class AllBlockPartials { CUCKOO_RIGHT_DOOR = get("cuckoo_clock/right_door"), CUCKOO_PIG = get("cuckoo_clock/pig"), CUCKOO_CREEPER = get("cuckoo_clock/creeper"), - GANTRY_COGS = get("gantry_pinion/wheels"), + GANTRY_COGS = get("gantry_carriage/wheels"), ROPE_COIL = get("rope_pulley/rope_coil"), ROPE_HALF = get("rope_pulley/rope_half"), @@ -93,6 +96,8 @@ public class AllBlockPartials { SYMMETRY_PLANE = get("symmetry_effect/plane"), SYMMETRY_CROSSPLANE = get("symmetry_effect/crossplane"), SYMMETRY_TRIPLEPLANE = get("symmetry_effect/tripleplane"), + + STICKER_HEAD = get("sticker/head"), PORTABLE_STORAGE_INTERFACE_MIDDLE = get("portable_storage_interface/block_middle"), PORTABLE_STORAGE_INTERFACE_MIDDLE_POWERED = get("portable_storage_interface/block_middle_powered"), @@ -117,6 +122,8 @@ public class AllBlockPartials { SPEED_CONTROLLER_BRACKET = get("rotation_speed_controller/bracket"), + GOGGLES = get("goggles"), + COUPLING_ATTACHMENT = getEntity("minecart_coupling/attachment"), COUPLING_RING = getEntity("minecart_coupling/ring"), COUPLING_CONNECTOR = getEntity("minecart_coupling/connector") @@ -255,4 +262,22 @@ public class AllBlockPartials { return dispatcher.getMaterial(KineticRenderMaterials.ROTATING).getModel(this, referenceState, facing, ms); } + public InstancedModel renderOnHorizontalModel(InstancedTileRenderer dispatcher, BlockState referenceState) { + Direction facing = referenceState.get(HORIZONTAL_FACING); + return renderOnDirectionalSouthModel(dispatcher, referenceState, facing); + } + + public InstancedModel renderOnDirectionalSouthModel(InstancedTileRenderer dispatcher, BlockState referenceState, Direction facing) { + Supplier ms = () -> { + MatrixStack stack = new MatrixStack(); + MatrixStacker.of(stack) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(AngleHelper.verticalAngle(facing)) + .unCentre(); + return stack; + }; + return dispatcher.getMaterial(RenderMaterials.MODELS).getModel(this, referenceState, facing, ms); + } + } diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index bd6475ef7..58e0864ee 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -1,29 +1,10 @@ package com.simibubi.create; -import static com.simibubi.create.AllMovementBehaviours.addMovementBehaviour; -import static com.simibubi.create.AllTags.tagBlockAndItem; -import static com.simibubi.create.content.AllSections.SCHEMATICS; -import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock; -import static com.simibubi.create.foundation.data.BlockStateGen.oxidizedBlockstate; -import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures; -import static com.simibubi.create.foundation.data.ModelGen.customItemModel; -import static com.simibubi.create.foundation.data.ModelGen.oxidizedItemModel; - import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllItemTags; import com.simibubi.create.content.AllSections; import com.simibubi.create.content.contraptions.base.CasingBlock; -import com.simibubi.create.content.contraptions.components.actors.DrillBlock; -import com.simibubi.create.content.contraptions.components.actors.DrillMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.HarvesterBlock; -import com.simibubi.create.content.contraptions.components.actors.HarvesterMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.PloughBlock; -import com.simibubi.create.content.contraptions.components.actors.PloughMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceBlock; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceMovement; -import com.simibubi.create.content.contraptions.components.actors.SawMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.SeatBlock; -import com.simibubi.create.content.contraptions.components.actors.SeatMovementBehaviour; +import com.simibubi.create.content.contraptions.components.actors.*; import com.simibubi.create.content.contraptions.components.clock.CuckooClockBlock; import com.simibubi.create.content.contraptions.components.crafter.CrafterCTBehaviour; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterBlock; @@ -46,15 +27,12 @@ import com.simibubi.create.content.contraptions.components.motor.CreativeMotorGe import com.simibubi.create.content.contraptions.components.press.MechanicalPressBlock; import com.simibubi.create.content.contraptions.components.saw.SawBlock; import com.simibubi.create.content.contraptions.components.saw.SawGenerator; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.SailBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedBearingMovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.WindmillBearingBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.*; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.LinearChassisBlock; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.LinearChassisBlock.ChassisCTBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.RadialChassisBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryPinionBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageBlock; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock.MinecartAnchorBlock; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlockItem; @@ -72,15 +50,7 @@ import com.simibubi.create.content.contraptions.fluids.PumpBlock; import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyBlock; import com.simibubi.create.content.contraptions.fluids.actors.ItemDrainBlock; import com.simibubi.create.content.contraptions.fluids.actors.SpoutBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlockItem; -import com.simibubi.create.content.contraptions.fluids.pipes.BracketGenerator; -import com.simibubi.create.content.contraptions.fluids.pipes.EncasedPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.GlassFluidPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.SmartFluidPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.SmartFluidPipeGenerator; +import com.simibubi.create.content.contraptions.fluids.pipes.*; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankGenerator; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankItem; @@ -102,13 +72,7 @@ import com.simibubi.create.content.contraptions.relays.elementary.BracketedKinet import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; import com.simibubi.create.content.contraptions.relays.elementary.CogwheelBlockItem; import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.content.contraptions.relays.encased.AdjustablePulleyBlock; -import com.simibubi.create.content.contraptions.relays.encased.ClutchBlock; -import com.simibubi.create.content.contraptions.relays.encased.EncasedBeltBlock; -import com.simibubi.create.content.contraptions.relays.encased.EncasedBeltGenerator; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCTBehaviour; -import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock; -import com.simibubi.create.content.contraptions.relays.encased.GearshiftBlock; +import com.simibubi.create.content.contraptions.relays.encased.*; import com.simibubi.create.content.contraptions.relays.gauge.GaugeBlock; import com.simibubi.create.content.contraptions.relays.gauge.GaugeGenerator; import com.simibubi.create.content.contraptions.relays.gearbox.GearboxBlock; @@ -120,42 +84,18 @@ import com.simibubi.create.content.logistics.block.chute.ChuteGenerator; import com.simibubi.create.content.logistics.block.chute.ChuteItem; import com.simibubi.create.content.logistics.block.chute.SmartChuteBlock; import com.simibubi.create.content.logistics.block.depot.DepotBlock; -import com.simibubi.create.content.logistics.block.diodes.AbstractDiodeGenerator; -import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterBlock; -import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterGenerator; -import com.simibubi.create.content.logistics.block.diodes.PoweredLatchBlock; -import com.simibubi.create.content.logistics.block.diodes.PoweredLatchGenerator; -import com.simibubi.create.content.logistics.block.diodes.PulseRepeaterBlock; -import com.simibubi.create.content.logistics.block.diodes.PulseRepeaterGenerator; -import com.simibubi.create.content.logistics.block.diodes.ToggleLatchBlock; -import com.simibubi.create.content.logistics.block.diodes.ToggleLatchGenerator; -import com.simibubi.create.content.logistics.block.funnel.AndesiteFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelGenerator; -import com.simibubi.create.content.logistics.block.funnel.BrassFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.FunnelMovementBehaviour; +import com.simibubi.create.content.logistics.block.diodes.*; +import com.simibubi.create.content.logistics.block.funnel.*; import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateBlock; import com.simibubi.create.content.logistics.block.inventories.CreativeCrateBlock; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmBlock; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmItem; -import com.simibubi.create.content.logistics.block.redstone.AnalogLeverBlock; -import com.simibubi.create.content.logistics.block.redstone.ContactMovementBehaviour; -import com.simibubi.create.content.logistics.block.redstone.ContentObserverBlock; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeBlock; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeGenerator; -import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock; -import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock; -import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkGenerator; -import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchBlock; +import com.simibubi.create.content.logistics.block.redstone.*; import com.simibubi.create.content.schematics.block.SchematicTableBlock; import com.simibubi.create.content.schematics.block.SchematicannonBlock; +import com.simibubi.create.foundation.block.ItemUseOverrides; import com.simibubi.create.foundation.config.StressConfigDefaults; -import com.simibubi.create.foundation.data.AssetLookup; -import com.simibubi.create.foundation.data.BlockStateGen; -import com.simibubi.create.foundation.data.BuilderTransformers; -import com.simibubi.create.foundation.data.CreateRegistrate; -import com.simibubi.create.foundation.data.ModelGen; -import com.simibubi.create.foundation.data.SharedProperties; +import com.simibubi.create.foundation.data.*; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.utility.DyeHelper; import com.simibubi.create.foundation.worldgen.OxidizingBlock; @@ -181,6 +121,15 @@ import net.minecraftforge.client.model.generators.ModelFile; import net.minecraftforge.common.Tags; import net.minecraftforge.common.ToolType; +import static com.simibubi.create.AllMovementBehaviours.addMovementBehaviour; +import static com.simibubi.create.AllTags.tagBlockAndItem; +import static com.simibubi.create.content.AllSections.SCHEMATICS; +import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock; +import static com.simibubi.create.foundation.data.BlockStateGen.oxidizedBlockstate; +import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures; +import static com.simibubi.create.foundation.data.ModelGen.customItemModel; +import static com.simibubi.create.foundation.data.ModelGen.oxidizedItemModel; + public class AllBlocks { private static final CreateRegistrate REGISTRATE = Create.registrate() @@ -371,6 +320,7 @@ public class AllBlocks { .blockstate(BlockStateGen.directionalBlockProvider(true)) .transform(StressConfigDefaults.setCapacity(8.0)) .tag(AllBlockTags.BRITTLE.tag) + .onRegister(ItemUseOverrides::addBlock) .item() .transform(customItemModel()) .register(); @@ -691,8 +641,8 @@ public class AllBlocks { .getString() + "/head")))) .register(); - public static final BlockEntry GANTRY_PINION = - REGISTRATE.block("gantry_pinion", GantryPinionBlock::new) + public static final BlockEntry GANTRY_CARRIAGE = + REGISTRATE.block("gantry_carriage", GantryCarriageBlock::new) .initialProperties(SharedProperties::stone) .properties(Block.Properties::nonOpaque) .blockstate(BlockStateGen.directionalAxisBlockProvider()) @@ -845,6 +795,15 @@ public class AllBlocks { .build() .register(); + public static final BlockEntry STICKER = REGISTRATE.block("sticker", StickerBlock::new) + .initialProperties(SharedProperties::stone) + .properties(Block.Properties::nonOpaque) + .addLayer(() -> RenderType::getCutoutMipped) + .blockstate((c, p) -> p.directionalBlock(c.get(), AssetLookup.forPowered(c, p))) + .item() + .transform(customItemModel()) + .register(); + public static final BlockEntry MECHANICAL_DRILL = REGISTRATE.block("mechanical_drill", DrillBlock::new) .initialProperties(SharedProperties::stone) .blockstate(BlockStateGen.directionalBlockProvider(true)) @@ -1082,7 +1041,10 @@ public class AllBlocks { .initialProperties(SharedProperties::stone) .tag(AllBlockTags.SAFE_NBT.tag) .onRegister(addMovementBehaviour(FunnelMovementBehaviour.andesite())) - .transform(BuilderTransformers.funnel("andesite", Create.asResource("block/andesite_casing"))) + .blockstate(new FunnelGenerator("andesite", false)::generate) + .item(FunnelItem::new) + .model(FunnelGenerator.itemModel("andesite")) + .build() .register(); public static final BlockEntry ANDESITE_BELT_FUNNEL = @@ -1098,7 +1060,10 @@ public class AllBlocks { .initialProperties(SharedProperties::softMetal) .tag(AllBlockTags.SAFE_NBT.tag) .onRegister(addMovementBehaviour(FunnelMovementBehaviour.brass())) - .transform(BuilderTransformers.funnel("brass", Create.asResource("block/brass_casing"))) + .blockstate(new FunnelGenerator("brass", true)::generate) + .item(FunnelItem::new) + .model(FunnelGenerator.itemModel("brass")) + .build() .register(); public static final BlockEntry BRASS_BELT_FUNNEL = @@ -1180,6 +1145,7 @@ public class AllBlocks { .initialProperties(() -> Blocks.LEVER) .tag(AllBlockTags.SAFE_NBT.tag) .blockstate((c, p) -> p.horizontalFaceBlock(c.get(), AssetLookup.partialBaseModel(c, p))) + .onRegister(ItemUseOverrides::addBlock) .item() .transform(customItemModel()) .register(); diff --git a/src/main/java/com/simibubi/create/AllEntityTypes.java b/src/main/java/com/simibubi/create/AllEntityTypes.java index d811fba0e..c92797f23 100644 --- a/src/main/java/com/simibubi/create/AllEntityTypes.java +++ b/src/main/java/com/simibubi/create/AllEntityTypes.java @@ -31,9 +31,9 @@ public class AllEntityTypes { contraption("gantry_contraption", GantryContraptionEntity::new, 10, 40, false); public static final RegistryEntry> SUPER_GLUE = register("super_glue", - SuperGlueEntity::new, EntityClassification.MISC, 10, Integer.MAX_VALUE, false, SuperGlueEntity::build); + SuperGlueEntity::new, EntityClassification.MISC, 10, Integer.MAX_VALUE, false, true, SuperGlueEntity::build); public static final RegistryEntry> SEAT = - register("seat", SeatEntity::new, EntityClassification.MISC, 0, Integer.MAX_VALUE, false, SeatEntity::build); + register("seat", SeatEntity::new, EntityClassification.MISC, 0, Integer.MAX_VALUE, false, true, SeatEntity::build); // @@ -41,12 +41,12 @@ public class AllEntityTypes { private static RegistryEntry> contraption(String name, IFactory factory, int range, int updateFrequency, boolean sendVelocity) { - return register(name, factory, EntityClassification.MISC, range, updateFrequency, sendVelocity, + return register(name, factory, EntityClassification.MISC, range, updateFrequency, sendVelocity, true, AbstractContraptionEntity::build); } private static RegistryEntry> register(String name, IFactory factory, - EntityClassification group, int range, int updateFrequency, boolean sendVelocity, + EntityClassification group, int range, int updateFrequency, boolean sendVelocity, boolean immuneToFire, NonNullConsumer> propertyBuilder) { String id = Lang.asId(name); return Create.registrate() @@ -55,6 +55,10 @@ public class AllEntityTypes { .setUpdateInterval(updateFrequency) .setShouldReceiveVelocityUpdates(sendVelocity)) .properties(propertyBuilder) + .properties(b -> { + if (immuneToFire) + b.immuneToFire(); + }) .register(); } diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index b948aacc7..4cd832dc1 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -16,6 +16,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.glu import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MinecartContraptionItem; import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingItem; import com.simibubi.create.content.contraptions.goggles.GogglesItem; +import com.simibubi.create.content.contraptions.goggles.GogglesModel; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlockItem; import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorItem; import com.simibubi.create.content.contraptions.relays.gearbox.VerticalGearboxItem; @@ -67,6 +68,74 @@ public class AllItems { REGISTRATE.startSection(MATERIALS); } + public static final ItemEntry WHEAT_FLOUR = ingredient("wheat_flour"), DOUGH = ingredient("dough"), + CINDER_FLOUR = ingredient("cinder_flour"), POWDERED_OBSIDIAN = ingredient("powdered_obsidian"), + ROSE_QUARTZ = ingredient("rose_quartz"), POLISHED_ROSE_QUARTZ = ingredient("polished_rose_quartz"), + PROPELLER = ingredient("propeller"), WHISK = ingredient("whisk"), BRASS_HAND = ingredient("brass_hand"), + CRAFTER_SLOT_COVER = ingredient("crafter_slot_cover"), ELECTRON_TUBE = ingredient("electron_tube"), + INTEGRATED_CIRCUIT = ingredient("integrated_circuit"); + + public static final ItemEntry BLAZE_CAKE_BASE = + REGISTRATE.item("blaze_cake_base", HiddenIngredientItem::new) + .tag(AllItemTags.UPRIGHT_ON_BELT.tag) + .register(); + + public static final ItemEntry BLAZE_CAKE = REGISTRATE.item("blaze_cake", CombustibleItem::new) + .tag(AllItemTags.UPRIGHT_ON_BELT.tag) + .register(); + + public static final ItemEntry BAR_OF_CHOCOLATE = REGISTRATE.item("bar_of_chocolate", Item::new) + .properties(p -> p.food(new Food.Builder().hunger(6) + .saturation(0.3F) + .build())) + .lang("Bar of Chocolate") + .register(); + + public static final ItemEntry SWEET_ROLL = REGISTRATE.item("sweet_roll", Item::new) + .properties(p -> p.food(new Food.Builder().hunger(6) + .saturation(0.8F) + .build())) + .register(); + + public static final ItemEntry CHOCOLATE_BERRIES = REGISTRATE.item("chocolate_glazed_berries", Item::new) + .properties(p -> p.food(new Food.Builder().hunger(7) + .saturation(0.8F) + .build())) + .register(); + + public static final ItemEntry HONEYED_APPLE = REGISTRATE.item("honeyed_apple", Item::new) + .properties(p -> p.food(new Food.Builder().hunger(8) + .saturation(0.8F) + .build())) + .register(); + + public static final ItemEntry BUILDERS_TEA = REGISTRATE.item("builders_tea", BuildersTeaItem::new) + .tag(AllItemTags.UPRIGHT_ON_BELT.tag) + .properties(p -> p.maxStackSize(16)) + .lang("Builder's Tea") + .register(); + + public static final ItemEntry ANDESITE_ALLOY = ingredient("andesite_alloy"), + COPPER_INGOT = taggedIngredient("copper_ingot", forgeItemTag("ingots/copper"), CREATE_INGOTS.tag), + ZINC_INGOT = taggedIngredient("zinc_ingot", forgeItemTag("ingots/zinc"), CREATE_INGOTS.tag), + BRASS_INGOT = taggedIngredient("brass_ingot", forgeItemTag("ingots/brass"), CREATE_INGOTS.tag); + + public static final ItemEntry CHROMATIC_COMPOUND = + REGISTRATE.item("chromatic_compound", ChromaticCompoundItem::new) + .properties(p -> p.rarity(Rarity.UNCOMMON)) + .model(AssetLookup.existingItemModel()) + .onRegister(CreateRegistrate.itemColors(() -> ChromaticCompoundColor::new)) + .register(); + + public static final ItemEntry SHADOW_STEEL = REGISTRATE.item("shadow_steel", ShadowSteelItem::new) + .properties(p -> p.rarity(Rarity.UNCOMMON)) + .register(); + + public static final ItemEntry REFINED_RADIANCE = + REGISTRATE.item("refined_radiance", RefinedRadianceItem::new) + .properties(p -> p.rarity(Rarity.UNCOMMON)) + .register(); + public static final ItemEntry COPPER_NUGGET = taggedIngredient("copper_nugget", forgeItemTag("nuggets/copper"), NUGGETS.tag), ZINC_NUGGET = taggedIngredient("zinc_nugget", forgeItemTag("nuggets/zinc"), NUGGETS.tag), @@ -90,59 +159,6 @@ public class AllItems { CRUSHED_QUICKSILVER = compatCrushedOre("quicksilver"), CRUSHED_BAUXITE = compatCrushedOre("aluminum"), CRUSHED_URANIUM = compatCrushedOre("uranium"), CRUSHED_NICKEL = compatCrushedOre("nickel"); - public static final ItemEntry ANDESITE_ALLOY = ingredient("andesite_alloy"), - COPPER_INGOT = taggedIngredient("copper_ingot", forgeItemTag("ingots/copper"), CREATE_INGOTS.tag), - ZINC_INGOT = taggedIngredient("zinc_ingot", forgeItemTag("ingots/zinc"), CREATE_INGOTS.tag), - BRASS_INGOT = taggedIngredient("brass_ingot", forgeItemTag("ingots/brass"), CREATE_INGOTS.tag), - - WHEAT_FLOUR = ingredient("wheat_flour"), DOUGH = ingredient("dough"), CINDER_FLOUR = ingredient("cinder_flour"), - POWDERED_OBSIDIAN = ingredient("powdered_obsidian"), ROSE_QUARTZ = ingredient("rose_quartz"), - POLISHED_ROSE_QUARTZ = ingredient("polished_rose_quartz"), PROPELLER = ingredient("propeller"), - WHISK = ingredient("whisk"), BRASS_HAND = ingredient("brass_hand"), - CRAFTER_SLOT_COVER = ingredient("crafter_slot_cover"); - - public static final ItemEntry BLAZE_CAKE_BASE = - REGISTRATE.item("blaze_cake_base", HiddenIngredientItem::new) - .tag(AllItemTags.UPRIGHT_ON_BELT.tag) - .register(); - - public static final ItemEntry BLAZE_CAKE = REGISTRATE.item("blaze_cake", CombustibleItem::new) - .tag(AllItemTags.UPRIGHT_ON_BELT.tag) - .register(); - - public static final ItemEntry BAR_OF_CHOCOLATE = REGISTRATE.item("bar_of_chocolate", Item::new) - .properties(p -> p.food(new Food.Builder().hunger(5) - .saturation(0.6F) - .build())) - .lang("Bar of Chocolate") - .register(); - - public static final ItemEntry BUILDERS_TEA = REGISTRATE.item("builders_tea", BuildersTeaItem::new) - .tag(AllItemTags.UPRIGHT_ON_BELT.tag) - .properties(p -> p.maxStackSize(16)) - .lang("Builder's Tea") - .register(); - - public static final ItemEntry CHROMATIC_COMPOUND = - REGISTRATE.item("chromatic_compound", ChromaticCompoundItem::new) - .properties(p -> p.rarity(Rarity.UNCOMMON)) - .model(AssetLookup.existingItemModel()) - .onRegister(CreateRegistrate.itemColors(() -> ChromaticCompoundColor::new)) - .register(); - - public static final ItemEntry SHADOW_STEEL = REGISTRATE.item("shadow_steel", ShadowSteelItem::new) - .properties(p -> p.rarity(Rarity.UNCOMMON)) - .register(); - - public static final ItemEntry REFINED_RADIANCE = - REGISTRATE.item("refined_radiance", RefinedRadianceItem::new) - .properties(p -> p.rarity(Rarity.UNCOMMON)) - .register(); - - public static final ItemEntry - - ELECTRON_TUBE = ingredient("electron_tube"), INTEGRATED_CIRCUIT = ingredient("integrated_circuit"); - // Kinetics static { @@ -165,6 +181,12 @@ public class AllItems { .model(AssetLookup.customItemModel("blaze_burner", "block")) .register(); + public static final ItemEntry GOGGLES = REGISTRATE.item("goggles", GogglesItem::new) + .properties(p -> p.maxStackSize(1)) + .onRegister(CreateRegistrate.itemModel(() -> GogglesModel::new)) + .lang("Engineer's Goggles") + .register(); + public static final ItemEntry SUPER_GLUE = REGISTRATE.item("super_glue", SuperGlueItem::new) .register(); @@ -187,12 +209,6 @@ public class AllItems { .model(AssetLookup.itemModelWithPartials()) .register(); - public static final ItemEntry GOGGLES = REGISTRATE.item("goggles", GogglesItem::new) - .properties(p -> p.maxStackSize(1)) - .model(AssetLookup.existingItemModel()) - .lang("Engineer's Goggles") - .register(); - public static final ItemEntry MINECART_CONTRAPTION = REGISTRATE.item("minecart_contraption", MinecartContraptionItem::rideable) .register(); diff --git a/src/main/java/com/simibubi/create/AllShapes.java b/src/main/java/com/simibubi/create/AllShapes.java index 44322d22c..7c102139e 100644 --- a/src/main/java/com/simibubi/create/AllShapes.java +++ b/src/main/java/com/simibubi/create/AllShapes.java @@ -78,7 +78,7 @@ public class AllShapes { .add(0.1, 1, 10, 15.9, 5, 14) .add(0.1, -3, 11, 15.9, 1, 15) .forHorizontal(NORTH), - FUNNEL = shape(2, 2, 14, 14, 14, 18).add(1, 8, 12, 15, 15, 14) + FUNNEL_WALL = shape(2, 2, 14, 14, 14, 18).add(1, 8, 12, 15, 15, 14) .add(0.1, 13, 7, 15.9, 15, 11) .add(0.1, 9, 8, 15.9, 13, 12) .add(0.1, 5, 9, 15.9, 9, 13) @@ -187,10 +187,10 @@ public class AllShapes { TANK_TOP_BOTTOM = shape(TANK_BOTTOM_LID).add(TANK_TOP_LID) .add(TANK) .build(), - FUNNEL_FLOOR = shape(2, -2, 2, 14, 8, 14).add(1, 2, 1, 15, 8, 15) + FUNNEL_FLOOR = shape(2, -2, 2, 14, 8, 14).add(1, 1, 1, 15, 8, 15) .add(0, 4, 0, 16, 10, 16) .build(), - FUNNEL_CEILING = shape(2, 8, 2, 14, 18, 14).add(1, 8, 1, 15, 14, 15) + FUNNEL_CEILING = shape(2, 8, 2, 14, 18, 14).add(1, 8, 1, 15, 15, 15) .add(0, 6, 0, 16, 12, 16) .build(), DEPOT = shape(CASING_11PX.get(Direction.UP)).add(1, 11, 1, 15, 13, 15) diff --git a/src/main/java/com/simibubi/create/AllSpriteShifts.java b/src/main/java/com/simibubi/create/AllSpriteShifts.java index c7ce9a30d..825023bfd 100644 --- a/src/main/java/com/simibubi/create/AllSpriteShifts.java +++ b/src/main/java/com/simibubi/create/AllSpriteShifts.java @@ -44,7 +44,10 @@ public class AllSpriteShifts { SHADOW_STEEL_CASING = omni("shadow_steel_casing"), REFINED_RADIANCE_CASING = omni("refined_radiance_casing"), CREATIVE_CASING = getCT(CTType.CROSS, "creative_casing"); - public static final CTSpriteShiftEntry CHASSIS = getCT(CTType.OMNIDIRECTIONAL, "linear_chassis_end"), + public static final CTSpriteShiftEntry + CHASSIS_SIDE = getCT(CTType.OMNIDIRECTIONAL, "linear_chassis_side"), + SECONDARY_CHASSIS_SIDE = getCT(CTType.OMNIDIRECTIONAL, "secondary_linear_chassis_side"), + CHASSIS = getCT(CTType.OMNIDIRECTIONAL, "linear_chassis_end"), CHASSIS_STICKY = getCT(CTType.OMNIDIRECTIONAL, "linear_chassis_end_sticky"); public static final CTSpriteShiftEntry BRASS_TUNNEL_TOP = vertical("brass_tunnel_top"), diff --git a/src/main/java/com/simibubi/create/AllTags.java b/src/main/java/com/simibubi/create/AllTags.java index e6fba3059..a017cc657 100644 --- a/src/main/java/com/simibubi/create/AllTags.java +++ b/src/main/java/com/simibubi/create/AllTags.java @@ -189,7 +189,8 @@ public class AllTags { AllItemTags.CREATE_INGOTS.includeIn(AllItemTags.BEACON_PAYMENT); AllItemTags.CREATE_INGOTS.includeIn(AllItemTags.INGOTS); - AllItemTags.UPRIGHT_ON_BELT.add(Items.GLASS_BOTTLE, Items.POTION, Items.SPLASH_POTION, Items.LINGERING_POTION); + AllItemTags.UPRIGHT_ON_BELT.add(Items.GLASS_BOTTLE, Items.POTION, Items.SPLASH_POTION, Items.LINGERING_POTION, + Items.HONEY_BOTTLE); AllBlockTags.WINDMILL_SAILS.includeAll(BlockTags.WOOL); diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 1abb73271..88b073b28 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -1,28 +1,18 @@ package com.simibubi.create; -import com.simibubi.create.content.contraptions.base.BackHalfShaftInstance; -import com.simibubi.create.content.contraptions.base.HalfShaftInstance; -import com.simibubi.create.content.contraptions.base.HorizontalHalfShaftInstance; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.base.ShaftlessCogInstance; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.components.actors.DrillInstance; -import com.simibubi.create.content.contraptions.components.actors.DrillRenderer; -import com.simibubi.create.content.contraptions.components.actors.DrillTileEntity; -import com.simibubi.create.content.contraptions.components.actors.HarvesterRenderer; -import com.simibubi.create.content.contraptions.components.actors.HarvesterTileEntity; -import com.simibubi.create.content.contraptions.components.actors.PortableFluidInterfaceTileEntity; -import com.simibubi.create.content.contraptions.components.actors.PortableItemInterfaceTileEntity; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceRenderer; +import com.simibubi.create.content.contraptions.base.*; +import com.simibubi.create.content.contraptions.components.actors.*; import com.simibubi.create.content.contraptions.components.clock.CuckooClockRenderer; import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterInstance; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterRenderer; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity; +import com.simibubi.create.content.contraptions.components.crank.HandCrankInstance; import com.simibubi.create.content.contraptions.components.crank.HandCrankRenderer; import com.simibubi.create.content.contraptions.components.crank.HandCrankTileEntity; import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelControllerTileEntity; import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelTileEntity; +import com.simibubi.create.content.contraptions.components.deployer.DeployerInstance; import com.simibubi.create.content.contraptions.components.deployer.DeployerRenderer; import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity; import com.simibubi.create.content.contraptions.components.fan.EncasedFanRenderer; @@ -32,6 +22,7 @@ import com.simibubi.create.content.contraptions.components.fan.NozzleTileEntity; import com.simibubi.create.content.contraptions.components.flywheel.FlyWheelInstance; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelRenderer; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelTileEntity; +import com.simibubi.create.content.contraptions.components.flywheel.engine.EngineInstance; import com.simibubi.create.content.contraptions.components.flywheel.engine.EngineRenderer; import com.simibubi.create.content.contraptions.components.flywheel.engine.FurnaceEngineTileEntity; import com.simibubi.create.content.contraptions.components.millstone.MillStoneCogInstance; @@ -39,10 +30,12 @@ import com.simibubi.create.content.contraptions.components.millstone.MillstoneRe import com.simibubi.create.content.contraptions.components.millstone.MillstoneTileEntity; import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerRenderer; import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerTileEntity; +import com.simibubi.create.content.contraptions.components.mixer.MixerInstance; import com.simibubi.create.content.contraptions.components.motor.CreativeMotorRenderer; import com.simibubi.create.content.contraptions.components.motor.CreativeMotorTileEntity; import com.simibubi.create.content.contraptions.components.press.MechanicalPressRenderer; import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity; +import com.simibubi.create.content.contraptions.components.press.PressInstance; import com.simibubi.create.content.contraptions.components.saw.SawInstance; import com.simibubi.create.content.contraptions.components.saw.SawRenderer; import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; @@ -51,8 +44,12 @@ import com.simibubi.create.content.contraptions.components.structureMovement.bea import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.WindmillBearingTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryPinionRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryPinionTileEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerInstance; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerRenderer; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerTileEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageInstance; +import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageRenderer; +import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonTileEntity; @@ -63,18 +60,8 @@ import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheel import com.simibubi.create.content.contraptions.fluids.PumpCogInstance; import com.simibubi.create.content.contraptions.fluids.PumpRenderer; import com.simibubi.create.content.contraptions.fluids.PumpTileEntity; -import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyRenderer; -import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyTileEntity; -import com.simibubi.create.content.contraptions.fluids.actors.ItemDrainRenderer; -import com.simibubi.create.content.contraptions.fluids.actors.ItemDrainTileEntity; -import com.simibubi.create.content.contraptions.fluids.actors.SpoutRenderer; -import com.simibubi.create.content.contraptions.fluids.actors.SpoutTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveRenderer; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.SmartFluidPipeTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.TransparentStraightPipeRenderer; +import com.simibubi.create.content.contraptions.fluids.actors.*; +import com.simibubi.create.content.contraptions.fluids.pipes.*; import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankRenderer; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; @@ -90,13 +77,8 @@ import com.simibubi.create.content.contraptions.relays.belt.BeltInstance; import com.simibubi.create.content.contraptions.relays.belt.BeltRenderer; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.AdjustablePulleyTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.ClutchTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftRenderer; -import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; -import com.simibubi.create.content.contraptions.relays.encased.SplitShaftInstance; -import com.simibubi.create.content.contraptions.relays.encased.SplitShaftRenderer; +import com.simibubi.create.content.contraptions.relays.encased.*; +import com.simibubi.create.content.contraptions.relays.gauge.GaugeInstance; import com.simibubi.create.content.contraptions.relays.gauge.GaugeRenderer; import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; @@ -104,6 +86,7 @@ import com.simibubi.create.content.contraptions.relays.gearbox.GearboxInstance; import com.simibubi.create.content.contraptions.relays.gearbox.GearboxRenderer; import com.simibubi.create.content.contraptions.relays.gearbox.GearboxTileEntity; import com.simibubi.create.content.contraptions.relays.gearbox.GearshiftTileEntity; +import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelInstance; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelRenderer; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity; import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity; @@ -116,6 +99,7 @@ import com.simibubi.create.content.logistics.block.depot.DepotTileEntity; import com.simibubi.create.content.logistics.block.diodes.AdjustablePulseRepeaterTileEntity; import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterRenderer; import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterTileEntity; +import com.simibubi.create.content.logistics.block.funnel.FunnelInstance; import com.simibubi.create.content.logistics.block.funnel.FunnelRenderer; import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateTileEntity; @@ -123,24 +107,22 @@ import com.simibubi.create.content.logistics.block.inventories.CreativeCrateTile import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInstance; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmRenderer; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity; -import com.simibubi.create.content.logistics.block.redstone.AnalogLeverRenderer; -import com.simibubi.create.content.logistics.block.redstone.AnalogLeverTileEntity; -import com.simibubi.create.content.logistics.block.redstone.ContentObserverTileEntity; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeRenderer; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; -import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkTileEntity; -import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchTileEntity; +import com.simibubi.create.content.logistics.block.redstone.*; import com.simibubi.create.content.schematics.block.SchematicTableTileEntity; +import com.simibubi.create.content.schematics.block.SchematicannonInstance; import com.simibubi.create.content.schematics.block.SchematicannonRenderer; import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.tterrag.registrate.util.entry.TileEntityEntry; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; public class AllTileEntities { // Schematics public static final TileEntityEntry SCHEMATICANNON = Create.registrate() .tileEntity("schematicannon", SchematicannonTileEntity::new) + .instance(() -> SchematicannonInstance::new) .validBlocks(AllBlocks.SCHEMATICANNON) .renderer(() -> SchematicannonRenderer::new) .register(); @@ -153,44 +135,44 @@ public class AllTileEntities { // Kinetics public static final TileEntityEntry SIMPLE_KINETIC = Create.registrate() .tileEntity("simple_kinetic", SimpleKineticTileEntity::new) + .instance(() -> SingleRotatingInstance::new) .validBlocks(AllBlocks.SHAFT, AllBlocks.COGWHEEL, AllBlocks.LARGE_COGWHEEL) .renderer(() -> KineticTileEntityRenderer::new) - .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry MOTOR = Create.registrate() .tileEntity("motor", CreativeMotorTileEntity::new) + .instance(() -> HalfShaftInstance::new) .validBlocks(AllBlocks.CREATIVE_MOTOR) .renderer(() -> CreativeMotorRenderer::new) - .onRegister(HalfShaftInstance::register) .register(); public static final TileEntityEntry GEARBOX = Create.registrate() .tileEntity("gearbox", GearboxTileEntity::new) + .instance(() -> GearboxInstance::new) .validBlocks(AllBlocks.GEARBOX) .renderer(() -> GearboxRenderer::new) - .onRegister(GearboxInstance::register) .register(); public static final TileEntityEntry ENCASED_SHAFT = Create.registrate() .tileEntity("encased_shaft", EncasedShaftTileEntity::new) + .instance(() -> ShaftInstance::new) .validBlocks(AllBlocks.ANDESITE_ENCASED_SHAFT, AllBlocks.BRASS_ENCASED_SHAFT, AllBlocks.ENCASED_CHAIN_DRIVE) .renderer(() -> EncasedShaftRenderer::new) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry ADJUSTABLE_PULLEY = Create.registrate() .tileEntity("adjustable_pulley", AdjustablePulleyTileEntity::new) + .instance(() -> ShaftInstance::new) .validBlocks(AllBlocks.ADJUSTABLE_CHAIN_GEARSHIFT) .renderer(() -> EncasedShaftRenderer::new) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry ENCASED_FAN = Create.registrate() .tileEntity("encased_fan", EncasedFanTileEntity::new) + .instance(() -> FanInstance::new) .validBlocks(AllBlocks.ENCASED_FAN) .renderer(() -> EncasedFanRenderer::new) - .onRegister(FanInstance::register) .register(); public static final TileEntityEntry NOZZLE = Create.registrate() @@ -201,59 +183,59 @@ public class AllTileEntities { public static final TileEntityEntry CLUTCH = Create.registrate() .tileEntity("clutch", ClutchTileEntity::new) + .instance(() -> SplitShaftInstance::new) .validBlocks(AllBlocks.CLUTCH) .renderer(() -> SplitShaftRenderer::new) - .onRegister(SplitShaftInstance::register) .register(); public static final TileEntityEntry GEARSHIFT = Create.registrate() .tileEntity("gearshift", GearshiftTileEntity::new) + .instance(() -> SplitShaftInstance::new) .validBlocks(AllBlocks.GEARSHIFT) .renderer(() -> SplitShaftRenderer::new) - .onRegister(SplitShaftInstance::register) .register(); public static final TileEntityEntry TURNTABLE = Create.registrate() .tileEntity("turntable", TurntableTileEntity::new) + .instance(() -> SingleRotatingInstance::new) .validBlocks(AllBlocks.TURNTABLE) .renderer(() -> KineticTileEntityRenderer::new) - .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry HAND_CRANK = Create.registrate() .tileEntity("hand_crank", HandCrankTileEntity::new) + .instance(() -> HandCrankInstance::new) .validBlocks(AllBlocks.HAND_CRANK, AllBlocks.COPPER_VALVE_HANDLE) .validBlocks(AllBlocks.DYED_VALVE_HANDLES) .renderer(() -> HandCrankRenderer::new) - .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry CUCKOO_CLOCK = Create.registrate() .tileEntity("cuckoo_clock", CuckooClockTileEntity::new) + .instance(() -> HorizontalHalfShaftInstance::new) .validBlocks(AllBlocks.CUCKOO_CLOCK, AllBlocks.MYSTERIOUS_CUCKOO_CLOCK) .renderer(() -> CuckooClockRenderer::new) - .onRegister(HorizontalHalfShaftInstance::register) .register(); public static final TileEntityEntry GANTRY_SHAFT = Create.registrate() .tileEntity("gantry_shaft", GantryShaftTileEntity::new) + .instance(() -> SingleRotatingInstance::new) .validBlocks(AllBlocks.GANTRY_SHAFT) .renderer(() -> KineticTileEntityRenderer::new) - .onRegister(SingleRotatingInstance::register) .register(); - public static final TileEntityEntry GANTRY_PINION = Create.registrate() - .tileEntity("gantry_pinion", GantryPinionTileEntity::new) - .validBlocks(AllBlocks.GANTRY_PINION) - .renderer(() -> GantryPinionRenderer::new) - .onRegister(ShaftInstance::register) + public static final TileEntityEntry GANTRY_PINION = Create.registrate() + .tileEntity("gantry_pinion", GantryCarriageTileEntity::new) + .instance(() -> GantryCarriageInstance::new) + .validBlocks(AllBlocks.GANTRY_CARRIAGE) + .renderer(() -> GantryCarriageRenderer::new) .register(); public static final TileEntityEntry MECHANICAL_PUMP = Create.registrate() .tileEntity("mechanical_pump", PumpTileEntity::new) + .instance(() -> PumpCogInstance::new) .validBlocks(AllBlocks.MECHANICAL_PUMP) .renderer(() -> PumpRenderer::new) - .onRegister(PumpCogInstance::register) .register(); public static final TileEntityEntry SMART_FLUID_PIPE = Create.registrate() @@ -280,9 +262,9 @@ public class AllTileEntities { public static final TileEntityEntry FLUID_VALVE = Create.registrate() .tileEntity("fluid_valve", FluidValveTileEntity::new) + .instance(() -> FluidValveInstance::new) .validBlocks(AllBlocks.FLUID_VALVE) .renderer(() -> FluidValveRenderer::new) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry FLUID_TANK = Create.registrate() @@ -299,9 +281,9 @@ public class AllTileEntities { public static final TileEntityEntry HOSE_PULLEY = Create.registrate() .tileEntity("hose_pulley", HosePulleyTileEntity::new) + .instance(() -> ShaftInstance::new) .validBlocks(AllBlocks.HOSE_PULLEY) .renderer(() -> HosePulleyRenderer::new) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry SPOUT = Create.registrate() @@ -318,9 +300,9 @@ public class AllTileEntities { public static final TileEntityEntry BELT = Create.registrate() .tileEntity("belt", BeltTileEntity::new) + .instance(() -> BeltInstance::new) .validBlocks(AllBlocks.BELT) .renderer(() -> BeltRenderer::new) - .onRegister(BeltInstance::register) .register(); public static final TileEntityEntry CHUTE = Create.registrate() @@ -337,56 +319,58 @@ public class AllTileEntities { public static final TileEntityEntry ANDESITE_TUNNEL = Create.registrate() .tileEntity("andesite_tunnel", BeltTunnelTileEntity::new) + .instance(() -> BeltTunnelInstance::new) .validBlocks(AllBlocks.ANDESITE_TUNNEL) .renderer(() -> BeltTunnelRenderer::new) .register(); public static final TileEntityEntry BRASS_TUNNEL = Create.registrate() .tileEntity("brass_tunnel", BrassTunnelTileEntity::new) + .instance(() -> BeltTunnelInstance::new) .validBlocks(AllBlocks.BRASS_TUNNEL) .renderer(() -> BeltTunnelRenderer::new) .register(); public static final TileEntityEntry MECHANICAL_ARM = Create.registrate() .tileEntity("mechanical_arm", ArmTileEntity::new) + .instance(() -> ArmInstance::new) .validBlocks(AllBlocks.MECHANICAL_ARM) .renderer(() -> ArmRenderer::new) - .onRegister(ArmInstance::register) .register(); public static final TileEntityEntry MECHANICAL_PISTON = Create.registrate() .tileEntity("mechanical_piston", MechanicalPistonTileEntity::new) + .instance(() -> ShaftInstance::new) .validBlocks(AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON) .renderer(() -> MechanicalPistonRenderer::new) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry WINDMILL_BEARING = Create.registrate() .tileEntity("windmill_bearing", WindmillBearingTileEntity::new) + .instance(() -> BackHalfShaftInstance::new) .validBlocks(AllBlocks.WINDMILL_BEARING) .renderer(() -> BearingRenderer::new) - .onRegister(BackHalfShaftInstance::register) .register(); public static final TileEntityEntry MECHANICAL_BEARING = Create.registrate() .tileEntity("mechanical_bearing", MechanicalBearingTileEntity::new) + .instance(() -> BackHalfShaftInstance::new) .validBlocks(AllBlocks.MECHANICAL_BEARING) .renderer(() -> BearingRenderer::new) - .onRegister(BackHalfShaftInstance::register) .register(); public static final TileEntityEntry CLOCKWORK_BEARING = Create.registrate() .tileEntity("clockwork_bearing", ClockworkBearingTileEntity::new) + .instance(() -> BackHalfShaftInstance::new) .validBlocks(AllBlocks.CLOCKWORK_BEARING) .renderer(() -> BearingRenderer::new) - .onRegister(BackHalfShaftInstance::register) .register(); public static final TileEntityEntry ROPE_PULLEY = Create.registrate() .tileEntity("rope_pulley", PulleyTileEntity::new) + .instance(() -> ShaftInstance::new) .validBlocks(AllBlocks.ROPE_PULLEY) .renderer(() -> PulleyRenderer::new) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry CHASSIS = Create.registrate() @@ -394,19 +378,26 @@ public class AllTileEntities { .validBlocks(AllBlocks.RADIAL_CHASSIS, AllBlocks.LINEAR_CHASSIS, AllBlocks.SECONDARY_LINEAR_CHASSIS) // .renderer(() -> renderer) .register(); + + public static final TileEntityEntry STICKER = Create.registrate() + .tileEntity("sticker", StickerTileEntity::new) + .instance(() -> StickerInstance::new) + .validBlocks(AllBlocks.STICKER) + .renderer(() -> StickerRenderer::new) + .register(); public static final TileEntityEntry DRILL = Create.registrate() .tileEntity("drill", DrillTileEntity::new) + .instance(() -> DrillInstance::new) .validBlocks(AllBlocks.MECHANICAL_DRILL) .renderer(() -> DrillRenderer::new) - .onRegister(DrillInstance::register) .register(); public static final TileEntityEntry SAW = Create.registrate() .tileEntity("saw", SawTileEntity::new) + .instance(() -> SawInstance::new) .validBlocks(AllBlocks.MECHANICAL_SAW) .renderer(() -> SawRenderer::new) - .onRegister(SawInstance::register) .register(); public static final TileEntityEntry HARVESTER = Create.registrate() @@ -430,29 +421,30 @@ public class AllTileEntities { public static final TileEntityEntry FLYWHEEL = Create.registrate() .tileEntity("flywheel", FlywheelTileEntity::new) + .instance(() -> FlyWheelInstance::new) .validBlocks(AllBlocks.FLYWHEEL) .renderer(() -> FlywheelRenderer::new) - .onRegister(FlyWheelInstance::register) .register(); public static final TileEntityEntry FURNACE_ENGINE = Create.registrate() .tileEntity("furnace_engine", FurnaceEngineTileEntity::new) + .instance(() -> EngineInstance::new) .validBlocks(AllBlocks.FURNACE_ENGINE) .renderer(() -> EngineRenderer::new) .register(); public static final TileEntityEntry MILLSTONE = Create.registrate() .tileEntity("millstone", MillstoneTileEntity::new) + .instance(() -> MillStoneCogInstance::new) .validBlocks(AllBlocks.MILLSTONE) .renderer(() -> MillstoneRenderer::new) - .onRegister(MillStoneCogInstance::register) .register(); public static final TileEntityEntry CRUSHING_WHEEL = Create.registrate() .tileEntity("crushing_wheel", CrushingWheelTileEntity::new) + .instance(() -> SingleRotatingInstance::new) .validBlocks(AllBlocks.CRUSHING_WHEEL) .renderer(() -> KineticTileEntityRenderer::new) - .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry CRUSHING_WHEEL_CONTROLLER = @@ -464,30 +456,30 @@ public class AllTileEntities { public static final TileEntityEntry WATER_WHEEL = Create.registrate() .tileEntity("water_wheel", WaterWheelTileEntity::new) + .instance(() -> SingleRotatingInstance::new) .validBlocks(AllBlocks.WATER_WHEEL) .renderer(() -> KineticTileEntityRenderer::new) - .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry MECHANICAL_PRESS = Create.registrate() .tileEntity("mechanical_press", MechanicalPressTileEntity::new) + .instance(() -> PressInstance::new) .validBlocks(AllBlocks.MECHANICAL_PRESS) .renderer(() -> MechanicalPressRenderer::new) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry MECHANICAL_MIXER = Create.registrate() .tileEntity("mechanical_mixer", MechanicalMixerTileEntity::new) + .instance(() -> MixerInstance::new) .validBlocks(AllBlocks.MECHANICAL_MIXER) .renderer(() -> MechanicalMixerRenderer::new) - .onRegister(ShaftlessCogInstance::register) .register(); public static final TileEntityEntry DEPLOYER = Create.registrate() .tileEntity("deployer", DeployerTileEntity::new) + .instance(() -> DeployerInstance::new) .validBlocks(AllBlocks.DEPLOYER) .renderer(() -> DeployerRenderer::new) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry BASIN = Create.registrate() @@ -504,41 +496,42 @@ public class AllTileEntities { public static final TileEntityEntry MECHANICAL_CRAFTER = Create.registrate() .tileEntity("mechanical_crafter", MechanicalCrafterTileEntity::new) + .instance(() -> MechanicalCrafterInstance::new) .validBlocks(AllBlocks.MECHANICAL_CRAFTER) .renderer(() -> MechanicalCrafterRenderer::new) - .onRegister(MechanicalCrafterInstance::register) .register(); public static final TileEntityEntry SEQUENCED_GEARSHIFT = Create.registrate() .tileEntity("sequenced_gearshift", SequencedGearshiftTileEntity::new) + .instance(() -> SplitShaftInstance::new) .validBlocks(AllBlocks.SEQUENCED_GEARSHIFT) .renderer(() -> SplitShaftRenderer::new) - .onRegister(SplitShaftInstance::register) .register(); public static final TileEntityEntry ROTATION_SPEED_CONTROLLER = Create.registrate() .tileEntity("rotation_speed_controller", SpeedControllerTileEntity::new) + .instance(() -> ShaftInstance::new) .validBlocks(AllBlocks.ROTATION_SPEED_CONTROLLER) .renderer(() -> SpeedControllerRenderer::new) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry SPEEDOMETER = Create.registrate() .tileEntity("speedometer", SpeedGaugeTileEntity::new) + .instance(() -> GaugeInstance.Speed::new) .validBlocks(AllBlocks.SPEEDOMETER) .renderer(() -> GaugeRenderer::speed) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry STRESSOMETER = Create.registrate() .tileEntity("stressometer", StressGaugeTileEntity::new) + .instance(() -> GaugeInstance.Stress::new) .validBlocks(AllBlocks.STRESSOMETER) .renderer(() -> GaugeRenderer::stress) - .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry ANALOG_LEVER = Create.registrate() .tileEntity("analog_lever", AnalogLeverTileEntity::new) + .instance(() -> AnalogLeverInstance::new) .validBlocks(AllBlocks.ANALOG_LEVER) .renderer(() -> AnalogLeverRenderer::new) .register(); @@ -588,6 +581,7 @@ public class AllTileEntities { public static final TileEntityEntry FUNNEL = Create.registrate() .tileEntity("funnel", FunnelTileEntity::new) + .instance(() -> FunnelInstance::new) .validBlocks(AllBlocks.BRASS_FUNNEL, AllBlocks.BRASS_BELT_FUNNEL, AllBlocks.ANDESITE_FUNNEL, AllBlocks.ANDESITE_BELT_FUNNEL) .renderer(() -> FunnelRenderer::new) diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index e698cfe85..cd696310b 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -1,10 +1,5 @@ package com.simibubi.create; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity; @@ -14,15 +9,20 @@ import com.simibubi.create.content.schematics.client.SchematicHandler; import com.simibubi.create.foundation.ResourceReloadHandler; import com.simibubi.create.foundation.block.render.CustomBlockModels; import com.simibubi.create.foundation.block.render.SpriteShifter; +import com.simibubi.create.foundation.gui.UIRenderHelper; import com.simibubi.create.foundation.item.CustomItemModels; import com.simibubi.create.foundation.item.CustomRenderedItems; +import com.simibubi.create.foundation.ponder.content.PonderIndex; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.render.AllProgramSpecs; import com.simibubi.create.foundation.render.KineticRenderer; import com.simibubi.create.foundation.render.SuperByteBufferCache; import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.OptifineHandler; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.utility.WorldAttached; import com.simibubi.create.foundation.utility.ghost.GhostBlocks; import com.simibubi.create.foundation.utility.outliner.Outliner; - import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BlockModelShapes; @@ -33,6 +33,7 @@ import net.minecraft.item.Item; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.IWorld; import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.TextureStitchEvent; @@ -40,13 +41,19 @@ import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + public class CreateClient { public static ClientSchematicLoader schematicSender; public static SchematicHandler schematicHandler; public static SchematicAndQuillHandler schematicAndQuillHandler; public static SuperByteBufferCache bufferCache; - public static KineticRenderer kineticRenderer; + public static WorldAttached kineticRenderer; public static final Outliner outliner = new Outliner(); public static GhostBlocks ghostBlocks; @@ -68,7 +75,8 @@ public class CreateClient { } public static void clientInit(FMLClientSetupEvent event) { - kineticRenderer = new KineticRenderer(); + AllProgramSpecs.init(); + kineticRenderer = new WorldAttached<>(KineticRenderer::new); schematicSender = new ClientSchematicLoader(); schematicHandler = new SchematicHandler(); @@ -77,6 +85,7 @@ public class CreateClient { bufferCache = new SuperByteBufferCache(); bufferCache.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE); bufferCache.registerCompartment(ContraptionRenderDispatcher.CONTRAPTION, 20); + bufferCache.registerCompartment(WorldSectionElement.DOC_WORLD_SECTION, 20); ghostBlocks = new GhostBlocks(); @@ -86,6 +95,10 @@ public class CreateClient { AllEntityTypes.registerRenderers(); getColorHandler().init(); AllFluids.assignRenderLayers(); + PonderIndex.register(); + PonderIndex.registerTags(); + + UIRenderHelper.init(); IResourceManager resourceManager = Minecraft.getInstance() .getResourceManager(); @@ -185,8 +198,18 @@ public class CreateClient { } public static void invalidateRenderers() { - CreateClient.bufferCache.invalidate(); - CreateClient.kineticRenderer.invalidate(); + invalidateRenderers(null); + } + + public static void invalidateRenderers(@Nullable IWorld world) { + bufferCache.invalidate(); + + if (world != null) { + kineticRenderer.get(world).invalidate(); + } else { + kineticRenderer.forEach(InstancedTileRenderer::invalidate); + } + ContraptionRenderDispatcher.invalidateAll(); } } diff --git a/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java b/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java index de757db48..fd502605e 100644 --- a/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java +++ b/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java @@ -1,5 +1,38 @@ package com.simibubi.create.compat.jei; +import com.google.common.base.Predicates; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.Create; +import com.simibubi.create.compat.jei.category.*; +import com.simibubi.create.compat.jei.category.BlockCuttingCategory.CondensedBlockCuttingRecipe; +import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity; +import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; +import com.simibubi.create.content.contraptions.fluids.recipe.PotionMixingRecipeManager; +import com.simibubi.create.content.contraptions.processing.BasinRecipe; +import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateScreen; +import com.simibubi.create.content.logistics.item.filter.AbstractFilterScreen; +import com.simibubi.create.content.logistics.item.filter.AttributeFilterScreen; +import com.simibubi.create.content.logistics.item.filter.FilterScreen; +import com.simibubi.create.content.schematics.block.SchematicTableScreen; +import com.simibubi.create.content.schematics.block.SchematicannonScreen; +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.config.CRecipes; +import com.simibubi.create.foundation.config.ConfigBase.ConfigBool; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.registration.*; +import mezz.jei.api.runtime.IIngredientManager; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.item.crafting.*; +import net.minecraft.util.IItemProvider; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.ModList; + +import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -8,63 +41,6 @@ import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; -import javax.annotation.Nonnull; - -import com.google.common.base.Predicates; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllItems; -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.Create; -import com.simibubi.create.compat.jei.category.BlockCuttingCategory; -import com.simibubi.create.compat.jei.category.BlockCuttingCategory.CondensedBlockCuttingRecipe; -import com.simibubi.create.compat.jei.category.BlockzapperUpgradeCategory; -import com.simibubi.create.compat.jei.category.CreateRecipeCategory; -import com.simibubi.create.compat.jei.category.CrushingCategory; -import com.simibubi.create.compat.jei.category.FanBlastingCategory; -import com.simibubi.create.compat.jei.category.FanSmokingCategory; -import com.simibubi.create.compat.jei.category.FanWashingCategory; -import com.simibubi.create.compat.jei.category.ItemDrainCategory; -import com.simibubi.create.compat.jei.category.MechanicalCraftingCategory; -import com.simibubi.create.compat.jei.category.MillingCategory; -import com.simibubi.create.compat.jei.category.MixingCategory; -import com.simibubi.create.compat.jei.category.MysteriousItemConversionCategory; -import com.simibubi.create.compat.jei.category.PackingCategory; -import com.simibubi.create.compat.jei.category.PolishingCategory; -import com.simibubi.create.compat.jei.category.PressingCategory; -import com.simibubi.create.compat.jei.category.ProcessingViaFanCategory; -import com.simibubi.create.compat.jei.category.SawingCategory; -import com.simibubi.create.compat.jei.category.SpoutCategory; -import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity; -import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; -import com.simibubi.create.content.contraptions.fluids.recipe.PotionMixingRecipeManager; -import com.simibubi.create.content.contraptions.processing.BasinRecipe; -import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateScreen; -import com.simibubi.create.content.logistics.item.filter.AbstractFilterScreen; -import com.simibubi.create.content.schematics.block.SchematicannonScreen; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.config.CRecipes; -import com.simibubi.create.foundation.config.ConfigBase.ConfigBool; - -import mezz.jei.api.IModPlugin; -import mezz.jei.api.JeiPlugin; -import mezz.jei.api.registration.IGuiHandlerRegistration; -import mezz.jei.api.registration.IRecipeCatalystRegistration; -import mezz.jei.api.registration.IRecipeCategoryRegistration; -import mezz.jei.api.registration.IRecipeRegistration; -import mezz.jei.api.registration.ISubtypeRegistration; -import mezz.jei.api.runtime.IIngredientManager; -import net.minecraft.client.Minecraft; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.item.crafting.ICraftingRecipe; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.item.crafting.IRecipeSerializer; -import net.minecraft.item.crafting.IRecipeType; -import net.minecraft.item.crafting.ShapedRecipe; -import net.minecraft.util.IItemProvider; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.ModList; - @JeiPlugin @SuppressWarnings("unused") public class CreateJEI implements IModPlugin { @@ -226,8 +202,12 @@ public class CreateJEI implements IModPlugin { @Override public void registerGuiHandlers(IGuiHandlerRegistration registration) { - registration.addGuiContainerHandler(AdjustableCrateScreen.class, new SlotMover<>()); - registration.addGuiContainerHandler(SchematicannonScreen.class, new SlotMover<>()); + SlotMover slotMover = new SlotMover(); + registration.addGuiContainerHandler(AdjustableCrateScreen.class, slotMover); + registration.addGuiContainerHandler(SchematicannonScreen.class, slotMover); + registration.addGuiContainerHandler(SchematicTableScreen.class, slotMover); + registration.addGuiContainerHandler(FilterScreen.class, slotMover); + registration.addGuiContainerHandler(AttributeFilterScreen.class, slotMover); registration.addGhostIngredientHandler(AbstractFilterScreen.class, new FilterGhostIngredientHandler()); } diff --git a/src/main/java/com/simibubi/create/compat/jei/SlotMover.java b/src/main/java/com/simibubi/create/compat/jei/SlotMover.java index 3188e3324..e6ec1ef42 100644 --- a/src/main/java/com/simibubi/create/compat/jei/SlotMover.java +++ b/src/main/java/com/simibubi/create/compat/jei/SlotMover.java @@ -1,22 +1,20 @@ package com.simibubi.create.compat.jei; -import java.util.List; - import com.simibubi.create.foundation.gui.AbstractSimiContainerScreen; - import mezz.jei.api.gui.handlers.IGuiContainerHandler; import net.minecraft.client.renderer.Rectangle2d; -import net.minecraft.inventory.container.Container; + +import java.util.List; /** * Allows a {@link AbstractSimiContainerScreen} to specify an area in getExtraArea() that will be avoided by JEI * * Name is taken from CoFHCore's 1.12 implementation. */ -public class SlotMover implements IGuiContainerHandler> { +public class SlotMover implements IGuiContainerHandler> { @Override - public List getGuiExtraAreas(AbstractSimiContainerScreen containerScreen) { + public List getGuiExtraAreas(AbstractSimiContainerScreen containerScreen) { return containerScreen.getExtraAreas(); } } diff --git a/src/main/java/com/simibubi/create/compat/jei/category/BlockCuttingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/BlockCuttingCategory.java index 24965ab5e..3f701ef8f 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/BlockCuttingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/BlockCuttingCategory.java @@ -1,16 +1,11 @@ package com.simibubi.create.compat.jei.category; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.compat.jei.category.BlockCuttingCategory.CondensedBlockCuttingRecipe; import com.simibubi.create.compat.jei.category.animations.AnimatedSaw; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.item.ItemHelper; - import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; @@ -22,6 +17,10 @@ import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.StonecuttingRecipe; import net.minecraft.util.ResourceLocation; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public class BlockCuttingCategory extends CreateRecipeCategory { private AnimatedSaw saw = new AnimatedSaw(); @@ -34,7 +33,7 @@ public class BlockCuttingCategory extends CreateRecipeCategory getRecipeClass() { return CondensedBlockCuttingRecipe.class; } - + @Override public void setIngredients(CondensedBlockCuttingRecipe recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); @@ -119,6 +118,11 @@ public class BlockCuttingCategory extends CreateRecipeCategory> implements IRecipeCategory { public List> recipeCatalysts = new ArrayList<>(); @@ -104,11 +103,10 @@ public abstract class CreateRecipeCategory> implements IRec ProcessingOutput output = results.get(slotIndex - 1); float chance = output.getChance(); if (chance != 1) - tooltip.add(1, Lang.translate("recipe.processing.chance", chance < 0.01 ? "<1" : (int) (chance * 100)) - .formatted(TextFormatting.GOLD)); + tooltip.add(1, Lang.translate("recipe.processing.chance", chance < 0.01 ? "<1" : (int) (chance * 100)).formatted(TextFormatting.GOLD)); }); } - + public List withImprovedVisibility(List stacks) { return stacks.stream() .map(this::withImprovedVisibility) @@ -131,7 +129,7 @@ public abstract class CreateRecipeCategory> implements IRec fluidStacks.addTooltipCallback((slotIndex, input, fluid, tooltip) -> { if (fluid.getFluid() .isEquivalentTo(AllFluids.POTION.get())) { - ITextComponent name = PotionFluidHandler.getPotionName(fluid); + ITextComponent name = fluid.getDisplayName(); if (tooltip.isEmpty()) tooltip.add(0, name); else diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java index 2ff8f46ad..77b8aa0c7 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java @@ -3,7 +3,6 @@ package com.simibubi.create.compat.jei.category.animations; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import mezz.jei.api.gui.drawable.IDrawable; import net.minecraft.block.BlockState; import net.minecraft.state.properties.BlockStateProperties; @@ -12,7 +11,7 @@ import net.minecraft.util.Direction.Axis; public abstract class AnimatedKinetics implements IDrawable { public static float getCurrentAngle() { - return ((AnimationTickHolder.getRenderTick()) * 4f) % 360; + return ((AnimationTickHolder.getRenderTime()) * 4f) % 360; } protected BlockState shaft(Axis axis) { diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMixer.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMixer.java index 011e34801..32522a5ae 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMixer.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMixer.java @@ -5,7 +5,6 @@ import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.gui.GuiGameElement; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3f; @@ -30,7 +29,7 @@ public class AnimatedMixer extends AnimatedKinetics { .scale(scale) .render(matrixStack); - float animation = ((MathHelper.sin(AnimationTickHolder.getRenderTick() / 32f) + 1) / 5) + .5f; + float animation = ((MathHelper.sin(AnimationTickHolder.getRenderTime() / 32f) + 1) / 5) + .5f; GuiGameElement.of(AllBlockPartials.MECHANICAL_MIXER_POLE) .atLocal(0, animation, 0) diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java index e1567d2b4..345c1d249 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java @@ -5,7 +5,6 @@ import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.gui.GuiGameElement; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.vector.Vector3f; @@ -49,7 +48,7 @@ public class AnimatedPress extends AnimatedKinetics { } private float getAnimatedHeadOffset() { - float cycle = (AnimationTickHolder.getRenderTick()) % 30; + float cycle = (AnimationTickHolder.getRenderTime()) % 30; if (cycle < 10) { float progress = cycle / 10; return -(progress * progress * progress); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java index b866f9924..744ba4cdb 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java @@ -1,14 +1,11 @@ package com.simibubi.create.compat.jei.category.animations; -import java.util.List; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.fluid.FluidRenderer; import com.simibubi.create.foundation.gui.GuiGameElement; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer.Impl; import net.minecraft.client.renderer.Tessellator; @@ -16,6 +13,8 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3f; import net.minecraftforge.fluids.FluidStack; +import java.util.List; + public class AnimatedSpout extends AnimatedKinetics { private List fluids; @@ -37,7 +36,7 @@ public class AnimatedSpout extends AnimatedKinetics { .scale(scale) .render(matrixStack); - float cycle = AnimationTickHolder.getRenderTick() % 30; + float cycle = AnimationTickHolder.getRenderTime() % 30; float squeeze = cycle < 20 ? MathHelper.sin((float) (cycle / 20f * Math.PI)) : 0; squeeze *= 20; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java index 0d566b45f..185815e03 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java @@ -1,21 +1,11 @@ package com.simibubi.create.content.contraptions.base; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; - import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; public class BackHalfShaftInstance extends HalfShaftInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, BackHalfShaftInstance::new)); - } - - public BackHalfShaftInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public BackHalfShaftInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java index 6e70b9780..5c02bd90c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java @@ -2,21 +2,11 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; - import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; public class HalfShaftInstance extends SingleRotatingInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, HalfShaftInstance::new)); - } - public HalfShaftInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java index 958305113..2db938ca4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java @@ -1,19 +1,10 @@ package com.simibubi.create.content.contraptions.base; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; - import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; public class HorizontalHalfShaftInstance extends HalfShaftInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, HorizontalHalfShaftInstance::new)); - } public HorizontalHalfShaftInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java index f03ef0947..563e6fbb6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java @@ -1,15 +1,15 @@ package com.simibubi.create.content.contraptions.base; -import java.nio.ByteBuffer; - import com.simibubi.create.foundation.render.backend.instancing.InstanceData; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.impl.IFlatLight; import com.simibubi.create.foundation.utility.ColorHelper; - import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3f; -public class KineticData> extends InstanceData { +import java.nio.ByteBuffer; + +public class KineticData> extends InstanceData implements IFlatLight { private float x; private float y; private float z; @@ -58,11 +58,20 @@ public class KineticData> extends InstanceData { return (D) this; } + public D nudge(float x, float y, float z) { + this.x += x; + this.y += y; + this.z += z; + return (D) this; + } + + @Override public D setBlockLight(int blockLight) { this.blockLight = (byte) ((blockLight & 0xF) << 4); return (D) this; } + @Override public D setSkyLight(int skyLight) { this.skyLight = (byte) ((skyLight & 0xF) << 4); return (D) this; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java index 49223a3cb..8d3d32d31 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.content.contraptions.components.actors.ContraptionActorData; import com.simibubi.create.content.contraptions.relays.belt.BeltData; +import com.simibubi.create.content.logistics.block.FlapData; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.MaterialType; @@ -10,4 +11,6 @@ public class KineticRenderMaterials { public static final MaterialType> BELTS = new MaterialType<>(); public static final MaterialType> ACTORS = new MaterialType<>(); + + public static final MaterialType> FLAPS = new MaterialType<>(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java index 648c2aa01..8082f35ee 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java @@ -1,21 +1,12 @@ package com.simibubi.create.content.contraptions.base; -import static net.minecraft.util.text.TextFormatting.GOLD; -import static net.minecraft.util.text.TextFormatting.GRAY; - -import java.util.List; - -import javax.annotation.Nullable; - import com.simibubi.create.Create; -import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.KineticNetwork; import com.simibubi.create.content.contraptions.RotationPropagator; import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; import com.simibubi.create.content.contraptions.base.IRotate.StressImpact; import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation; -import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; @@ -23,7 +14,6 @@ import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendere import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.utility.Lang; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.resources.I18n; @@ -43,7 +33,12 @@ import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; + +import javax.annotation.Nullable; +import java.util.List; + +import static net.minecraft.util.text.TextFormatting.GOLD; +import static net.minecraft.util.text.TextFormatting.GRAY; public abstract class KineticTileEntity extends SmartTileEntity implements ITickableTileEntity, IHaveGoggleInformation, IHaveHoveringInformation, IInstanceRendered { @@ -75,7 +70,7 @@ public abstract class KineticTileEntity extends SmartTileEntity @Override public void initialize() { - if (hasNetwork()) { + if (hasNetwork() && !world.isRemote) { KineticNetwork network = getOrCreateNetwork(); if (!network.initialized) network.initFromTE(capacity, stress, networkSize); @@ -224,6 +219,7 @@ public abstract class KineticTileEntity extends SmartTileEntity boolean overStressedBefore = overStressed; clearKineticInformation(); + cachedBoundingBox = null; // DO NOT READ kinetic information when placed after movement if (wasMoved) { super.fromTag(state, compound, clientPacket); @@ -528,19 +524,6 @@ public abstract class KineticTileEntity extends SmartTileEntity return block.hasIntegratedCogwheel(world, pos, state); } - @Override - public void onLoad() { - super.onLoad(); - if (world != null && world.isRemote) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.add(this)); - } - - @Override - public void onChunkUnloaded() { - if (world != null && world.isRemote) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.remove(this)); - } - @Override public void requestModelDataUpdate() { super.requestModelDataUpdate(); @@ -549,11 +532,6 @@ public abstract class KineticTileEntity extends SmartTileEntity } } - @Override - public void onChunkLightUpdate() { - CreateClient.kineticRenderer.onLightUpdate(this); - } - protected AxisAlignedBB cachedBoundingBox; @OnlyIn(Dist.CLIENT) public AxisAlignedBB getRenderBoundingBox() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java index cc27ee7f8..35db855a3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java @@ -12,7 +12,6 @@ import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.ColorHelper; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -58,7 +57,7 @@ public class KineticTileEntityRenderer extends SafeTileEntityRenderer extends T } protected final void updateRotation(InstanceKey key, Direction.Axis axis) { - key.modifyInstance(data -> { - data.setColor(tile.network) - .setRotationalSpeed(tile.getSpeed()) - .setRotationOffset(getRotationOffset(axis)) - .setRotationAxis(axis); - }); + key.getInstance() + .setColor(tile.network) + .setRotationalSpeed(tile.getSpeed()) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(axis); } - protected final Consumer setupFunc(float speed, Direction.Axis axis) { - return data -> { - data.setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) - .setSkyLight(world.getLightLevel(LightType.SKY, pos)) - .setTileEntity(tile) - .setRotationalSpeed(speed) - .setRotationOffset(getRotationOffset(axis)) - .setRotationAxis(axis); - }; - } + protected final InstanceKey setup(InstanceKey key, float speed, Direction.Axis axis) { + key.getInstance() + .setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) + .setSkyLight(world.getLightLevel(LightType.SKY, pos)) + .setTileEntity(tile) + .setRotationalSpeed(speed) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(axis); - protected final void relight(KineticData data) { - data.setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) - .setSkyLight(world.getLightLevel(LightType.SKY, pos)); + return key; } protected float getRotationOffset(final Direction.Axis axis) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticVertexAttributes.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticVertexAttributes.java index 46f8740f4..bb6585755 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticVertexAttributes.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticVertexAttributes.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IAttribSpec; import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; @@ -26,7 +27,7 @@ public enum KineticVertexAttributes implements IVertexAttrib { } @Override - public VertexAttribSpec attribSpec() { + public IAttribSpec attribSpec() { return spec; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/RotatingVertexAttributes.java b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingVertexAttributes.java index 677b18190..e264731cc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/RotatingVertexAttributes.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingVertexAttributes.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IAttribSpec; import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; @@ -22,7 +23,7 @@ public enum RotatingVertexAttributes implements IVertexAttrib { } @Override - public VertexAttribSpec attribSpec() { + public IAttribSpec attribSpec() { return spec; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/ShaftlessCogInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/ShaftlessCogInstance.java index ff96d5856..952846454 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/ShaftlessCogInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/ShaftlessCogInstance.java @@ -2,20 +2,11 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; -import net.minecraft.tileentity.TileEntityType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; - public class ShaftlessCogInstance extends SingleRotatingInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, ShaftlessCogInstance::new)); - } - public ShaftlessCogInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public ShaftlessCogInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java index 9008e2f44..2cd7aac57 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java @@ -1,34 +1,25 @@ package com.simibubi.create.content.contraptions.base; -import static com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer.KINETIC_TILE; - import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; - import net.minecraft.block.BlockState; -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; + +import static com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer.KINETIC_TILE; public class SingleRotatingInstance extends KineticTileInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, SingleRotatingInstance::new)); - } protected InstanceKey rotatingModelKey; - public SingleRotatingInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public SingleRotatingInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } @Override protected void init() { Direction.Axis axis = ((IRotate) lastState.getBlock()).getRotationAxis(lastState); - rotatingModelKey = getModel().setupInstance(setupFunc(tile.getSpeed(), axis)); + rotatingModelKey = setup(getModel().createInstance(), tile.getSpeed(), axis); } @Override @@ -39,7 +30,7 @@ public class SingleRotatingInstance extends KineticTileInstance owner) { super(owner); } @@ -57,6 +60,11 @@ public class ContraptionActorData extends InstanceData { return this; } + public ContraptionActorData setSpeed(float speed) { + this.speed = speed; + return this; + } + public ContraptionActorData setRotationAxis(Vector3f axis) { setRotationAxis(axis.getX(), axis.getY(), axis.getZ()); return this; @@ -81,15 +89,11 @@ public class ContraptionActorData extends InstanceData { return this; } - public ContraptionActorData setLocalRotation(Vector3f axis) { - setLocalRotation(axis.getX(), axis.getY(), axis.getZ()); - return this; - } - - public ContraptionActorData setLocalRotation(float localRotationX, float localRotationY, float localRotationZ) { - this.localRotationX = localRotationX; - this.localRotationY = localRotationY; - this.localRotationZ = localRotationZ; + public ContraptionActorData setLocalRotation(Quaternion q) { + this.qX = q.getX(); + this.qY = q.getY(); + this.qZ = q.getZ(); + this.qW = q.getW(); return this; } @@ -99,8 +103,9 @@ public class ContraptionActorData extends InstanceData { putVec2(buf, blockLight, skyLight); put(buf, rotationOffset); putVec3(buf, rotationAxisX, rotationAxisY, rotationAxisZ); - putVec3(buf, localRotationX, localRotationY, localRotationZ); + putVec4(buf, qX, qY, qZ, qW); putVec3(buf, rotationCenterX, rotationCenterY, rotationCenterZ); + put(buf, speed); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillActorInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillActorInstance.java new file mode 100644 index 000000000..acd1d0dc4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillActorInstance.java @@ -0,0 +1,61 @@ +package com.simibubi.create.content.contraptions.components.actors; + +import com.simibubi.create.AllBlockPartials; +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.ContraptionKineticRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.VecHelper; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.Quaternion; + +public class DrillActorInstance extends ActorInstance { + + InstanceKey drillHead; + private Direction facing; + + public DrillActorInstance(ContraptionKineticRenderer modelManager, MovementContext context) { + super(modelManager, context); + + RenderMaterial> renderMaterial = modelManager.getActorMaterial(); + + BlockState state = context.state; + + facing = state.get(DrillBlock.FACING); + + Direction.Axis axis = facing.getAxis(); + float eulerX = AngleHelper.verticalAngle(facing); + + float eulerY; + if (axis == Direction.Axis.Y) + eulerY = 0; + else + eulerY = facing.getHorizontalAngle() + ((axis == Direction.Axis.X) ? 180 : 0); + + drillHead = renderMaterial.getModel(AllBlockPartials.DRILL_HEAD, state).createInstance(); + + drillHead.getInstance() + .setPosition(context.localPos) + .setBlockLight(localBlockLight()) + .setRotationOffset(0) + .setRotationAxis(0, 0, 1) + .setLocalRotation(new Quaternion(eulerX, eulerY, 0, true)) + .setSpeed(getSpeed(facing)); + } + + @Override + protected void tick() { + drillHead.getInstance().setSpeed(getSpeed(facing)); + } + + @Override + protected float getSpeed(Direction facing) { + if (context.contraption.stalled || !VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite())) + return context.getAnimationSpeed(); + return 0; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java index 6ff6d7832..4ad1dd834 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java @@ -4,48 +4,15 @@ import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; -import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; -import com.simibubi.create.foundation.utility.AngleHelper; - -import net.minecraft.block.BlockState; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.Direction; -import net.minecraft.world.LightType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; public class DrillInstance extends SingleRotatingInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, DrillInstance::new)); } - public DrillInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public DrillInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } - public static void addInstanceForContraption(RenderedContraption contraption, MovementContext context) { - RenderMaterial> renderMaterial = contraption.getActorMaterial(); - - BlockState state = context.state; - InstancedModel model = renderMaterial.getModel(AllBlockPartials.DRILL_HEAD, state); - - model.setupInstance(data -> { - Direction facing = state.get(DrillBlock.FACING); - float eulerX = AngleHelper.verticalAngle(facing) + ((facing.getAxis() == Direction.Axis.Y) ? 180 : 0); - float eulerY = facing.getHorizontalAngle(); - data.setPosition(context.localPos) - .setBlockLight(contraption.renderWorld.getLightLevel(LightType.BLOCK, context.localPos)) - .setRotationOffset(0) - .setRotationAxis(0, 0, 1) - .setLocalRotation(eulerX, eulerY, 0); - }); - } - @Override protected InstancedModel getModel() { return AllBlockPartials.DRILL_HEAD.renderOnDirectionalSouthRotating(modelManager, tile.getBlockState()); 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 1198ea618..9fab0cbe9 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 @@ -2,10 +2,10 @@ package com.simibubi.create.content.contraptions.components.actors; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionKineticRenderer; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.util.DamageSource; @@ -15,6 +15,8 @@ import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import javax.annotation.Nullable; + public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour { @Override @@ -42,9 +44,10 @@ public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour { return true; } + @Nullable @Override - public void addInstance(RenderedContraption contraption, MovementContext context) { - DrillInstance.addInstanceForContraption(contraption, context); + public ActorInstance createInstance(ContraptionKineticRenderer kr, MovementContext context) { + return new DrillActorInstance(kr, context); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java index 8a73c8ec7..1cf206097 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.contraptions.components.actors; -import static net.minecraft.state.properties.BlockStateProperties.FACING; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; @@ -12,7 +10,6 @@ import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -42,9 +39,9 @@ public class DrillRenderer extends KineticTileEntityRenderer { Direction facing = state.get(DrillBlock.FACING); float speed = (float) (context.contraption.stalled - || !VecHelper.isVecPointingTowards(context.relativeMotion, state.get(FACING) + || !VecHelper.isVecPointingTowards(context.relativeMotion, facing .getOpposite()) ? context.getAnimationSpeed() : 0); - float time = AnimationTickHolder.getRenderTick() / 20; + float time = AnimationTickHolder.getRenderTime() / 20; float angle = (float) (((time * speed) % 360)); for (MatrixStack m : matrixStacks) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterActorInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterActorInstance.java new file mode 100644 index 000000000..d70a2c500 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterActorInstance.java @@ -0,0 +1,50 @@ +package com.simibubi.create.content.contraptions.components.actors; + +import com.simibubi.create.AllBlockPartials; +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.ContraptionKineticRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.Quaternion; +import net.minecraft.util.math.vector.Vector3f; + +import static net.minecraft.state.properties.BlockStateProperties.HORIZONTAL_FACING; + +public class HarvesterActorInstance extends ActorInstance { + + InstanceKey harvester; + private Direction facing; + + public HarvesterActorInstance(ContraptionKineticRenderer modelManager, MovementContext context) { + super(modelManager, context); + + RenderMaterial> renderMaterial = modelManager.getActorMaterial(); + + BlockState state = context.state; + + facing = state.get(HORIZONTAL_FACING); + float originOffset = 1 / 16f; + Vector3f rotOffset = new Vector3f(0.5f, -2 * originOffset + 0.5f, originOffset + 0.5f); + + harvester = renderMaterial.getModel(AllBlockPartials.HARVESTER_BLADE, state).createInstance(); + + float horizontalAngle = facing.getHorizontalAngle() + ((facing.getAxis() == Direction.Axis.X) ? 180 : 0); + harvester.getInstance() + .setPosition(context.localPos) + .setBlockLight(localBlockLight()) + .setRotationOffset(0) + .setRotationCenter(rotOffset) + .setRotationAxis(-1, 0, 0) + .setLocalRotation(new Quaternion(Vector3f.POSITIVE_Y, horizontalAngle, true)) + .setSpeed(getSpeed(facing)); + } + + @Override + protected void tick() { + harvester.getInstance().setSpeed(getSpeed(facing)); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java index 7c171e542..5b6dc8e51 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java @@ -1,24 +1,14 @@ package com.simibubi.create.content.contraptions.components.actors; -import static net.minecraft.block.HorizontalBlock.HORIZONTAL_FACING; - -import org.apache.commons.lang3.mutable.MutableBoolean; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionKineticRenderer; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.VecHelper; - -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.CocoaBlock; -import net.minecraft.block.CropsBlock; -import net.minecraft.block.KelpBlock; -import net.minecraft.block.KelpTopBlock; -import net.minecraft.block.SugarCaneBlock; +import net.minecraft.block.*; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.item.ItemStack; import net.minecraft.state.IntegerProperty; @@ -28,6 +18,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.common.IPlantable; +import org.apache.commons.lang3.mutable.MutableBoolean; + +import javax.annotation.Nullable; + +import static net.minecraft.block.HorizontalBlock.HORIZONTAL_FACING; public class HarvesterMovementBehaviour extends MovementBehaviour { @@ -42,9 +37,10 @@ public class HarvesterMovementBehaviour extends MovementBehaviour { return true; } + @Nullable @Override - public void addInstance(RenderedContraption contraption, MovementContext context) { - HarvesterRenderer.addInstanceForContraption(contraption, context); + public ActorInstance createInstance(ContraptionKineticRenderer kr, MovementContext context) { + return new HarvesterActorInstance(kr, context); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java index 532f4b660..08b963561 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java @@ -1,20 +1,14 @@ package com.simibubi.create.content.contraptions.components.actors; -import static net.minecraft.state.properties.BlockStateProperties.HORIZONTAL_FACING; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; import com.simibubi.create.foundation.render.SuperByteBuffer; -import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -22,8 +16,9 @@ import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; -import net.minecraft.util.math.vector.Vector3f; -import net.minecraft.world.LightType; +import net.minecraft.world.World; + +import static net.minecraft.state.properties.BlockStateProperties.HORIZONTAL_FACING; public class HarvesterRenderer extends SafeTileEntityRenderer { @@ -35,30 +30,13 @@ public class HarvesterRenderer extends SafeTileEntityRenderer> renderMaterial = contraption.getActorMaterial(); - - BlockState state = context.state; - InstancedModel model = renderMaterial.getModel(AllBlockPartials.HARVESTER_BLADE, state); - - model.setupInstance(data -> { - Direction facing = state.get(HORIZONTAL_FACING); - float originOffset = 1 / 16f; - Vector3f rotOffset = new Vector3f(0.5f, -2 * originOffset + 0.5f, originOffset + 0.5f); - data.setPosition(context.localPos) - .setBlockLight(contraption.renderWorld.getLightLevel(LightType.BLOCK, context.localPos)) - .setRotationOffset(0) - .setRotationCenter(rotOffset) - .setRotationAxis(-1, 0, 0) - .setLocalRotation(0, facing.getHorizontalAngle(), 0); - }); - } - public static void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal, IRenderTypeBuffer buffers) { BlockState blockState = context.state; @@ -67,23 +45,25 @@ public class HarvesterRenderer extends SafeTileEntityRenderer dropItem(context, s)); + } + } + @Override public void stopMoving(MovementContext context) { super.stopMoving(context); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java index 706477329..c5d14099f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java @@ -1,13 +1,10 @@ package com.simibubi.create.content.contraptions.components.actors; -import java.util.List; - import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.LerpedFloat; - +import com.simibubi.create.foundation.utility.animation.LerpedFloat; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.nbt.CompoundNBT; @@ -17,6 +14,8 @@ import net.minecraft.util.math.MathHelper; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import java.util.List; + public abstract class PortableStorageInterfaceTileEntity extends SmartTileEntity { protected int transferTimer; @@ -56,8 +55,9 @@ public abstract class PortableStorageInterfaceTileEntity extends SmartTileEntity public void tick() { super.tick(); boolean wasConnected = isConnected(); + int timeUnit = getTransferTimeout() / 2; - if (transferTimer > 0) { + if (transferTimer > 0 && (!isVirtual() || transferTimer != timeUnit)) { transferTimer--; if (transferTimer == 0 || powered) stopTransferring(); @@ -68,7 +68,6 @@ public abstract class PortableStorageInterfaceTileEntity extends SmartTileEntity markDirty(); float progress = 0; - int timeUnit = getTransferTimeout() / 2; if (isConnected) progress = 1; else if (transferTimer >= timeUnit * 3) @@ -107,12 +106,13 @@ public abstract class PortableStorageInterfaceTileEntity extends SmartTileEntity powered = isBlockPowered; sendData(); } - + public boolean isPowered() { return powered; } protected AxisAlignedBB cachedBoundingBox; + @Override @OnlyIn(Dist.CLIENT) public AxisAlignedBB getRenderBoundingBox() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java index faa25f9d3..8da527cd2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java @@ -1,7 +1,6 @@ package com.simibubi.create.content.contraptions.components.actors; import com.simibubi.create.AllEntityTypes; - import net.minecraft.client.renderer.culling.ClippingHelper; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererManager; @@ -15,6 +14,7 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; +import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.network.NetworkHooks; @@ -63,8 +63,9 @@ public class SeatEntity extends Entity implements IEntityAdditionalSpawnData { } @Override - protected boolean canBeRidden(Entity p_184228_1_) { - return true; + protected boolean canBeRidden(Entity entity) { + // Fake Players (tested with deployers) have a BUNCH of weird issues, don't let them ride seats + return !(entity instanceof FakePlayer); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterBlock.java index cfd7e9617..277fa0c16 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterBlock.java @@ -8,11 +8,12 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity.Phase; import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Pointing; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -234,6 +235,14 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock implements IT return ActionResultType.PASS; } + @Override + public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + InvManipulationBehaviour behaviour = TileEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); + if (behaviour != null) + behaviour.onNeighborChanged(fromPos); + } + @Override public float getParticleTargetRadius() { return .85f; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java index 5313cdbef..cb3d68883 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java @@ -1,27 +1,18 @@ package com.simibubi.create.content.contraptions.components.crafter; -import java.util.function.Supplier; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.utility.MatrixStacker; - -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; + +import java.util.function.Supplier; public class MechanicalCrafterInstance extends SingleRotatingInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, MechanicalCrafterInstance::new)); - } public MechanicalCrafterInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java index 56e037b84..e7848ca4b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java @@ -2,7 +2,6 @@ package com.simibubi.create.content.contraptions.components.crafter; import com.google.gson.JsonObject; import com.simibubi.create.AllRecipeTypes; - import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; @@ -36,6 +35,11 @@ public class MechanicalCraftingRecipe extends ShapedRecipe { return AllRecipeTypes.MECHANICAL_CRAFTING.type; } + @Override + public boolean isDynamic() { + return true; + } + @Override public IRecipeSerializer getSerializer() { return AllRecipeTypes.MECHANICAL_CRAFTING.serializer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankBlock.java index a6cc4c35f..9cd4a201c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankBlock.java @@ -6,7 +6,6 @@ import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.config.AllConfigs; - import net.minecraft.block.Block; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; @@ -55,11 +54,6 @@ public class HandCrankBlock extends DirectionalKineticBlock implements ITE te.turn(player.isSneaking())); player.addExhaustion(getRotationSpeed() * AllConfigs.SERVER.kinetics.crankHungerMultiplier.getF()); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankInstance.java new file mode 100644 index 000000000..b59c90a42 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankInstance.java @@ -0,0 +1,75 @@ +package com.simibubi.create.content.contraptions.components.crank; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; +import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.block.Block; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; + +public class HandCrankInstance extends SingleRotatingInstance implements ITickableInstance { + + private InstanceKey crank; + private Direction facing; + + public HandCrankInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + super.init(); + + Block block = lastState.getBlock(); + AllBlockPartials renderedHandle = null; + if (block instanceof HandCrankBlock) + renderedHandle = ((HandCrankBlock) block).getRenderedHandle(); + if (renderedHandle == null) + return; + + facing = lastState.get(BlockStateProperties.FACING); + InstancedModel model = renderedHandle.renderOnDirectionalSouthModel(modelManager, lastState, facing.getOpposite()); + crank = model.createInstance(); + + updateLight(); + } + + @Override + public void tick() { + if (crank == null) return; + + HandCrankTileEntity crankTile = (HandCrankTileEntity) tile; + + Direction.Axis axis = facing.getAxis(); + float angle = (crankTile.independentAngle + AnimationTickHolder.getPartialTicks() * crankTile.chasingVelocity) / 360; + + MatrixStack ms = new MatrixStack(); + MatrixStacker.of(ms) + .translate(getFloatingPos()) + .centre() + .rotate(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis), angle) + .unCentre(); + + crank.getInstance().setTransformNoCopy(ms); + } + + @Override + public void remove() { + super.remove(); + if (crank != null) crank.delete(); + } + + @Override + public void updateLight() { + super.updateLight(); + if (crank != null) relight(pos, crank.getInstance()); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankRenderer.java index ea2fbbda4..7ae91fe8f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankRenderer.java @@ -1,13 +1,11 @@ package com.simibubi.create.content.contraptions.components.crank; -import static net.minecraft.state.properties.BlockStateProperties.FACING; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.foundation.render.SuperByteBuffer; - +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -15,6 +13,8 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction; +import static net.minecraft.state.properties.BlockStateProperties.FACING; + public class HandCrankRenderer extends KineticTileEntityRenderer { public HandCrankRenderer(TileEntityRendererDispatcher dispatcher) { @@ -26,6 +26,8 @@ public class HandCrankRenderer extends KineticTileEntityRenderer { int light, int overlay) { super.renderSafe(te, partialTicks, ms, buffer, light, overlay); + if (FastRenderDispatcher.available(te.getWorld())) return; + BlockState state = te.getBlockState(); Block block = state.getBlock(); AllBlockPartials renderedHandle = null; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java index 8fce2390b..459c1e91f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java @@ -1,13 +1,5 @@ package com.simibubi.create.content.contraptions.components.crusher; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Random; -import java.util.UUID; - -import static com.simibubi.create.content.contraptions.components.crusher.CrushingWheelControllerBlock.FACING; - import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.content.contraptions.processing.ProcessingInventory; import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; @@ -18,9 +10,9 @@ import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; @@ -43,6 +35,10 @@ import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.RecipeWrapper; +import java.util.*; + +import static com.simibubi.create.content.contraptions.components.crusher.CrushingWheelControllerBlock.FACING; + public class CrushingWheelControllerTileEntity extends SmartTileEntity { public Entity processingEntity; @@ -200,12 +196,25 @@ public class CrushingWheelControllerTileEntity extends SmartTileEntity { return; if (!(processingEntity instanceof ItemEntity)) { + Vector3d entityOutPos = outPos.add(facing.getAxis() == Axis.X ? .5f * offset : 0f + , facing.getAxis() == Axis.Y ? .5f * offset : 0f + , facing.getAxis() == Axis.Z ? .5f * offset : 0f); + int crusherDamage = AllConfigs.SERVER.kinetics.crushingDamage.get(); + + if (processingEntity instanceof LivingEntity) { + if ((((LivingEntity) processingEntity).getHealth() - crusherDamage <= 0) //Takes LivingEntity instances as exception, so it can move them before it would kill them. + && (((LivingEntity) processingEntity).hurtTime <= 0)) { //This way it can actually output the items to the right spot. + processingEntity.setPosition(entityOutPos.x + , entityOutPos.y + , entityOutPos.z); + } + } processingEntity.attackEntityFrom(CrushingWheelTileEntity.damageSource, - AllConfigs.SERVER.kinetics.crushingDamage.get()); + crusherDamage); if (!processingEntity.isAlive()) { - processingEntity.setPosition(outPos.x + (facing.getAxis() == Axis.X ? .75f * offset : 0f) //This is supposed to move the mobs to the output location - , outPos.y + (facing.getAxis() == Axis.Y ? .75f * offset : 0f) //So the item drops end up on the other end - , outPos.z + (facing.getAxis() == Axis.Z ? .75f * offset : 0f)); //This, however, does not currently work consistently for non-downwards crushers. + processingEntity.setPosition(entityOutPos.x + , entityOutPos.y + , entityOutPos.z); } return; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelTileEntity.java index 8d94992d5..6049c8299 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelTileEntity.java @@ -2,12 +2,13 @@ package com.simibubi.create.content.contraptions.components.crusher; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.utility.Iterate; - +import net.minecraft.entity.item.ItemEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.DamageSource; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; -import net.minecraftforge.event.entity.living.LivingDeathEvent; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraftforge.event.entity.living.LivingDropsEvent; import net.minecraftforge.event.entity.living.LootingLevelEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; @@ -50,14 +51,17 @@ public class CrushingWheelTileEntity extends KineticTileEntity { public static void crushingIsFortunate(LootingLevelEvent event) { if (event.getDamageSource() != damageSource) return; - event.setLootingLevel(2); + event.setLootingLevel(2); //This does not currently increase mob drops. It seems like this only works for damage done by an entity. } @SubscribeEvent - public static void crushingTeleportsEntities(LivingDeathEvent event) { - if (event.getSource() != damageSource) + public static void handleCrushedMobDrops(LivingDropsEvent event) { + if (event.getSource() != CrushingWheelTileEntity.damageSource) return; - event.getEntity().setPos(event.getEntity().getX(), Math.floor(event.getEntity().getY()) - .5f, event.getEntity().getZ()); + Vector3d outSpeed = Vector3d.ZERO; + for (ItemEntity outputItem : event.getDrops()) { + outputItem.setMotion(outSpeed); + } } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerActorInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerActorInstance.java new file mode 100644 index 000000000..b4f44bfdb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerActorInstance.java @@ -0,0 +1,96 @@ +package com.simibubi.create.content.contraptions.components.deployer; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.*; +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.ContraptionKineticRenderer; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionProgram; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.*; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3d; + +import static com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; +import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; + +public class DeployerActorInstance extends ActorInstance { + + Direction facing; + boolean stationaryTimer; + + float yRot; + float zRot; + float zRotPole; + + InstanceKey pole; + InstanceKey hand; + InstanceKey shaft; + + public DeployerActorInstance(ContraptionKineticRenderer modelManager, MovementContext context) { + super(modelManager, context); + + RenderMaterial> mat = modelManager.basicMaterial(); + + BlockState state = context.state; + DeployerTileEntity.Mode mode = NBTHelper.readEnum(context.tileData, "Mode", DeployerTileEntity.Mode.class); + AllBlockPartials handPose = DeployerRenderer.getHandPose(mode); + + stationaryTimer = context.data.contains("StationaryTimer"); + facing = state.get(FACING); + + boolean rotatePole = state.get(AXIS_ALONG_FIRST_COORDINATE) ^ facing.getAxis() == Direction.Axis.Z; + yRot = AngleHelper.horizontalAngle(facing); + zRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; + zRotPole = rotatePole ? 90 : 0; + + pole = mat.getModel(AllBlockPartials.DEPLOYER_POLE, state).createInstance(); + hand = mat.getModel(handPose, state).createInstance(); + + Direction.Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state); + shaft = modelManager.getMaterial(KineticRenderMaterials.ROTATING) + .getModel(KineticTileEntityRenderer.KINETIC_TILE, KineticTileInstance.shaft(axis)) + .createInstance(); + + int blockLight = localBlockLight(); + + shaft.getInstance() + .setBlockLight(blockLight) + .setRotationAxis(axis) + .setPosition(context.localPos); + + pole.getInstance().setBlockLight(blockLight); + hand.getInstance().setBlockLight(blockLight); + } + + @Override + protected void tick() { + double factor; + if (context.contraption.stalled || context.position == null || context.data.contains("StationaryTimer")) { + factor = MathHelper.sin(AnimationTickHolder.getRenderTime() * .5f) * .25f + .25f; + } else { + Vector3d center = VecHelper.getCenterOf(new BlockPos(context.position)); + double distance = context.position.distanceTo(center); + double nextDistance = context.position.add(context.motion) + .distanceTo(center); + factor = .5f - MathHelper.clamp(MathHelper.lerp(AnimationTickHolder.getPartialTicks(), distance, nextDistance), 0, 1); + } + + Vector3d offset = Vector3d.of(facing.getDirectionVec()).scale(factor); + + MatrixStack ms = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(ms); + + msr.translate(context.localPos) + .translate(offset); + + DeployerInstance.transformModel(msr, pole, hand, yRot, zRot, zRotPole); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerInstance.java new file mode 100644 index 000000000..9c16d01a9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerInstance.java @@ -0,0 +1,143 @@ +package com.simibubi.create.content.contraptions.components.deployer; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; +import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.util.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3d; + +import static com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; +import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; + +public class DeployerInstance extends ShaftInstance implements ITickableInstance { + + DeployerTileEntity tile; + + Direction facing; + + InstanceKey pole; + + AllBlockPartials currentHand; + InstanceKey hand; + + float yRot; + float zRot; + float zRotPole; + + float progress = Float.NaN; + + public DeployerInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + super(dispatcher, tile); + } + + @Override + protected void init() { + super.init(); + + this.tile = (DeployerTileEntity) super.tile; + facing = lastState.get(FACING); + + boolean rotatePole = lastState.get(AXIS_ALONG_FIRST_COORDINATE) ^ facing.getAxis() == Direction.Axis.Z; + + yRot = AngleHelper.horizontalAngle(facing); + zRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; + zRotPole = rotatePole ? 90 : 0; + + pole = modelManager.basicMaterial().getModel(AllBlockPartials.DEPLOYER_POLE, lastState).createInstance(); + + updateHandPose(); + relight(pos, pole.getInstance()); + } + + @Override + public void tick() { + + boolean newHand = updateHandPose(); + + float newProgress = getProgress(AnimationTickHolder.getPartialTicks()); + + if (!newHand && MathHelper.epsilonEquals(newProgress, progress)) return; + + progress = newProgress; + + MatrixStack ms = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(ms); + + msr.translate(getFloatingPos()) + .translate(getHandOffset()); + + transformModel(msr, pole, hand, yRot, zRot, zRotPole); + + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, hand.getInstance(), pole.getInstance()); + } + + @Override + public void remove() { + super.remove(); + hand.delete(); + pole.delete(); + currentHand = null; // updateHandPose() uses an invalid key after a block update otherwise. + hand = null; + } + + private boolean updateHandPose() { + AllBlockPartials handPose = tile.getHandPose(); + + if (currentHand == handPose) return false; + currentHand = handPose; + + if (hand != null) hand.delete(); + + hand = modelManager.basicMaterial().getModel(currentHand, lastState).createInstance(); + + relight(pos, hand.getInstance()); + + return true; + } + + protected Vector3d getHandOffset() { + float handLength = tile.getHandPose() == AllBlockPartials.DEPLOYER_HAND_POINTING ? 0 + : tile.getHandPose() == AllBlockPartials.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 16f; + float distance = Math.min(MathHelper.clamp(progress, 0, 1) * (tile.reach + handLength), 21 / 16f); + return Vector3d.of(facing.getDirectionVec()).scale(distance); + } + + private float getProgress(float partialTicks) { + if (tile.state == DeployerTileEntity.State.EXPANDING) + return 1 - (tile.timer - partialTicks * tile.getTimerSpeed()) / 1000f; + if (tile.state == DeployerTileEntity.State.RETRACTING) + return (tile.timer - partialTicks * tile.getTimerSpeed()) / 1000f; + return 0; + } + + static void transformModel(MatrixStacker msr, InstanceKey pole, InstanceKey hand, float yRot, float zRot, float zRotPole) { + + msr.centre(); + msr.rotate(Direction.SOUTH, (float) ((zRot) / 180 * Math.PI)); + msr.rotate(Direction.UP, (float) ((yRot) / 180 * Math.PI)); + + msr.push(); + msr.rotate(Direction.SOUTH, (float) ((zRotPole) / 180 * Math.PI)); + msr.unCentre(); + pole.getInstance().setTransform(msr.unwrap()); + msr.pop(); + + msr.unCentre(); + + hand.getInstance().setTransform(msr.unwrap()); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java index 14d8a335f..1fc78fa48 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java @@ -1,19 +1,16 @@ package com.simibubi.create.content.contraptions.components.deployer; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.lang3.tuple.Pair; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.Mode; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; 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.ContraptionKineticRenderer; import com.simibubi.create.content.logistics.item.filter.FilterItem; import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.NBTHelper; - import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; @@ -23,6 +20,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.Constants.NBT; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.List; public class DeployerMovementBehaviour extends MovementBehaviour { @@ -168,7 +170,18 @@ public class DeployerMovementBehaviour extends MovementBehaviour { @Override public void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal, IRenderTypeBuffer buffers) { - DeployerRenderer.renderInContraption(context, ms, msLocal, buffers); + if (!FastRenderDispatcher.available()) + DeployerRenderer.renderInContraption(context, ms, msLocal, buffers); } + @Override + public boolean hasSpecialInstancedRendering() { + return true; + } + + @Nullable + @Override + public ActorInstance createInstance(ContraptionKineticRenderer kr, MovementContext context) { + return new DeployerActorInstance(kr, context); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java index 06b42bbf0..b2c540244 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java @@ -1,15 +1,11 @@ package com.simibubi.create.content.contraptions.components.deployer; -import static com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; -import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.Mode; -import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.State; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.render.SuperByteBuffer; @@ -20,7 +16,6 @@ import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -39,6 +34,9 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3f; import net.minecraft.world.World; +import static com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; +import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; + public class DeployerRenderer extends SafeTileEntityRenderer { public DeployerRenderer(TileEntityRendererDispatcher dispatcher) { @@ -50,11 +48,17 @@ public class DeployerRenderer extends SafeTileEntityRenderer int light, int overlay) { renderItem(te, partialTicks, ms, buffer, light, overlay); FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay); + + if (FastRenderDispatcher.available(te.getWorld())) return; + renderComponents(te, partialTicks, ms, buffer, light, overlay); } protected void renderItem(DeployerTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + + if (te.heldItem.isEmpty()) return; + BlockState deployerState = te.getBlockState(); Vector3d offset = getHandOffset(te, partialTicks, deployerState).add(VecHelper.getCenterOf(BlockPos.ZERO)); ms.push(); @@ -89,7 +93,7 @@ public class DeployerRenderer extends SafeTileEntityRenderer ms.translate(0, isBlockItem ? 9 / 16f : 11 / 16f, 0); ms.scale(scale, scale, scale); transform = TransformType.GROUND; - ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(AnimationTickHolder.getRenderTick())); + ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(AnimationTickHolder.getRenderTime(te.getWorld()))); } else { float scale = punching ? .75f : isBlockItem ? .75f - 1 / 64f : .5f; @@ -123,18 +127,8 @@ public class DeployerRenderer extends SafeTileEntityRenderer } protected Vector3d getHandOffset(DeployerTileEntity te, float partialTicks, BlockState blockState) { - float progress = 0; - if (te.state == State.EXPANDING) - progress = 1 - (te.timer - partialTicks * te.getTimerSpeed()) / 1000f; - if (te.state == State.RETRACTING) - progress = (te.timer - partialTicks * te.getTimerSpeed()) / 1000f; - - float handLength = te.getHandPose() == AllBlockPartials.DEPLOYER_HAND_POINTING ? 0 - : te.getHandPose() == AllBlockPartials.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 16f; - float distance = Math.min(MathHelper.clamp(progress, 0, 1) * (te.reach + handLength), 21 / 16f); - Vector3d offset = Vector3d.of(blockState.get(FACING) - .getDirectionVec()).scale(distance); - return offset; + float distance = te.getHandOffset(partialTicks); + return Vector3d.of(blockState.get(FACING).getDirectionVec()).scale(distance); } protected BlockState getRenderedBlockState(KineticTileEntity te) { @@ -166,8 +160,7 @@ public class DeployerRenderer extends SafeTileEntityRenderer BlockPos pos = BlockPos.ZERO; Mode mode = NBTHelper.readEnum(context.tileData, "Mode", Mode.class); World world = context.world; - AllBlockPartials handPose = - mode == Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING : AllBlockPartials.DEPLOYER_HAND_POINTING; + AllBlockPartials handPose = getHandPose(mode); SuperByteBuffer pole = AllBlockPartials.DEPLOYER_POLE.renderOn(blockState); SuperByteBuffer hand = handPose.renderOn(blockState); @@ -176,7 +169,7 @@ public class DeployerRenderer extends SafeTileEntityRenderer double factor; if (context.contraption.stalled || context.position == null || context.data.contains("StationaryTimer")) { - factor = MathHelper.sin(AnimationTickHolder.getRenderTick() * .5f) * .25f + .25f; + factor = MathHelper.sin(AnimationTickHolder.getRenderTime() * .5f) * .25f + .25f; } else { Vector3d center = VecHelper.getCenterOf(new BlockPos(context.position)); double distance = context.position.distanceTo(center); @@ -198,4 +191,8 @@ public class DeployerRenderer extends SafeTileEntityRenderer .renderInto(ms, builder); } + static AllBlockPartials getHandPose(DeployerTileEntity.Mode mode) { + return mode == DeployerTileEntity.Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING : AllBlockPartials.DEPLOYER_HAND_POINTING; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java index 9bde88cb7..bfa759a3a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java @@ -1,10 +1,5 @@ package com.simibubi.create.content.contraptions.components.deployer; -import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; - -import java.util.ArrayList; -import java.util.List; - import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.KineticTileEntity; @@ -15,7 +10,7 @@ import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; - +import com.simibubi.create.foundation.utility.animation.LerpedFloat; import net.minecraft.block.BlockState; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; @@ -25,11 +20,7 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.*; import net.minecraft.util.math.RayTraceContext.BlockMode; import net.minecraft.util.math.RayTraceContext.FluidMode; import net.minecraft.util.math.vector.Vector3d; @@ -40,6 +31,11 @@ import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.IItemHandlerModifiable; +import java.util.ArrayList; +import java.util.List; + +import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; + public class DeployerTileEntity extends KineticTileEntity { protected State state; @@ -55,6 +51,8 @@ public class DeployerTileEntity extends KineticTileEntity { private LazyOptional invHandler; private ListNBT deferredInventoryList; + private LerpedFloat animatedOffset; + enum State { WAITING, EXPANDING, RETRACTING, DUMPING; } @@ -69,6 +67,8 @@ public class DeployerTileEntity extends KineticTileEntity { mode = Mode.USE; heldItem = ItemStack.EMPTY; redstoneLocked = false; + animatedOffset = LerpedFloat.linear() + .startWithValue(0); } @Override @@ -108,7 +108,7 @@ public class DeployerTileEntity extends KineticTileEntity { @Override public void tick() { super.tick(); - + if (getSpeed() == 0) return; if (!world.isRemote && player != null && player.blockBreakingProgress != null) { @@ -362,11 +362,11 @@ public class DeployerTileEntity extends KineticTileEntity { @Override public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap) && invHandler != null) + if (isItemHandlerCap(cap) && invHandler != null) return invHandler.cast(); return super.getCapability(cap, side); } - + @Override public boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { if (super.addToTooltip(tooltip, isPlayerSneaking)) @@ -383,4 +383,28 @@ public class DeployerTileEntity extends KineticTileEntity { public boolean shouldRenderAsTE() { return true; } + + public float getHandOffset(float partialTicks) { + if (isVirtual()) + return animatedOffset.getValue(partialTicks); + + float progress = 0; + int timerSpeed = getTimerSpeed(); + AllBlockPartials handPose = getHandPose(); + + if (state == State.EXPANDING) + progress = 1 - (timer - partialTicks * timerSpeed) / 1000f; + if (state == State.RETRACTING) + progress = (timer - partialTicks * timerSpeed) / 1000f; + float handLength = handPose == AllBlockPartials.DEPLOYER_HAND_POINTING ? 0 + : handPose == AllBlockPartials.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 16f; + float distance = Math.min(MathHelper.clamp(progress, 0, 1) * (reach + handLength), 21 / 16f); + + return distance; + } + + public void setAnimatedOffset(float offset) { + animatedOffset.setValue(offset); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java index 5bf8b87d2..dcb5652e5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.contraptions.components.fan; -import static net.minecraft.state.properties.BlockStateProperties.FACING; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; @@ -10,7 +8,6 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.WorldRenderer; @@ -18,6 +15,8 @@ import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction; import net.minecraft.util.math.MathHelper; +import static net.minecraft.state.properties.BlockStateProperties.FACING; + public class EncasedFanRenderer extends KineticTileEntityRenderer { public EncasedFanRenderer(TileEntityRendererDispatcher dispatcher) { @@ -41,7 +40,7 @@ public class EncasedFanRenderer extends KineticTileEntityRenderer { SuperByteBuffer fanInner = AllBlockPartials.ENCASED_FAN_INNER.renderOnDirectionalSouth(te.getBlockState(), direction.getOpposite()); - float time = AnimationTickHolder.getRenderTick(); + float time = AnimationTickHolder.getRenderTime(te.getWorld()); float speed = te.getSpeed() * 5; if (speed > 0) speed = MathHelper.clamp(speed, 80, 64 * 20); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java index 8522b5ebd..e8c4346f4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.contraptions.components.fan; -import javax.annotation.Nullable; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; @@ -9,7 +7,6 @@ import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlo import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.utility.BlockHelper; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; @@ -20,6 +17,8 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import javax.annotation.Nullable; + @MethodsReturnNonnullByDefault public class EncasedFanTileEntity extends GeneratingKineticTileEntity implements IAirCurrentSource { @@ -172,7 +171,9 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity implements public void tick() { super.tick(); - if (!world.isRemote && airCurrentUpdateCooldown-- <= 0) { + boolean server = !world.isRemote || isVirtual(); + + if (server && airCurrentUpdateCooldown-- <= 0) { airCurrentUpdateCooldown = AllConfigs.SERVER.kinetics.fanBlockCheckRate.get(); updateAirFlow = true; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java index c2fbf6d56..49a38cb42 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java @@ -1,34 +1,24 @@ package com.simibubi.create.content.contraptions.components.fan; -import static net.minecraft.state.properties.BlockStateProperties.FACING; - import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.IRotate; import com.simibubi.create.content.contraptions.base.KineticTileInstance; import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; - -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; -import net.minecraft.world.LightType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; + +import static net.minecraft.state.properties.BlockStateProperties.FACING; public class FanInstance extends KineticTileInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, FanInstance::new)); - } protected InstanceKey shaft; protected InstanceKey fan; - public FanInstance(InstancedTileRenderer modelManager, EncasedFanTileEntity tile) { + public FanInstance(InstancedTileRenderer modelManager, EncasedFanTileEntity tile) { super(modelManager, tile); } @@ -42,30 +32,22 @@ public class FanInstance extends KineticTileInstance { InstancedModel fanInner = AllBlockPartials.ENCASED_FAN_INNER.renderOnDirectionalSouthRotating(modelManager, lastState, direction.getOpposite()); - shaft = shaftHalf.setupInstance(data -> { - BlockPos behind = pos.offset(direction.getOpposite()); - int blockLight = world.getLightLevel(LightType.BLOCK, behind); - int skyLight = world.getLightLevel(LightType.SKY, behind); + shaft = shaftHalf.createInstance(); + shaft.getInstance() + .setRotationalSpeed(tile.getSpeed()) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) + .setTileEntity(tile); - data.setRotationalSpeed(tile.getSpeed()) - .setRotationOffset(getRotationOffset(axis)) - .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) - .setTileEntity(tile) - .setBlockLight(blockLight) - .setSkyLight(skyLight); - }); - fan = fanInner.setupInstance(data -> { - BlockPos inFront = pos.offset(direction); - int blockLight = world.getLightLevel(LightType.BLOCK, inFront); - int skyLight = world.getLightLevel(LightType.SKY, inFront); - data.setRotationalSpeed(getFanSpeed()) - .setRotationOffset(getRotationOffset(axis)) - .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) - .setTileEntity(tile) - .setBlockLight(blockLight) - .setSkyLight(skyLight); - }); + fan = fanInner.createInstance(); + fan.getInstance() + .setRotationalSpeed(getFanSpeed()) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) + .setTileEntity(tile); + + updateLight(); } private float getFanSpeed() { @@ -82,32 +64,22 @@ public class FanInstance extends KineticTileInstance { Direction.Axis axis = lastState.get(FACING).getAxis(); updateRotation(shaft, axis); - fan.modifyInstance(data -> { - data.setColor(tile.network) - .setRotationalSpeed(getFanSpeed()) - .setRotationOffset(getRotationOffset(axis)) - .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()); - }); + fan.getInstance() + .setColor(tile.network) + .setRotationalSpeed(getFanSpeed()) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()); } @Override public void updateLight() { final Direction direction = lastState.get(FACING); - shaft.modifyInstance(data -> { - BlockPos behind = pos.offset(direction.getOpposite()); - int blockLight = world.getLightLevel(LightType.BLOCK, behind); - int skyLight = world.getLightLevel(LightType.SKY, behind); - data.setBlockLight(blockLight) - .setSkyLight(skyLight); - }); - fan.modifyInstance(data -> { - BlockPos inFront = pos.offset(direction); - int blockLight = world.getLightLevel(LightType.BLOCK, inFront); - int skyLight = world.getLightLevel(LightType.SKY, inFront); - data.setBlockLight(blockLight) - .setSkyLight(skyLight); - }); + BlockPos behind = pos.offset(direction.getOpposite()); + relight(behind, shaft.getInstance()); + + BlockPos inFront = pos.offset(direction); + relight(inFront, fan.getInstance()); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java index f49c7dbef..cf0713744 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java @@ -1,34 +1,46 @@ package com.simibubi.create.content.contraptions.components.flywheel; -import java.util.function.Consumer; - +import com.google.common.collect.Lists; +import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.IRotate; import com.simibubi.create.content.contraptions.base.KineticTileInstance; import com.simibubi.create.content.contraptions.base.RotatingData; -import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; -import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; - -import net.minecraft.block.BlockState; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.Rotation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; +import net.minecraft.util.math.MathHelper; -public class FlyWheelInstance extends KineticTileInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, FlyWheelInstance::new)); - } +import java.util.Collections; +import java.util.List; + +public class FlyWheelInstance extends KineticTileInstance implements ITickableInstance { protected Direction facing; + protected boolean connectedLeft; + protected float connectorAngleMult; + + protected Direction connection; protected InstanceKey shaft; -// protected InstanceKey wheel; + + protected InstanceKey wheel; + protected InstanceKey upperRotating; + protected InstanceKey lowerRotating; + protected InstanceKey upperSliding; + protected InstanceKey lowerSliding; + + protected List> connectors; + + protected float lastAngle = Float.NaN; + + protected boolean firstFrame = true; public FlyWheelInstance(InstancedTileRenderer modelManager, FlywheelTileEntity tile) { super(modelManager, tile); @@ -39,38 +51,145 @@ public class FlyWheelInstance extends KineticTileInstance { facing = lastState.get(BlockStateProperties.HORIZONTAL_FACING); Direction.Axis axis = ((IRotate) lastState.getBlock()).getRotationAxis(lastState); - Consumer setup = setupFunc(tile.getSpeed(), axis); - shaft = shaftModel().setupInstance(setup); -// wheel = wheelModel().setupInstance(setup); + shaft = setup(shaftModel().createInstance(), tile.getSpeed(), axis); + + wheel = AllBlockPartials.FLYWHEEL.renderOnHorizontalModel(modelManager, lastState.rotate(Rotation.CLOCKWISE_90)).createInstance(); + + connection = FlywheelBlock.getConnection(lastState); + if (connection != null) { + connectedLeft = lastState.get(FlywheelBlock.CONNECTION) == FlywheelBlock.ConnectionState.LEFT; + + boolean flipAngle = connection.getAxis() == Direction.Axis.X ^ connection.getAxisDirection() == Direction.AxisDirection.NEGATIVE; + + connectorAngleMult = flipAngle ? -1 : 1; + + RenderMaterial> mat = modelManager.getMaterial(RenderMaterials.MODELS); + + upperRotating = mat.getModel(AllBlockPartials.FLYWHEEL_UPPER_ROTATING, lastState).createInstance(); + lowerRotating = mat.getModel(AllBlockPartials.FLYWHEEL_LOWER_ROTATING, lastState).createInstance(); + upperSliding = mat.getModel(AllBlockPartials.FLYWHEEL_UPPER_SLIDING, lastState).createInstance(); + lowerSliding = mat.getModel(AllBlockPartials.FLYWHEEL_LOWER_SLIDING, lastState).createInstance(); + + connectors = Lists.newArrayList(upperRotating, lowerRotating, upperSliding, lowerSliding); + } else { + connectors = Collections.emptyList(); + } + + updateLight(); + firstFrame = true; + } + + @Override + public void tick() { + + float partialTicks = AnimationTickHolder.getPartialTicks(); + + float speed = tile.visualSpeed.get(partialTicks) * 3 / 10f; + float angle = tile.angle + speed * partialTicks; + + if (!firstFrame && Math.abs(angle - lastAngle) < 0.001) return; + + MatrixStack ms = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(ms); + + msr.translate(getFloatingPos()); + + if (connection != null) { + float rotation = angle * connectorAngleMult; + + ms.push(); + rotateToFacing(msr, connection); + + ms.push(); + transformConnector(msr, true, true, rotation, connectedLeft); + upperRotating.getInstance().setTransform(ms); + ms.pop(); + + ms.push(); + transformConnector(msr, false, true, rotation, connectedLeft); + lowerRotating.getInstance().setTransform(ms); + ms.pop(); + + ms.push(); + transformConnector(msr, true, false, rotation, connectedLeft); + upperSliding.getInstance().setTransform(ms); + ms.pop(); + + ms.push(); + transformConnector(msr, false, false, rotation, connectedLeft); + lowerSliding.getInstance().setTransform(ms); + ms.pop(); + + ms.pop(); + } + + msr.centre() + .rotate(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, facing.getAxis()), AngleHelper.rad(angle)) + .unCentre(); + + wheel.getInstance().setTransformNoCopy(ms); + + lastAngle = angle; + firstFrame = false; } @Override protected void onUpdate() { Direction.Axis axis = ((IRotate) lastState.getBlock()).getRotationAxis(lastState); updateRotation(shaft, axis); -// updateRotation(wheel, axis); } @Override public void updateLight() { - shaft.modifyInstance(this::relight); -// wheel.modifyInstance(this::relight); + relight(pos, shaft.getInstance(), wheel.getInstance()); + + if (connection != null) { + relight(this.pos.offset(connection), connectors.stream().map(InstanceKey::getInstance)); + } } @Override public void remove() { shaft.delete(); - shaft = null; -// wheel.delete(); -// wheel = null; + wheel.delete(); + + connectors.forEach(InstanceKey::delete); + connectors.clear(); } protected InstancedModel shaftModel() { return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState, facing.getOpposite()); } - protected InstancedModel wheelModel() { - BlockState rotate = lastState.rotate(Rotation.CLOCKWISE_90); - return AllBlockPartials.FLYWHEEL.renderOnDirectionalSouthRotating(modelManager, rotate, rotate.get(BlockStateProperties.HORIZONTAL_FACING)); + protected void transformConnector(MatrixStacker ms, boolean upper, boolean rotating, float angle, boolean flip) { + float shift = upper ? 1 / 4f : -1 / 8f; + float offset = upper ? 1 / 4f : 1 / 4f; + float radians = (float) (angle / 180 * Math.PI); + float shifting = MathHelper.sin(radians) * shift + offset; + + float maxAngle = upper ? -5 : -15; + float minAngle = upper ? -45 : 5; + float barAngle = 0; + + if (rotating) + barAngle = MathHelper.lerp((MathHelper.sin((float) (radians + Math.PI / 2)) + 1) / 2, minAngle, maxAngle); + + float pivotX = (upper ? 8f : 3f) / 16; + float pivotY = (upper ? 8f : 2f) / 16; + float pivotZ = (upper ? 23f : 21.5f) / 16f; + + ms.translate(pivotX, pivotY, pivotZ + shifting); + if (rotating) + ms.rotate(Direction.EAST, AngleHelper.rad(barAngle)); + ms.translate(-pivotX, -pivotY, -pivotZ); + + if (flip && !upper) + ms.translate(9 / 16f, 0, 0); + } + + protected void rotateToFacing(MatrixStacker buffer, Direction facing) { + buffer.centre() + .rotate(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(facing))) + .unCentre(); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java index be3d3e108..ad0c22af8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.contraptions.components.flywheel; -import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; @@ -9,8 +7,8 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelBlock.ConnectionState; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AngleHelper; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -22,6 +20,8 @@ import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Rotation; import net.minecraft.util.math.MathHelper; +import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING; + public class FlywheelRenderer extends KineticTileEntityRenderer { public FlywheelRenderer(TileEntityRendererDispatcher dispatcher) { @@ -33,10 +33,11 @@ public class FlywheelRenderer extends KineticTileEntityRenderer { int light, int overlay) { super.renderSafe(te, partialTicks, ms, buffer, light, overlay); + if (FastRenderDispatcher.available(te.getWorld())) return; + BlockState blockState = te.getBlockState(); FlywheelTileEntity wte = (FlywheelTileEntity) te; - SuperByteBuffer wheel = AllBlockPartials.FLYWHEEL.renderOnHorizontal(blockState.rotate(Rotation.CLOCKWISE_90)); float speed = wte.visualSpeed.get(partialTicks) * 3 / 10f; float angle = wte.angle + speed * partialTicks; @@ -68,6 +69,7 @@ public class FlywheelRenderer extends KineticTileEntityRenderer { .renderInto(ms, vb); } + SuperByteBuffer wheel = AllBlockPartials.FLYWHEEL.renderOnHorizontal(blockState.rotate(Rotation.CLOCKWISE_90)); kineticRotationTransform(wheel, te, blockState.get(HORIZONTAL_FACING) .getAxis(), AngleHelper.rad(angle), light); wheel.renderInto(ms, vb); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java index c3dc7f193..54720d28e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java @@ -2,7 +2,6 @@ package com.simibubi.create.content.contraptions.components.flywheel; import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; @@ -77,7 +76,8 @@ public class FlywheelTileEntity extends GeneratingKineticTileEntity { super.tick(); if (world.isRemote) { - visualSpeed.target(getGeneratedSpeed()); + float targetSpeed = isVirtual() ? speed : getGeneratedSpeed(); + visualSpeed.target(targetSpeed); visualSpeed.tick(); angle += visualSpeed.value * 3 / 10f; angle %= 360; @@ -101,9 +101,4 @@ public class FlywheelTileEntity extends GeneratingKineticTileEntity { updateGeneratedRotation(); } } - - @Override - public boolean shouldRenderAsTE() { - return true; - } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineInstance.java new file mode 100644 index 000000000..30a87e688 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineInstance.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.contraptions.components.flywheel.engine; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.TileEntityInstance; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.block.Block; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; + +public class EngineInstance extends TileEntityInstance { + + protected InstanceKey frame; + + public EngineInstance(InstancedTileRenderer modelManager, EngineTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + Block block = lastState + .getBlock(); + if (!(block instanceof EngineBlock)) + return; + + EngineBlock engineBlock = (EngineBlock) block; + AllBlockPartials frame = engineBlock.getFrameModel(); + + Direction facing = lastState.get(BlockStateProperties.HORIZONTAL_FACING); + + this.frame = modelManager.getMaterial(RenderMaterials.MODELS).getModel(frame, lastState).createInstance(); + + float angle = AngleHelper.rad(AngleHelper.horizontalAngle(facing)); + + MatrixStack ms = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(ms); + + msr.translate(getFloatingPos()) + .nudge(tile.hashCode()) + .centre() + .rotate(Direction.UP, angle) + .unCentre() + .translate(0, 0, -1); + + this.frame.getInstance() + .setTransformNoCopy(ms); + + updateLight(); + } + + @Override + public void remove() { + frame.delete(); + } + + @Override + public void updateLight() { + relight(pos, frame.getInstance()); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineRenderer.java index 477348870..42cc92dfd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineRenderer.java @@ -2,9 +2,9 @@ package com.simibubi.create.content.contraptions.components.flywheel.engine; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; - import net.minecraft.block.Block; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -21,6 +21,9 @@ public class EngineRenderer extends SafeTileEntityRe @Override protected void renderSafe(T te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + + if (FastRenderDispatcher.available(te.getWorld())) return; + Block block = te.getBlockState() .getBlock(); if (block instanceof EngineBlock) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineTileEntity.java index 02eea9daf..b4f1f4cf6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineTileEntity.java @@ -1,13 +1,11 @@ package com.simibubi.create.content.contraptions.components.flywheel.engine; -import java.util.List; - import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelBlock; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelTileEntity; +import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; @@ -17,7 +15,9 @@ import net.minecraft.util.math.BlockPos; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public class EngineTileEntity extends SmartTileEntity { +import java.util.List; + +public class EngineTileEntity extends SmartTileEntity implements IInstanceRendered { public float appliedCapacity; public float appliedSpeed; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java index 329cc5e7b..cc06621a6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java @@ -5,19 +5,11 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; -import net.minecraft.tileentity.TileEntityType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; - public class MillStoneCogInstance extends SingleRotatingInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, MillStoneCogInstance::new)); } - public MillStoneCogInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public MillStoneCogInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java index 4220afa17..8b2f873f1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java @@ -8,7 +8,6 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -31,22 +30,23 @@ public class MechanicalMixerRenderer extends KineticTileEntityRenderer { @Override protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + + if (FastRenderDispatcher.available(te.getWorld())) return; + BlockState blockState = te.getBlockState(); MechanicalMixerTileEntity mixer = (MechanicalMixerTileEntity) te; BlockPos pos = te.getPos(); IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid()); - if (!FastRenderDispatcher.available(te.getWorld())) { - SuperByteBuffer superBuffer = AllBlockPartials.SHAFTLESS_COGWHEEL.renderOn(blockState); - standardKineticRotationTransform(superBuffer, te, light).renderInto(ms, vb); - } + SuperByteBuffer superBuffer = AllBlockPartials.SHAFTLESS_COGWHEEL.renderOn(blockState); + standardKineticRotationTransform(superBuffer, te, light).renderInto(ms, vb); int packedLightmapCoords = WorldRenderer.getLightmapCoordinates(te.getWorld(), blockState, pos); float renderedHeadOffset = mixer.getRenderedHeadOffset(partialTicks); float speed = mixer.getRenderedHeadRotationSpeed(partialTicks); - float time = AnimationTickHolder.getRenderTick(); - float angle = (float) (((time * speed * 6 / 10f) % 360) / 180 * (float) Math.PI); + float time = AnimationTickHolder.getRenderTime(te.getWorld()); + float angle = ((time * speed * 6 / 10f) % 360) / 180 * (float) Math.PI; SuperByteBuffer poleRender = AllBlockPartials.MECHANICAL_MIXER_POLE.renderOn(blockState); poleRender.translate(0, -renderedHeadOffset, 0) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixerInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixerInstance.java new file mode 100644 index 000000000..10f53c990 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixerInstance.java @@ -0,0 +1,100 @@ +package com.simibubi.create.content.contraptions.components.mixer; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.base.RotatingData; +import com.simibubi.create.content.contraptions.base.ShaftlessCogInstance; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.util.Direction; + +public class MixerInstance extends ShaftlessCogInstance implements ITickableInstance { + + private InstanceKey mixerHead; + private InstanceKey mixerPole; + + public MixerInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + super(dispatcher, tile); + } + + @Override + protected void init() { + super.init(); + + mixerHead = rotatingMaterial().getModel(AllBlockPartials.MECHANICAL_MIXER_HEAD, lastState) + .createInstance(); + + mixerHead.getInstance() + .setRotationAxis(Direction.Axis.Y); + + mixerPole = modelManager.getMaterial(RenderMaterials.MODELS) + .getModel(AllBlockPartials.MECHANICAL_MIXER_POLE, lastState) + .createInstance(); + + + MechanicalMixerTileEntity mixer = (MechanicalMixerTileEntity) tile; + float renderedHeadOffset = getRenderedHeadOffset(mixer); + + transformPole(renderedHeadOffset); + transformHead(mixer, renderedHeadOffset); + updateLight(); + } + + @Override + public void tick() { + MechanicalMixerTileEntity mixer = (MechanicalMixerTileEntity) tile; + + float renderedHeadOffset = getRenderedHeadOffset(mixer); + + if (mixer.running) { + transformPole(renderedHeadOffset); + } + + transformHead(mixer, renderedHeadOffset); + } + + private void transformHead(MechanicalMixerTileEntity mixer, float renderedHeadOffset) { + float speed = mixer.getRenderedHeadRotationSpeed(AnimationTickHolder.getPartialTicks()); + + mixerHead.getInstance() + .setPosition(pos) + .nudge(0, -renderedHeadOffset, 0) + .setRotationalSpeed(speed * 2); + } + + private void transformPole(float renderedHeadOffset) { + MatrixStack ms = new MatrixStack(); + + MatrixStacker msr = MatrixStacker.of(ms); + msr.translate(getFloatingPos()); + msr.translate(0, -renderedHeadOffset, 0); + + mixerPole.getInstance().setTransformNoCopy(ms); + } + + private float getRenderedHeadOffset(MechanicalMixerTileEntity mixer) { + return mixer.getRenderedHeadOffset(AnimationTickHolder.getPartialTicks()); + } + + @Override + public void updateLight() { + super.updateLight(); + + relight(pos.down(), mixerHead.getInstance()); + + relight(pos, mixerPole.getInstance()); + } + + @Override + public void remove() { + super.remove(); + mixerHead.delete(); + mixerPole.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java index 18f2353a7..7c9d45699 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java @@ -5,7 +5,7 @@ import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.foundation.render.SuperByteBuffer; - +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -29,13 +29,17 @@ public class MechanicalPressRenderer extends KineticTileEntityRenderer { int light, int overlay) { super.renderSafe(te, partialTicks, ms, buffer, light, overlay); + if (FastRenderDispatcher.available(te.getWorld())) return; + BlockPos pos = te.getPos(); BlockState blockState = te.getBlockState(); int packedLightmapCoords = WorldRenderer.getLightmapCoordinates(te.getWorld(), blockState, pos); float renderedHeadOffset = ((MechanicalPressTileEntity) te).getRenderedHeadOffset(partialTicks); SuperByteBuffer headRender = AllBlockPartials.MECHANICAL_PRESS_HEAD.renderOnHorizontal(blockState); - headRender.translate(0, -renderedHeadOffset, 0).light(packedLightmapCoords).renderInto(ms, buffer.getBuffer(RenderType.getSolid())); + headRender.translate(0, -renderedHeadOffset, 0) + .light(packedLightmapCoords) + .renderInto(ms, buffer.getBuffer(RenderType.getSolid())); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/PressInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/PressInstance.java new file mode 100644 index 000000000..bba66bdf4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/PressInstance.java @@ -0,0 +1,73 @@ +package com.simibubi.create.content.contraptions.components.press; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; + +public class PressInstance extends ShaftInstance implements ITickableInstance { + + private InstanceKey pressHead; + + public PressInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + super(dispatcher, tile); + } + + @Override + protected void init() { + super.init(); + + pressHead = modelManager.getMaterial(RenderMaterials.MODELS) + .getModel(AllBlockPartials.MECHANICAL_PRESS_HEAD, lastState) + .createInstance(); + + updateLight(); + transformModels((MechanicalPressTileEntity) tile); + } + + @Override + public void tick() { + MechanicalPressTileEntity press = (MechanicalPressTileEntity) tile; + if (!press.running) + return; + + transformModels(press); + } + + private void transformModels(MechanicalPressTileEntity press) { + float renderedHeadOffset = getRenderedHeadOffset(press); + + MatrixStack ms = new MatrixStack(); + + MatrixStacker msr = MatrixStacker.of(ms); + msr.translate(getFloatingPos()); + msr.translate(0, -renderedHeadOffset, 0); + + pressHead.getInstance() + .setTransformNoCopy(ms); + } + + private float getRenderedHeadOffset(MechanicalPressTileEntity press) { + return press.getRenderedHeadOffset(AnimationTickHolder.getPartialTicks()); + } + + @Override + public void updateLight() { + super.updateLight(); + + relight(pos, pressHead.getInstance()); + } + + @Override + public void remove() { + super.remove(); + pressHead.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java index 62060db98..1e01db67b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java @@ -1,28 +1,19 @@ package com.simibubi.create.content.contraptions.components.saw; -import static net.minecraft.state.properties.BlockStateProperties.FACING; - import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; - -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Rotation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; + +import static net.minecraft.state.properties.BlockStateProperties.FACING; public class SawInstance extends SingleRotatingInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, SawInstance::new)); - } - public SawInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public SawInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java index 0cb7b7631..45b30f78a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java @@ -1,12 +1,5 @@ package com.simibubi.create.content.contraptions.components.saw; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllTags; import com.simibubi.create.content.contraptions.components.actors.BlockBreakingKineticTileEntity; @@ -22,17 +15,8 @@ import com.simibubi.create.foundation.utility.TreeCutter.Tree; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.recipe.RecipeConditions; import com.simibubi.create.foundation.utility.recipe.RecipeFinder; - import mcp.MethodsReturnNonnullByDefault; -import net.minecraft.block.BambooBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.CactusBlock; -import net.minecraft.block.ChorusPlantBlock; -import net.minecraft.block.KelpBlock; -import net.minecraft.block.KelpTopBlock; -import net.minecraft.block.StemGrownBlock; -import net.minecraft.block.SugarCaneBlock; +import net.minecraft.block.*; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; @@ -59,6 +43,12 @@ import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import javax.annotation.ParametersAreNonnullByDefault; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; +import java.util.function.Predicate; +import java.util.stream.Collectors; @ParametersAreNonnullByDefault @@ -125,7 +115,7 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { if (inventory.remainingTime > 0) spawnParticles(inventory.getStackInSlot(0)); - if (world.isRemote) + if (world.isRemote && !isVirtual()) return; if (inventory.remainingTime < 20 && !inventory.appliedRecipe) { @@ -313,7 +303,7 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { return; if (inventory.isEmpty()) return; - if (world.isRemote) + if (world.isRemote && !isVirtual()) return; List> recipes = getRecipes(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java index bb2d5b4ad..effb5f9b9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java @@ -1,15 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; - -import org.apache.commons.lang3.mutable.MutableInt; -import org.apache.commons.lang3.tuple.MutablePair; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.content.contraptions.components.actors.SeatEntity; @@ -20,7 +10,6 @@ import com.simibubi.create.foundation.collision.Matrix3d; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.material.PushReaction; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; @@ -48,6 +37,11 @@ import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.PacketDistributor; +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.tuple.MutablePair; + +import java.util.*; +import java.util.Map.Entry; public abstract class AbstractContraptionEntity extends Entity implements IEntityAdditionalSpawnData { @@ -58,7 +52,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit protected Contraption contraption; protected boolean initialized; - private boolean prevPosInvalid; + protected boolean prevPosInvalid; private boolean ticking; public AbstractContraptionEntity(EntityType entityTypeIn, World worldIn) { @@ -253,6 +247,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit BlockInfo blockInfo = pair.left; MovementBehaviour actor = AllMovementBehaviours.of(blockInfo.state); + Vector3d oldMotion = context.motion; Vector3d actorPosition = toGlobalVector(VecHelper.getCenterOf(blockInfo.pos) .add(actor.getActiveAreaOffset(context)), 1); BlockPos gridPosition = new BlockPos(actorPosition); @@ -261,8 +256,6 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit context.rotation = v -> applyRotation(v, 1); context.position = actorPosition; - - Vector3d oldMotion = context.motion; if (!actor.isActive(context)) continue; if (newPosVisited && !context.stall) { @@ -649,4 +642,25 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit } + //@Override //TODO find 1.16 replacement + //public void updateAquatics() { + /* + Override this with an empty method to reduce enormous calculation time when contraptions are in water + WARNING: THIS HAS A BUNCH OF SIDE EFFECTS! + - Fluids will not try to change contraption movement direction + - this.inWater and this.isInWater() will return unreliable data + - entities riding a contraption will not cause water splashes (seats are their own entity so this should be fine) + - fall distance is not reset when the contraption is in water + - this.eyesInWater and this.canSwim() will always be false + - swimming state will never be updated + */ + // extinguish(); + //} + + @Override + public void setFire(int p_70015_1_) { + // Contraptions no longer catch fire + } + + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java index 6a50f3f2d..5fee880eb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java @@ -1,7 +1,6 @@ package com.simibubi.create.content.contraptions.components.structureMovement; import com.simibubi.create.foundation.config.AllConfigs; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.math.BlockPos; @@ -9,7 +8,7 @@ import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; public class AssemblyException extends Exception { - + private static final long serialVersionUID = 1L; public final ITextComponent component; private BlockPos position = null; @@ -21,7 +20,8 @@ public class AssemblyException extends Exception { CompoundNBT nbt = new CompoundNBT(); nbt.putString("Component", ITextComponent.Serializer.toJson(exception.component)); if (exception.hasPosition()) - nbt.putLong("Position", exception.getPosition().toLong()); + nbt.putLong("Position", exception.getPosition() + .toLong()); compound.put("LastException", nbt); } @@ -48,38 +48,35 @@ public class AssemblyException extends Exception { } public static AssemblyException unmovableBlock(BlockPos pos, BlockState state) { - AssemblyException e = new AssemblyException("unmovableBlock", - pos.getX(), - pos.getY(), - pos.getZ(), - new TranslationTextComponent(state.getBlock().getTranslationKey())); + AssemblyException e = new AssemblyException("unmovableBlock", pos.getX(), pos.getY(), pos.getZ(), + new TranslationTextComponent(state.getBlock() + .getTranslationKey())); e.position = pos; return e; } public static AssemblyException unloadedChunk(BlockPos pos) { - AssemblyException e = new AssemblyException("chunkNotLoaded", - pos.getX(), - pos.getY(), - pos.getZ()); + AssemblyException e = new AssemblyException("chunkNotLoaded", pos.getX(), pos.getY(), pos.getZ()); e.position = pos; return e; } public static AssemblyException structureTooLarge() { - return new AssemblyException("structureTooLarge", - AllConfigs.SERVER.kinetics.maxBlocksMoved.get()); + return new AssemblyException("structureTooLarge", AllConfigs.SERVER.kinetics.maxBlocksMoved.get()); } public static AssemblyException tooManyPistonPoles() { - return new AssemblyException("tooManyPistonPoles", - AllConfigs.SERVER.kinetics.maxPistonPoles.get()); + return new AssemblyException("tooManyPistonPoles", AllConfigs.SERVER.kinetics.maxPistonPoles.get()); } public static AssemblyException noPistonPoles() { return new AssemblyException("noPistonPoles"); } + public static AssemblyException notEnoughSails(int sails) { + return new AssemblyException("not_enough_sails", sails, AllConfigs.SERVER.kinetics.minimumWindmillSails.get()); + } + public boolean hasPosition() { return position != null; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java index 7b659a41a..16ed46e04 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java @@ -8,12 +8,9 @@ import com.simibubi.create.content.contraptions.components.actors.PortableStorag import com.simibubi.create.content.contraptions.components.crank.HandCrankBlock; import com.simibubi.create.content.contraptions.components.fan.NozzleBlock; import com.simibubi.create.content.contraptions.components.flywheel.engine.EngineBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.SailBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.*; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerBlock; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; @@ -23,25 +20,7 @@ import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankConnectivityHandler; import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock; import com.simibubi.create.foundation.utility.BlockHelper; - -import net.minecraft.block.AbstractPressurePlateBlock; -import net.minecraft.block.AbstractRailBlock; -import net.minecraft.block.BellBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.CarpetBlock; -import net.minecraft.block.DoorBlock; -import net.minecraft.block.FenceGateBlock; -import net.minecraft.block.FlowerPotBlock; -import net.minecraft.block.GrindstoneBlock; -import net.minecraft.block.HorizontalBlock; -import net.minecraft.block.HorizontalFaceBlock; -import net.minecraft.block.LadderBlock; -import net.minecraft.block.RedstoneDiodeBlock; -import net.minecraft.block.RedstoneWallTorchBlock; -import net.minecraft.block.RedstoneWireBlock; -import net.minecraft.block.TorchBlock; -import net.minecraft.block.WallTorchBlock; +import net.minecraft.block.*; import net.minecraft.block.material.PushReaction; import net.minecraft.state.properties.AttachFace; import net.minecraft.state.properties.BellAttachment; @@ -199,6 +178,10 @@ public class BlockMovementTraits { .getAxis(); if (state.getBlock() instanceof FluidTankBlock) return FluidTankConnectivityHandler.isConnected(world, pos, pos.offset(direction)); + if (AllBlocks.STICKER.has(state) && state.get(StickerBlock.EXTENDED)) { + return direction == state.get(StickerBlock.FACING) + && !notSupportive(world.getBlockState(pos.offset(direction)), direction.getOpposite()); + } return false; } @@ -232,6 +215,8 @@ public class BlockMovementTraits { if (AllBlocks.MECHANICAL_PISTON_HEAD.has(state)) return facing.getAxis() != state.get(BlockStateProperties.FACING) .getAxis(); + if (AllBlocks.STICKER.has(state) && !state.get(StickerBlock.EXTENDED)) + return facing == state.get(StickerBlock.FACING); return isBrittle(state); } 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 25bcf7cf7..e62698509 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 @@ -1,29 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; -import java.util.function.BiConsumer; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - -import org.apache.commons.lang3.tuple.MutablePair; -import org.apache.commons.lang3.tuple.Pair; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.content.contraptions.base.IRotate; @@ -34,7 +10,8 @@ import com.simibubi.create.content.contraptions.components.structureMovement.bea import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryPinionBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageBlock; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueHandler; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock; @@ -52,23 +29,12 @@ import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateBl import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.fluid.CombinedTankWrapper; +import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld; import com.simibubi.create.foundation.render.backend.light.EmptyLighter; -import com.simibubi.create.foundation.utility.BlockFace; -import com.simibubi.create.foundation.utility.BlockHelper; -import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.NBTHelper; -import com.simibubi.create.foundation.utility.NBTProcessors; -import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; +import com.simibubi.create.foundation.utility.*; import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; - -import net.minecraft.block.AbstractButtonBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.ChestBlock; -import net.minecraft.block.DoorBlock; -import net.minecraft.block.IWaterLoggable; -import net.minecraft.block.PressurePlateBlock; +import net.minecraft.block.*; import net.minecraft.block.material.PushReaction; import net.minecraft.entity.Entity; import net.minecraft.fluid.FluidState; @@ -85,12 +51,12 @@ import net.minecraft.state.properties.PistonType; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Rotation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.palette.HashMapPalette; +import net.minecraft.village.PointOfInterestType; import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; @@ -106,6 +72,16 @@ import net.minecraftforge.fluids.capability.templates.FluidTank; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.CombinedInvWrapper; import net.minecraftforge.registries.GameData; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; +import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; public abstract class Contraption { @@ -177,9 +153,10 @@ public abstract class Contraption { return contraption; } - public boolean searchMovedStructure(World world, BlockPos pos, @Nullable Direction forcedDirection) throws AssemblyException { + public boolean searchMovedStructure(World world, BlockPos pos, @Nullable Direction forcedDirection) + throws AssemblyException { initialPassengers.clear(); - Queue frontier = new LinkedList<>(); + Queue frontier = new UniqueLinkedList<>(); Set visited = new HashSet<>(); anchor = pos; @@ -292,12 +269,20 @@ public abstract class Contraption { if (AllBlocks.BELT.has(state)) moveBelt(pos, frontier, visited, state); - if (AllBlocks.GANTRY_PINION.has(state)) + if (AllBlocks.GANTRY_CARRIAGE.has(state)) moveGantryPinion(world, pos, frontier, visited, state); if (AllBlocks.GANTRY_SHAFT.has(state)) moveGantryShaft(world, pos, frontier, visited, state); + if (AllBlocks.STICKER.has(state) && state.get(StickerBlock.EXTENDED)) { + Direction offset = state.get(StickerBlock.FACING); + BlockPos attached = pos.offset(offset); + if (!visited.contains(attached) + && !BlockMovementTraits.notSupportive(world.getBlockState(attached), offset.getOpposite())) + frontier.add(attached); + } + // Bearings potentially create stabilized sub-contraptions if (AllBlocks.MECHANICAL_BEARING.has(state)) moveBearing(pos, frontier, visited, state); @@ -353,7 +338,8 @@ public abstract class Contraption { boolean brittle = BlockMovementTraits.isBrittle(blockState); boolean canStick = !brittle && state.canStickTo(blockState) && blockState.canStickTo(state); if (canStick) { - if (state.getPushReaction() == PushReaction.PUSH_ONLY || blockState.getPushReaction() == PushReaction.PUSH_ONLY) { + if (state.getPushReaction() == PushReaction.PUSH_ONLY + || blockState.getPushReaction() == PushReaction.PUSH_ONLY) { canStick = false; } if (BlockMovementTraits.notSupportive(state, offset)) { @@ -364,7 +350,8 @@ public abstract class Contraption { } } - if (!wasVisited && (canStick || blockAttachedTowardsFace || faceHasGlue || (offset == forcedDirection && !BlockMovementTraits.notSupportive(state, forcedDirection)))) + if (!wasVisited && (canStick || blockAttachedTowardsFace || faceHasGlue + || (offset == forcedDirection && !BlockMovementTraits.notSupportive(state, forcedDirection)))) frontier.add(offsetPos); if (faceHasGlue) addGlue(superglue.get(offset)); @@ -424,7 +411,7 @@ public abstract class Contraption { protected void moveGantryPinion(World world, BlockPos pos, Queue frontier, Set visited, BlockState state) { - BlockPos offset = pos.offset(state.get(GantryPinionBlock.FACING)); + BlockPos offset = pos.offset(state.get(GantryCarriageBlock.FACING)); if (!visited.contains(offset)) frontier.add(offset); Axis rotationAxis = ((IRotate) state.getBlock()).getRotationAxis(state); @@ -448,7 +435,7 @@ public abstract class Contraption { if (d.getAxis() == facing.getAxis() && AllBlocks.GANTRY_SHAFT.has(offsetState) && offsetState.get(GantryShaftBlock.FACING) == facing) frontier.add(offset); - else if (AllBlocks.GANTRY_PINION.has(offsetState) && offsetState.get(GantryPinionBlock.FACING) == d) + else if (AllBlocks.GANTRY_CARRIAGE.has(offsetState) && offsetState.get(GantryCarriageBlock.FACING) == d) frontier.add(offset); } } @@ -504,7 +491,8 @@ public abstract class Contraption { } } - private boolean moveMechanicalPiston(World world, BlockPos pos, Queue frontier, Set visited, BlockState state) throws AssemblyException { + private boolean moveMechanicalPiston(World world, BlockPos pos, Queue frontier, Set visited, + BlockState state) throws AssemblyException { Direction direction = state.get(MechanicalPistonBlock.FACING); PistonState pistonState = state.get(MechanicalPistonBlock.STATE); if (pistonState == PistonState.MOVING) @@ -626,8 +614,9 @@ public abstract class Contraption { specialRenderedTileEntities.clear(); INBT blocks = nbt.get("Blocks"); - //used to differentiate between the 'old' and the paletted serialization - boolean usePalettedDeserialization = blocks != null && blocks.getId() == 10 && ((CompoundNBT) blocks).contains("Palette"); + // used to differentiate between the 'old' and the paletted serialization + boolean usePalettedDeserialization = + blocks != null && blocks.getId() == 10 && ((CompoundNBT) blocks).contains("Palette"); readBlocksCompound(blocks, world, usePalettedDeserialization); actors.clear(); @@ -713,16 +702,16 @@ public abstract class Contraption { } ListNBT superglueNBT = new ListNBT(); - for (Pair glueEntry : superglue) { - CompoundNBT c = new CompoundNBT(); - c.put("Pos", NBTUtil.writeBlockPos(glueEntry.getKey())); - c.putByte("Direction", (byte) glueEntry.getValue() - .getIndex()); - superglueNBT.add(c); - } - ListNBT storageNBT = new ListNBT(); if (!spawnPacket) { + for (Pair glueEntry : superglue) { + CompoundNBT c = new CompoundNBT(); + c.put("Pos", NBTUtil.writeBlockPos(glueEntry.getKey())); + c.putByte("Direction", (byte) glueEntry.getValue() + .getIndex()); + superglueNBT.add(c); + } + for (BlockPos pos : storage.keySet()) { CompoundNBT c = new CompoundNBT(); MountedStorage mountedStorage = storage.get(pos); @@ -835,16 +824,7 @@ public abstract class Contraption { TileEntity te = TileEntity.createFromTag(info.state, tag); if (te == null) return; - te.setLocation(new WrappedWorld(world) { - - @Override - public BlockState getBlockState(BlockPos pos) { - if (!pos.equals(te.getPos())) - return Blocks.AIR.getDefaultState(); - return info.state; - } - - }, te.getPos()); + te.setLocation(new ContraptionTileWorld(world, te, info), te.getPos()); if (te instanceof KineticTileEntity) ((KineticTileEntity) te).setSpeed(0); te.getBlockState(); @@ -902,7 +882,7 @@ public abstract class Contraption { iterator.remove(); world.removeTileEntity(add); int flags = BlockFlags.IS_MOVING | BlockFlags.NO_NEIGHBOR_DROPS | BlockFlags.UPDATE_NEIGHBORS - | BlockFlags.BLOCK_UPDATE; + | BlockFlags.BLOCK_UPDATE | BlockFlags.RERENDER_MAIN_THREAD; if (blockIn instanceof IWaterLoggable && oldState.contains(BlockStateProperties.WATERLOGGED) && oldState.get(BlockStateProperties.WATERLOGGED) .booleanValue()) { @@ -913,10 +893,16 @@ public abstract class Contraption { } } for (BlockInfo block : blocks.values()) { - BlockPos add = block.pos.add(anchor).add(offset); - if (!shouldUpdateAfterMovement(block)) - continue; - world.markAndNotifyBlock(add, world.getChunkAt(add), block.state, Blocks.AIR.getDefaultState(), BlockFlags.IS_MOVING | BlockFlags.DEFAULT, 512); + BlockPos add = block.pos.add(anchor) + .add(offset); +// if (!shouldUpdateAfterMovement(block)) +// continue; + int flags = BlockFlags.IS_MOVING | BlockFlags.DEFAULT; + world.notifyBlockUpdate(add, block.state, Blocks.AIR.getDefaultState(), flags); + world.markAndNotifyBlock(add, world.getChunkAt(add), block.state, Blocks.AIR.getDefaultState(), flags, 512); + block.state.updateDiagonalNeighbors(world, add, flags & -2); +// world.markAndNotifyBlock(add, null, block.state, Blocks.AIR.getDefaultState(), +// BlockFlags.IS_MOVING | BlockFlags.DEFAULT); this method did strange logspamming with POI-related blocks } } @@ -1063,31 +1049,32 @@ public abstract class Contraption { } protected boolean shouldUpdateAfterMovement(BlockInfo info) { + if (PointOfInterestType.forState(info.state) + .isPresent()) + return false; return true; } public void expandBoundsAroundAxis(Axis axis) { - AxisAlignedBB bb = bounds; - double maxXDiff = Math.max(bb.maxX - 1, -bb.minX); - double maxYDiff = Math.max(bb.maxY - 1, -bb.minY); - double maxZDiff = Math.max(bb.maxZ - 1, -bb.minZ); - double maxDiff = 0; + Set blocks = getBlocks().keySet(); - if (axis == Axis.X) - maxDiff = Math.max(maxZDiff, maxYDiff); - if (axis == Axis.Y) - maxDiff = Math.max(maxZDiff, maxXDiff); - if (axis == Axis.Z) - maxDiff = Math.max(maxXDiff, maxYDiff); + int radius = (int) (Math.ceil(Math.sqrt(getRadius(blocks, axis)))); - Vector3d vec = Vector3d.of(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis) - .getDirectionVec()); - Vector3d planeByNormal = VecHelper.axisAlingedPlaneOf(vec); - Vector3d min = vec.mul(bb.minX, bb.minY, bb.minZ) - .add(planeByNormal.scale(-maxDiff)); - Vector3d max = vec.mul(bb.maxX, bb.maxY, bb.maxZ) - .add(planeByNormal.scale(maxDiff + 1)); - bounds = new AxisAlignedBB(min, max); + GridAlignedBB betterBounds = GridAlignedBB.ofRadius(radius); + + GridAlignedBB contraptionBounds = GridAlignedBB.fromAABB(bounds); + if (axis == Direction.Axis.X) { + betterBounds.maxX = contraptionBounds.maxX; + betterBounds.minX = contraptionBounds.minX; + } else if (axis == Direction.Axis.Y) { + betterBounds.maxY = contraptionBounds.maxY; + betterBounds.minY = contraptionBounds.minY; + } else if (axis == Direction.Axis.Z) { + betterBounds.maxZ = contraptionBounds.maxZ; + betterBounds.minZ = contraptionBounds.minZ; + } + + bounds = betterBounds.toAABB(); } public void addExtraInventories(Entity entity) {} @@ -1139,4 +1126,51 @@ public abstract class Contraption { return new EmptyLighter(this); } + public static float getRadius(Set blocks, Direction.Axis axis) { + switch (axis) { + case X: + return getMaxDistSqr(blocks, BlockPos::getY, BlockPos::getZ); + case Y: + return getMaxDistSqr(blocks, BlockPos::getX, BlockPos::getZ); + case Z: + return getMaxDistSqr(blocks, BlockPos::getX, BlockPos::getY); + } + + throw new IllegalStateException("Impossible axis"); + } + + public static float getMaxDistSqr(Set blocks, Coordinate one, Coordinate other) { + float maxDistSq = -1; + for (BlockPos pos : blocks) { + float a = one.get(pos); + float b = other.get(pos); + + float distSq = a * a + b * b; + + + if (distSq > maxDistSq) maxDistSq = distSq; + } + + return maxDistSq; + } + + private static class ContraptionTileWorld extends WrappedWorld implements IFlywheelWorld { + + private final TileEntity te; + private final BlockInfo info; + + public ContraptionTileWorld(World world, TileEntity te, BlockInfo info) { + super(world); + this.te = te; + this.info = info; + } + + @Override + public BlockState getBlockState(BlockPos pos) { + if (!pos.equals(te.getPos())) + return Blocks.AIR.getDefaultState(); + return info.state; + } + + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java index b5fb9c102..d0dffbe9b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java @@ -3,7 +3,6 @@ package com.simibubi.create.content.contraptions.components.structureMovement; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.culling.ClippingHelper; import net.minecraft.client.renderer.entity.EntityRenderer; @@ -39,7 +38,7 @@ public class ContraptionEntityRenderer exte super.render(entity, yaw, partialTicks, ms, buffers, overlay); // Keep a copy of the transforms in order to determine correct lighting - MatrixStack msLocal = translateTo(entity, AnimationTickHolder.getRenderTick()); + MatrixStack msLocal = translateTo(entity, AnimationTickHolder.getPartialTicks()); MatrixStack[] matrixStacks = new MatrixStack[] { ms, msLocal }; ms.push(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java index 5188412ec..dc0f9c5bd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java @@ -1,16 +1,18 @@ package com.simibubi.create.content.contraptions.components.structureMovement; -import java.util.Arrays; -import java.util.List; - import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.utility.Lang; - import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; +import java.util.Arrays; +import java.util.List; + +import static net.minecraft.util.text.TextFormatting.GRAY; +import static net.minecraft.util.text.TextFormatting.WHITE; + public interface IDisplayAssemblyExceptions { default boolean addExceptionToTooltip(List tooltip) { @@ -22,8 +24,11 @@ public interface IDisplayAssemblyExceptions { tooltip.add(StringTextComponent.EMPTY); tooltip.add(IHaveGoggleInformation.componentSpacing.copy().append(Lang.translate("gui.assembly.exception").formatted(TextFormatting.GOLD))); + String text = TooltipHelper.getUnformattedDeepText(e.component); - Arrays.stream(text.split("\n")).forEach(l -> tooltip.add(IHaveGoggleInformation.componentSpacing.copy().append(new StringTextComponent(l).setStyle(e.component.getStyle()).formatted(TextFormatting.GRAY)))); + Arrays.stream(text.split("\n")) + .forEach(l -> TooltipHelper.cutStringTextComponent(l, GRAY, WHITE) + .forEach(c -> tooltip.add(IHaveGoggleInformation.componentSpacing.copy().append(c)))); return true; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java index d4ca79607..2003b9127 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java @@ -1,8 +1,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement; import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; - +import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionKineticRenderer; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; @@ -12,6 +12,8 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.items.ItemHandlerHelper; +import javax.annotation.Nullable; + public abstract class MovementBehaviour { public boolean isActive(MovementContext context) { @@ -61,7 +63,10 @@ public abstract class MovementBehaviour { IRenderTypeBuffer buffer) {} @OnlyIn(Dist.CLIENT) - public void addInstance(RenderedContraption contraption, MovementContext context) {} + @Nullable + public ActorInstance createInstance(ContraptionKineticRenderer kr, MovementContext context) { + return null; + } public void onSpeedChanged(MovementContext context, Vector3d oldMotion, Vector3d motion) { } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java index f60e772ee..f1d0c139a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java @@ -1,12 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement; -import static com.simibubi.create.foundation.utility.AngleHelper.angleLerp; - -import java.util.Optional; -import java.util.UUID; - -import javax.annotation.Nullable; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; @@ -15,12 +8,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.mou import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.Couple; -import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.NBTHelper; -import com.simibubi.create.foundation.utility.VecHelper; - +import com.simibubi.create.foundation.utility.*; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -45,6 +33,12 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.util.LazyOptional; +import javax.annotation.Nullable; +import java.util.Optional; +import java.util.UUID; + +import static com.simibubi.create.foundation.utility.AngleHelper.angleLerp; + /** * Ex: Minecarts, Couplings
* Oriented Contraption Entities can rotate freely around two axes @@ -63,6 +57,7 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { protected boolean forceAngle; private boolean isSerializingFurnaceCart; private boolean attachedExtraInventories; + private boolean manuallyPlaced; public float prevYaw; public float yaw; @@ -93,6 +88,14 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { return entity; } + public static OrientedContraptionEntity createAtYaw(World world, Contraption contraption, + Optional initialOrientation, float initialYaw) { + OrientedContraptionEntity entity = create(world, contraption, initialOrientation); + entity.startAtYaw(initialYaw); + entity.manuallyPlaced = true; + return entity; + } + public void setInitialOrientation(Direction direction) { dataManager.set(INITIAL_ORIENTATION, direction); } @@ -152,6 +155,11 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { if (compound.contains("InitialOrientation")) setInitialOrientation(NBTHelper.readEnum(compound, "InitialOrientation", Direction.class)); + + yaw = compound.getFloat("Yaw"); + pitch = compound.getFloat("Pitch"); + manuallyPlaced = compound.getBoolean("Placed"); + if (compound.contains("ForceYaw")) startAtYaw(compound.getFloat("ForceYaw")); @@ -163,9 +171,6 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { setMotion(Vector3d.ZERO); } - yaw = compound.getFloat("Yaw"); - pitch = compound.getFloat("Pitch"); - setCouplingId(compound.contains("OnCoupling") ? compound.getUniqueId("OnCoupling") : null); } @@ -186,6 +191,7 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { forceAngle = false; } + compound.putBoolean("Placed", manuallyPlaced); compound.putFloat("Yaw", yaw); compound.putFloat("Pitch", pitch); @@ -196,7 +202,7 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { @Override public void notifyDataManagerChange(DataParameter key) { super.notifyDataManagerChange(key); - if (key == INITIAL_ORIENTATION && isInitialOrientationPresent()) + if (key == INITIAL_ORIENTATION && isInitialOrientationPresent() && !manuallyPlaced) startAtInitialYaw(); } @@ -355,14 +361,16 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { boolean rotating = false; Vector3d movementVector = riding.getMotion(); - + Vector3d locationDiff = riding.getPositionVec() + .subtract(riding.prevPosX, riding.prevPosY, riding.prevPosZ); if (!(riding instanceof AbstractMinecartEntity)) - movementVector = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ); + movementVector = locationDiff; Vector3d motion = movementVector.normalize(); if (!isInitialOrientationPresent() && !world.isRemote) { - if (motion.length() > 0) { - Direction facingFromVector = Direction.getFacingFromVector(motion.x, motion.y, motion.z); + if (locationDiff.length() > 0) { + Direction facingFromVector = + Direction.getFacingFromVector(locationDiff.x, locationDiff.y, locationDiff.z); if (initialYawOffset != -1) facingFromVector = Direction.fromAngle(facingFromVector.getHorizontalAngle() - initialYawOffset); if (facingFromVector.getAxis() @@ -518,12 +526,12 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { for (MatrixStack stack : matrixStacks) MatrixStacker.of(stack) - .nudge(getEntityId()) - .centre() - .rotateY(angleYaw) - .rotateZ(anglePitch) - .rotateY(angleInitialYaw) - .unCentre(); + .nudge(getEntityId()) + .centre() + .rotateY(angleYaw) + .rotateZ(anglePitch) + .rotateY(angleInitialYaw) + .unCentre(); } @OnlyIn(Dist.CLIENT) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/AnchoredLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/AnchoredLighter.java new file mode 100644 index 000000000..09cfa2a39 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/AnchoredLighter.java @@ -0,0 +1,19 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.bearing; + +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; +import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; + +public class AnchoredLighter extends ContraptionLighter { + + public AnchoredLighter(Contraption contraption) { + super(contraption); + } + + @Override + public GridAlignedBB getContraptionBounds() { + GridAlignedBB bb = GridAlignedBB.fromAABB(contraption.bounds); + bb.translate(contraption.anchor); + return bb; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingBlock.java index e35a06e2d..6b1a723cb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingBlock.java @@ -1,8 +1,10 @@ package com.simibubi.create.content.contraptions.components.structureMovement.bearing; import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; - import net.minecraft.block.BlockState; +import net.minecraft.item.ItemUseContext; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; @@ -29,4 +31,15 @@ public abstract class BearingBlock extends DirectionalKineticBlock { return true; } + @Override + public ActionResultType onWrenched(BlockState state, ItemUseContext context) { + ActionResultType resultType = super.onWrenched(state, context); + if (!context.getWorld().isRemote && resultType.isAccepted()) { + TileEntity te = context.getWorld().getTileEntity(context.getPos()); + if (te instanceof MechanicalBearingTileEntity) { + ((MechanicalBearingTileEntity) te).disassemble(); + } + } + return resultType; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java index 7b1fc465f..6ba390e0b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java @@ -1,13 +1,11 @@ package com.simibubi.create.content.contraptions.components.structureMovement.bearing; -import org.apache.commons.lang3.tuple.Pair; - import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; - +import com.simibubi.create.foundation.config.AllConfigs; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; @@ -16,12 +14,13 @@ import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import org.apache.commons.lang3.tuple.Pair; public class BearingContraption extends Contraption { protected int sailBlocks; protected Direction facing; - + private boolean isWindmill; public BearingContraption() {} @@ -38,8 +37,8 @@ public class BearingContraption extends Contraption { return false; startMoving(world); expandBoundsAroundAxis(facing.getAxis()); - if (isWindmill && sailBlocks == 0) - return false; + if (isWindmill && sailBlocks < AllConfigs.SERVER.kinetics.minimumWindmillSails.get()) + throw AssemblyException.notEnoughSails(sailBlocks); if (blocks.isEmpty()) return false; return true; @@ -96,6 +95,6 @@ public class BearingContraption extends Contraption { @OnlyIn(Dist.CLIENT) @Override public ContraptionLighter makeLighter() { - return new BearingLighter(this); + return new AnchoredLighter(this); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java deleted file mode 100644 index f2b3e5eec..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import java.util.Set; - -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; -import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; - -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; - -public class BearingLighter extends ContraptionLighter { - - public BearingLighter(BearingContraption contraption) { - super(contraption); - } - - @Override - public GridAlignedBB getContraptionBounds() { - Set blocks = contraption.getBlocks().keySet(); - - Direction orientation = contraption.facing; - - float maxDistanceSq = -1; - for (BlockPos pos : blocks) { - float x = pos.getX(); - float y = pos.getY(); - float z = pos.getZ(); - - float distSq = x * x + y * y + z * z; - - if (distSq > maxDistanceSq) maxDistanceSq = distSq; - } - - int radius = (int) (Math.ceil(Math.sqrt(maxDistanceSq))); - - GridAlignedBB betterBounds = GridAlignedBB.ofRadius(radius); - GridAlignedBB contraptionBounds = GridAlignedBB.fromAABB(contraption.bounds); - - Direction.Axis axis = orientation.getAxis(); - - if (axis == Direction.Axis.X) { - betterBounds.maxX = contraptionBounds.maxX; - betterBounds.minX = contraptionBounds.minX; - } else if (axis == Direction.Axis.Y) { - betterBounds.maxY = contraptionBounds.maxY; - betterBounds.minY = contraptionBounds.minY; - } else if (axis == Direction.Axis.Z) { - betterBounds.maxZ = contraptionBounds.maxZ; - betterBounds.minZ = contraptionBounds.minZ; - } - - betterBounds.translate(contraption.anchor); - return betterBounds; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingBlock.java index 18112fbfa..faf4fde2b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingBlock.java @@ -2,9 +2,9 @@ package com.simibubi.create.content.contraptions.components.structureMovement.be import com.simibubi.create.AllTileEntities; import com.simibubi.create.foundation.block.ITE; - import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemUseContext; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; @@ -51,4 +51,12 @@ public class ClockworkBearingBlock extends BearingBlock implements ITE operationMode; + private float prevForcedAngle; + public ClockworkBearingTileEntity(TileEntityType type) { super(type); setLazyTickRate(3); @@ -67,6 +67,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe super.tick(); if (world.isRemote) { + prevForcedAngle = hourAngle; clientMinuteAngleDiff /= 2; clientHourAngleDiff /= 2; } @@ -342,6 +343,8 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe @Override public float getInterpolatedAngle(float partialTicks) { + if (isVirtual()) + return MathHelper.lerp(partialTicks, prevForcedAngle, hourAngle); if (hourHand == null || hourHand.isStalled()) partialTicks = 0; return MathHelper.lerp(partialTicks, hourAngle, hourAngle + getHourArmSpeed()); @@ -415,4 +418,8 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe public boolean shouldRenderAsTE() { return true; } + + public void setAngle(float forcedAngle) { + hourAngle = forcedAngle; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java index 1dea812eb..572e63850 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java @@ -1,20 +1,19 @@ package com.simibubi.create.content.contraptions.components.structureMovement.bearing; -import java.util.HashSet; -import java.util.Queue; -import java.util.Set; - -import org.apache.commons.lang3.tuple.Pair; - import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; import com.simibubi.create.foundation.utility.NBTHelper; - import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; public class ClockworkContraption extends Contraption { @@ -129,4 +128,8 @@ public class ClockworkContraption extends Contraption { HOUR, MINUTE } + @Override + public ContraptionLighter makeLighter() { + return new AnchoredLighter(this); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/IBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/IBearingTileEntity.java index f2f9a475d..67ebba73e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/IBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/IBearingTileEntity.java @@ -3,7 +3,6 @@ package com.simibubi.create.content.contraptions.components.structureMovement.be import com.simibubi.create.content.contraptions.components.structureMovement.DirectionalExtenderScrollOptionSlot; import com.simibubi.create.content.contraptions.components.structureMovement.IControlContraption; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - import net.minecraft.util.Direction.Axis; public interface IBearingTileEntity extends IControlContraption { @@ -20,5 +19,7 @@ public interface IBearingTileEntity extends IControlContraption { return bearingAxis != axis; }); } + + void setAngle(float forcedAngle); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java index 6dcf83ca1..69c263faf 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java @@ -1,9 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement.bearing; -import static net.minecraft.state.properties.BlockStateProperties.FACING; - -import java.util.List; - import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; @@ -17,7 +13,6 @@ import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; @@ -27,7 +22,12 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; -public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity implements IBearingTileEntity, IDisplayAssemblyExceptions { +import java.util.List; + +import static net.minecraft.state.properties.BlockStateProperties.FACING; + +public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity + implements IBearingTileEntity, IDisplayAssemblyExceptions { protected ScrollOptionBehaviour movementMode; protected ControlledContraptionEntity movedContraption; @@ -37,6 +37,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp protected float clientAngleDiff; protected AssemblyException lastException; + private float prevAngle; + public MechanicalBearingTileEntity(TileEntityType type) { super(type); setLazyTickRate(3); @@ -89,6 +91,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp @Override public float getInterpolatedAngle(float partialTicks) { + if (isVirtual()) + return MathHelper.lerp(partialTicks + .5f, prevAngle, angle); if (movedContraption == null || movedContraption.isStalled() || !running) partialTicks = 0; return MathHelper.lerp(partialTicks, angle, angle + getAngularSpeed()); @@ -147,7 +151,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp AllTriggers.triggerForNearbyPlayers(AllTriggers.WINDMILL, world, pos, 5); if (contraption.getSailBlocks() >= 16 * 8) AllTriggers.triggerForNearbyPlayers(AllTriggers.MAXED_WINDMILL, world, pos, 5); - + contraption.removeBlocksFromWorld(world, BlockPos.ZERO); movedContraption = ControlledContraptionEntity.create(world, this, contraption); BlockPos anchor = pos.offset(direction); @@ -181,6 +185,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp public void tick() { super.tick(); + prevAngle = angle; if (world.isRemote) clientAngleDiff /= 2; @@ -293,7 +298,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp BlockState state = getBlockState(); if (!(state.getBlock() instanceof BearingBlock)) return false; - + BlockState attachedState = world.getBlockState(pos.offset(state.get(BearingBlock.FACING))); if (attachedState.getMaterial() .isReplaceable()) @@ -306,4 +311,9 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp public boolean shouldRenderAsTE() { return true; } + + public void setAngle(float forcedAngle) { + angle = forcedAngle; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java index adec28c53..1a49ab773 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java @@ -1,13 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement.bearing; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -import javax.annotation.Nullable; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.foundation.block.ProperDirectionalBlock; @@ -16,18 +8,13 @@ import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import com.simibubi.create.foundation.utility.placement.PlacementOffset; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.BlockItem; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.item.DyeColor; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ShearsItem; +import net.minecraft.item.*; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; @@ -40,6 +27,13 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + public class SailBlock extends ProperDirectionalBlock { public static SailBlock frame(Properties properties) { @@ -71,7 +65,7 @@ public class SailBlock extends ProperDirectionalBlock { IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); if (placementHelper.matchesItem(heldItem)) - return placementHelper.getOffset(world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + return placementHelper.getOffset(player, world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); if (heldItem.getItem() instanceof ShearsItem) { if (!world.isRemote) @@ -209,7 +203,7 @@ public class SailBlock extends ProperDirectionalBlock { } @Override - public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + public PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { List directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getHitVec(), state.get(SailBlock.FACING).getAxis(), dir -> world.getBlockState(pos.offset(dir)).getMaterial().isReplaceable()); if (directions.isEmpty()) @@ -218,11 +212,5 @@ public class SailBlock extends ProperDirectionalBlock { return PlacementOffset.success(pos.offset(directions.get(0)), s -> s.with(FACING, state.get(FACING))); } } - - @Override - public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) { - //IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), state.get(FACING)); - displayGhost(offset); - } } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java index d2e8bf420..e24272a76 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java @@ -5,7 +5,6 @@ import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.block.BlockState; import net.minecraft.block.RotatedPillarBlock; import net.minecraft.entity.player.PlayerEntity; @@ -13,12 +12,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.particles.ParticleTypes; import net.minecraft.state.BooleanProperty; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ActionResultType; -import net.minecraft.util.Direction; -import net.minecraft.util.Hand; -import net.minecraft.util.Mirror; -import net.minecraft.util.Rotation; -import net.minecraft.util.SoundCategory; +import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.vector.Vector3d; @@ -59,7 +53,7 @@ public abstract class AbstractChassisBlock extends RotatedPillarBlock implements if (isSlimeBall && state.get(affectedSide)) { for (Direction face : Iterate.directions) { BooleanProperty glueableSide = getGlueableSide(state, face); - if (glueableSide != null && !state.get(glueableSide)) { + if (glueableSide != null && !state.get(glueableSide) && glueAllowedOnSide(worldIn, pos, state, face)) { if (worldIn.isRemote) { Vector3d vec = hit.getHitVec(); worldIn.addParticle(ParticleTypes.ITEM_SLIME, vec.x, vec.y, vec.z, 0, 0, 0); @@ -78,6 +72,8 @@ public abstract class AbstractChassisBlock extends RotatedPillarBlock implements return ActionResultType.PASS; if (state.get(affectedSide) == isSlimeBall) return ActionResultType.PASS; + if (!glueAllowedOnSide(worldIn, pos, state, hit.getFace())) + return ActionResultType.PASS; if (worldIn.isRemote) { Vector3d vec = hit.getHitVec(); worldIn.addParticle(ParticleTypes.ITEM_SLIME, vec.x, vec.y, vec.z, 0, 0, 0); @@ -94,6 +90,7 @@ public abstract class AbstractChassisBlock extends RotatedPillarBlock implements if (rotation == Rotation.NONE) return state; + @SuppressWarnings("deprecation") BlockState rotated = super.rotate(state, rotation); for (Direction face : Iterate.directions) { BooleanProperty glueableSide = getGlueableSide(rotated, face); @@ -141,4 +138,8 @@ public abstract class AbstractChassisBlock extends RotatedPillarBlock implements public abstract BooleanProperty getGlueableSide(BlockState state, Direction face); + protected boolean glueAllowedOnSide(IBlockReader world, BlockPos pos, BlockState state, Direction side) { + return true; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java index 1f8396922..042c261e6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java @@ -1,15 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement.chassis; -import static net.minecraft.state.properties.BlockStateProperties.AXIS; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; -import java.util.Set; - import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; import com.simibubi.create.foundation.config.AllConfigs; @@ -20,7 +10,6 @@ import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.BulkScrol import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; - import net.minecraft.block.BlockState; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; @@ -32,6 +21,10 @@ import net.minecraft.util.math.BlockPos; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.fml.DistExecutor; +import java.util.*; + +import static net.minecraft.state.properties.BlockStateProperties.AXIS; + public class ChassisTileEntity extends SmartTileEntity { ScrollValueBehaviour range; @@ -125,8 +118,6 @@ public class ChassisTileEntity extends SmartTileEntity { // Collect group of connected linear chassis for (Direction offset : Iterate.directions) { - if (offset.getAxis() == axis) - continue; BlockPos current = pos.offset(offset); if (visited.contains(current)) continue; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/LinearChassisBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/LinearChassisBlock.java index 21f53b4f8..b4e1e4d2e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/LinearChassisBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/LinearChassisBlock.java @@ -4,7 +4,6 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSpriteShifts; import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.BlockItemUseContext; @@ -15,6 +14,8 @@ import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockDisplayReader; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; public class LinearChassisBlock extends AbstractChassisBlock { @@ -51,6 +52,15 @@ public class LinearChassisBlock extends AbstractChassisBlock { return super.getStateForPlacement(context); } + @Override + public BlockState updatePostPlacement(BlockState state, Direction side, BlockState other, IWorld p_196271_4_, + BlockPos p_196271_5_, BlockPos p_196271_6_) { + BooleanProperty property = getGlueableSide(state, side); + if (property == null || !sameKind(state, other) || state.get(AXIS) != other.get(AXIS)) + return state; + return state.with(property, false); + } + @Override public BooleanProperty getGlueableSide(BlockState state, Direction face) { if (face.getAxis() != state.get(AXIS)) @@ -58,6 +68,12 @@ public class LinearChassisBlock extends AbstractChassisBlock { return face.getAxisDirection() == AxisDirection.POSITIVE ? STICKY_TOP : STICKY_BOTTOM; } + @Override + protected boolean glueAllowedOnSide(IBlockReader world, BlockPos pos, BlockState state, Direction side) { + BlockState other = world.getBlockState(pos.offset(side)); + return !sameKind(other, state) || state.get(AXIS) != other.get(AXIS); + } + public static boolean isChassis(BlockState state) { return AllBlocks.LINEAR_CHASSIS.has(state) || AllBlocks.SECONDARY_LINEAR_CHASSIS.has(state); } @@ -73,14 +89,49 @@ public class LinearChassisBlock extends AbstractChassisBlock { Block block = state.getBlock(); BooleanProperty glueableSide = ((LinearChassisBlock) block).getGlueableSide(state, direction); if (glueableSide == null) - return null; + return AllBlocks.LINEAR_CHASSIS.has(state) ? AllSpriteShifts.CHASSIS_SIDE + : AllSpriteShifts.SECONDARY_CHASSIS_SIDE; return state.get(glueableSide) ? AllSpriteShifts.CHASSIS_STICKY : AllSpriteShifts.CHASSIS; } + @Override + protected Direction getUpDirection(IBlockDisplayReader reader, BlockPos pos, BlockState state, Direction face) { + Axis axis = state.get(AXIS); + if (face.getAxis() == axis) + return super.getUpDirection(reader, pos, state, face); + return Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis); + } + + @Override + protected Direction getRightDirection(IBlockDisplayReader reader, BlockPos pos, BlockState state, Direction face) { + Axis axis = state.get(AXIS); + return axis != face.getAxis() && axis.isHorizontal() ? (face.getAxis() + .isHorizontal() ? Direction.DOWN : (axis == Axis.X ? Direction.NORTH : Direction.EAST)) + : super.getRightDirection(reader, pos, state, face); + } + + @Override + protected boolean reverseUVsHorizontally(BlockState state, Direction face) { + Axis axis = state.get(AXIS); + boolean side = face.getAxis() != axis; + if (side && axis == Axis.X && face.getAxis() + .isHorizontal()) + return true; + return super.reverseUVsHorizontally(state, face); + } + + @Override + protected boolean reverseUVsVertically(BlockState state, Direction face) { + return super.reverseUVsVertically(state, face); + } + @Override public boolean reverseUVs(BlockState state, Direction face) { Axis axis = state.get(AXIS); - if (axis.isHorizontal() && (face.getAxisDirection() == AxisDirection.POSITIVE)) + boolean end = face.getAxis() == axis; + if (end && axis.isHorizontal() && (face.getAxisDirection() == AxisDirection.POSITIVE)) + return true; + if (!end && axis.isHorizontal() && face == Direction.DOWN) return true; return super.reverseUVs(state, face); } @@ -88,7 +139,10 @@ public class LinearChassisBlock extends AbstractChassisBlock { @Override public boolean connectsTo(BlockState state, BlockState other, IBlockDisplayReader reader, BlockPos pos, BlockPos otherPos, Direction face) { - return sameKind(state, other) && state.get(AXIS) == other.get(AXIS); + Axis axis = state.get(AXIS); + boolean superConnect = face.getAxis() == axis ? super.connectsTo(state, other, reader, pos, otherPos, face) + : sameKind(state, other); + return superConnect && axis == other.get(AXIS); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerBlock.java new file mode 100644 index 000000000..159056580 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerBlock.java @@ -0,0 +1,161 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.chassis; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.ProperDirectionalBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.particles.BlockParticleData; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.StateContainer.Builder; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorldReader; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; + +public class StickerBlock extends ProperDirectionalBlock implements ITE { + + public static final BooleanProperty POWERED = BlockStateProperties.POWERED; + public static final BooleanProperty EXTENDED = BlockStateProperties.EXTENDED; + + public StickerBlock(Properties p_i48415_1_) { + super(p_i48415_1_); + setDefaultState(getDefaultState().with(POWERED, false) + .with(EXTENDED, false)); + } + + @Override + public BlockState getStateForPlacement(BlockItemUseContext context) { + Direction nearestLookingDirection = context.getNearestLookingDirection(); + boolean shouldPower = context.getWorld() + .isBlockPowered(context.getPos()); + Direction facing = context.getPlayer() != null && context.getPlayer() + .isSneaking() ? nearestLookingDirection : nearestLookingDirection.getOpposite(); + + return getDefaultState().with(FACING, facing) + .with(POWERED, shouldPower); + } + + @Override + protected void fillStateContainer(Builder builder) { + super.fillStateContainer(builder.add(POWERED, EXTENDED)); + } + + @Override + public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + if (worldIn.isRemote) + return; + + boolean previouslyPowered = state.get(POWERED); + if (previouslyPowered != worldIn.isBlockPowered(pos)) { + state = state.cycle(POWERED); + if (state.get(POWERED)) + state = state.cycle(EXTENDED); + worldIn.setBlockState(pos, state, 2); + } + } + + @Override + public boolean hasTileEntity(BlockState state) { + return true; + } + + @Override + public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side) { + return false; + } + + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return AllTileEntities.STICKER.create(); + } + + @Override + public Class getTileEntityClass() { + return StickerTileEntity.class; + } + + // Slime block stuff + + private boolean isUprightSticker(IBlockReader world, BlockPos pos) { + BlockState blockState = world.getBlockState(pos); + return AllBlocks.STICKER.has(blockState) && blockState.get(FACING) == Direction.UP; + } + + @Override + public void onFallenUpon(World p_180658_1_, BlockPos p_180658_2_, Entity p_180658_3_, float p_180658_4_) { + if (!isUprightSticker(p_180658_1_, p_180658_2_) || p_180658_3_.bypassesLandingEffects()) { + super.onFallenUpon(p_180658_1_, p_180658_2_, p_180658_3_, p_180658_4_); + } else { + p_180658_3_.handleFallDamage(p_180658_4_, 0.0F); + } + } + + @Override + public void onLanded(IBlockReader p_176216_1_, Entity p_176216_2_) { + if (!isUprightSticker(p_176216_1_, p_176216_2_.getBlockPos() + .down()) || p_176216_2_.bypassesLandingEffects()) { + super.onLanded(p_176216_1_, p_176216_2_); + } else { + this.func_226946_a_(p_176216_2_); + } + } + + private void func_226946_a_(Entity p_226946_1_) { + Vector3d vec3d = p_226946_1_.getMotion(); + if (vec3d.y < 0.0D) { + double d0 = p_226946_1_ instanceof LivingEntity ? 1.0D : 0.8D; + p_226946_1_.setMotion(vec3d.x, -vec3d.y * d0, vec3d.z); + } + } + + @Override + public void onEntityWalk(World p_176199_1_, BlockPos p_176199_2_, Entity p_176199_3_) { + double d0 = Math.abs(p_176199_3_.getMotion().y); + if (d0 < 0.1D && !p_176199_3_.bypassesSteppingEffects() && isUprightSticker(p_176199_1_, p_176199_2_)) { + double d1 = 0.4D + d0 * 0.2D; + p_176199_3_.setMotion(p_176199_3_.getMotion() + .mul(d1, 1.0D, d1)); + } + super.onEntityWalk(p_176199_1_, p_176199_2_, p_176199_3_); + } + + @Override + public boolean addLandingEffects(BlockState state1, ServerWorld worldserver, BlockPos pos, BlockState state2, + LivingEntity entity, int numberOfParticles) { + if (isUprightSticker(worldserver, pos)) { + worldserver.spawnParticle(new BlockParticleData(ParticleTypes.BLOCK, Blocks.SLIME_BLOCK.getDefaultState()), + entity.getX(), entity.getY(), entity.getZ(), numberOfParticles, 0.0D, 0.0D, 0.0D, (double) 0.15F); + return true; + } + return super.addLandingEffects(state1, worldserver, pos, state2, entity, numberOfParticles); + } + + @Override + public boolean addRunningEffects(BlockState state, World world, BlockPos pos, Entity entity) { + if (state.get(FACING) == Direction.UP) { + Vector3d vec3d = entity.getMotion(); + world.addParticle( + new BlockParticleData(ParticleTypes.BLOCK, Blocks.SLIME_BLOCK.getDefaultState()).setPos(pos), + entity.getX() + ((double) world.rand.nextFloat() - 0.5D) * (double) entity.getWidth(), + entity.getY() + 0.1D, + entity.getZ() + ((double) world.rand.nextFloat() - 0.5D) * (double) entity.getWidth(), vec3d.x * -4.0D, + 1.5D, vec3d.z * -4.0D); + return true; + } + return super.addRunningEffects(state, world, pos, entity); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerInstance.java new file mode 100644 index 000000000..2da5fb049 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerInstance.java @@ -0,0 +1,72 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.chassis; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.TileEntityInstance; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.client.Minecraft; +import net.minecraft.util.Direction; + +public class StickerInstance extends TileEntityInstance implements ITickableInstance { + + float lastOffset = Float.NaN; + + private InstanceKey head; + + public StickerInstance(InstancedTileRenderer modelManager, StickerTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + head = modelManager.getMaterial(RenderMaterials.MODELS).getModel(AllBlockPartials.STICKER_HEAD, lastState).createInstance(); + + updateLight(); + } + + @Override + public void tick() { + lastState = world.getBlockState(pos); + + float offset = tile.piston.getValue(AnimationTickHolder.getPartialTicks()); + + if (tile.getWorld() != Minecraft.getInstance().world) + offset = lastState.get(StickerBlock.EXTENDED) ? 1 : 0; + + if (Math.abs(offset - lastOffset) < 1e-4) + return; + + Direction facing = lastState.get(StickerBlock.FACING); + MatrixStack stack = new MatrixStack(); + MatrixStacker.of(stack) + .translate(getFloatingPos()) + .nudge(tile.hashCode()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(AngleHelper.verticalAngle(facing) + 90) + .unCentre() + .translate(0, (offset * offset) * 4 / 16f, 0); + + head.getInstance() + .setTransformNoCopy(stack); + + lastOffset = offset; + } + + @Override + public void updateLight() { + relight(pos, head.getInstance()); + } + + @Override + public void remove() { + head.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java new file mode 100644 index 000000000..5b1077bfd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java @@ -0,0 +1,49 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.chassis; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.util.Direction; + +public class StickerRenderer extends SafeTileEntityRenderer { + + public StickerRenderer(TileEntityRendererDispatcher dispatcher) { + super(dispatcher); + } + + @Override + protected void renderSafe(StickerTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, + int light, int overlay) { + + if (FastRenderDispatcher.available(te.getWorld())) return; + + BlockState state = te.getBlockState(); + SuperByteBuffer head = AllBlockPartials.STICKER_HEAD.renderOn(state); + float offset = te.piston.getValue(AnimationTickHolder.getPartialTicks(te.getWorld())); + + if (te.getWorld() != Minecraft.getInstance().world && !te.isVirtual()) + offset = state.get(StickerBlock.EXTENDED) ? 1 : 0; + + Direction facing = state.get(StickerBlock.FACING); + head.matrixStacker() + .nudge(te.hashCode()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(AngleHelper.verticalAngle(facing) + 90) + .unCentre() + .translate(0, (offset * offset) * 4 / 16f, 0); + + head.light(light) + .renderInto(ms, buffer.getBuffer(RenderType.getSolid())); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerTileEntity.java new file mode 100644 index 000000000..ccda7d654 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerTileEntity.java @@ -0,0 +1,94 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.chassis; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueItem; +import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered; +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.util.SoundCategory; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +import java.util.List; + +public class StickerTileEntity extends SmartTileEntity implements IInstanceRendered { + + LerpedFloat piston; + boolean update; + + public StickerTileEntity(TileEntityType tileEntityTypeIn) { + super(tileEntityTypeIn); + piston = LerpedFloat.linear(); + update = false; + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public void initialize() { + super.initialize(); + if (!world.isRemote) + return; + piston.startWithValue(isBlockStateExtended() ? 1 : 0); + } + + public boolean isBlockStateExtended() { + BlockState blockState = getBlockState(); + boolean extended = AllBlocks.STICKER.has(blockState) && blockState.get(StickerBlock.EXTENDED); + return extended; + } + + @Override + public void tick() { + super.tick(); + if (!world.isRemote) + return; + piston.tickChaser(); + + if (isAttachedToBlock() && piston.getValue(0) != piston.getValue() && piston.getValue() == 1) { + SuperGlueItem.spawnParticles(world, pos, getBlockState().get(StickerBlock.FACING), true); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> playSound(true)); + } + + if (!update) + return; + update = false; + int target = isBlockStateExtended() ? 1 : 0; + if (isAttachedToBlock() && target == 0 && piston.getChaseTarget() == 1) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> playSound(false)); + piston.chase(target, .4f, Chaser.LINEAR); + } + + public boolean isAttachedToBlock() { + BlockState blockState = getBlockState(); + if (!AllBlocks.STICKER.has(blockState)) + return false; + Direction direction = blockState.get(StickerBlock.FACING); + return SuperGlueEntity.isValidFace(world, pos.offset(direction), direction.getOpposite()); + } + + @Override + protected void fromTag(BlockState state, CompoundNBT compound, boolean clientPacket) { + super.fromTag(state, compound, clientPacket); + if (clientPacket) + update = true; + } + + @OnlyIn(Dist.CLIENT) + public void playSound(boolean attach) { + world.playSound(Minecraft.getInstance().player, pos, AllSoundEvents.SLIME_ADDED.get(), SoundCategory.BLOCKS, + 0.35F, attach ? 0.75F : 0.2f); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlock.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlock.java index d2120a056..b2cf779a8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlock.java @@ -7,7 +7,6 @@ import com.simibubi.create.content.contraptions.base.IRotate; import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -24,9 +23,9 @@ import net.minecraft.world.IWorld; import net.minecraft.world.IWorldReader; import net.minecraft.world.World; -public class GantryPinionBlock extends DirectionalAxisKineticBlock implements ITE { +public class GantryCarriageBlock extends DirectionalAxisKineticBlock implements ITE { - public GantryPinionBlock(Properties properties) { + public GantryCarriageBlock(Properties properties) { super(properties); } @@ -41,7 +40,7 @@ public class GantryPinionBlock extends DirectionalAxisKineticBlock implements IT @Override public void updateDiagonalNeighbors(BlockState stateIn, IWorld worldIn, BlockPos pos, int flags, int count) { super.updateDiagonalNeighbors(stateIn, worldIn, pos, flags, count); - withTileEntityDo(worldIn, pos, GantryPinionTileEntity::checkValidGantryShaft); + withTileEntityDo(worldIn, pos, GantryCarriageTileEntity::checkValidGantryShaft); } @Override @@ -113,7 +112,7 @@ public class GantryPinionBlock extends DirectionalAxisKineticBlock implements IT } public static Axis getValidGantryShaftAxis(BlockState state) { - if (!(state.getBlock() instanceof GantryPinionBlock)) + if (!(state.getBlock() instanceof GantryCarriageBlock)) return Axis.Y; IRotate block = (IRotate) state.getBlock(); Axis rotationAxis = block.getRotationAxis(state); @@ -135,8 +134,8 @@ public class GantryPinionBlock extends DirectionalAxisKineticBlock implements IT } @Override - public Class getTileEntityClass() { - return GantryPinionTileEntity.class; + public Class getTileEntityClass() { + return GantryCarriageTileEntity.class; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageInstance.java new file mode 100644 index 000000000..0793c133d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageInstance.java @@ -0,0 +1,87 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.gantry; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; +import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3f; + +public class GantryCarriageInstance extends ShaftInstance implements ITickableInstance { + + private InstanceKey gantryCogs; + + public GantryCarriageInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + super(dispatcher, tile); + } + + @Override + protected void init() { + super.init(); + + gantryCogs = modelManager.getMaterial(RenderMaterials.MODELS) + .getModel(AllBlockPartials.GANTRY_COGS, lastState) + .createInstance(); + + updateLight(); + } + + @Override + public void tick() { + lastState = tile.getBlockState(); + Direction facing = lastState.get(GantryCarriageBlock.FACING); + Boolean alongFirst = lastState.get(GantryCarriageBlock.AXIS_ALONG_FIRST_COORDINATE); + Direction.Axis rotationAxis = KineticTileEntityRenderer.getRotationAxisOf(tile); + BlockPos visualPos = facing.getAxisDirection() == Direction.AxisDirection.POSITIVE ? tile.getPos() + : tile.getPos() + .offset(facing.getOpposite()); + float angleForTe = GantryCarriageRenderer.getAngleForTe(tile, visualPos, rotationAxis); + + Direction.Axis gantryAxis = Direction.Axis.X; + for (Direction.Axis axis : Iterate.axes) + if (axis != rotationAxis && axis != facing.getAxis()) + gantryAxis = axis; + + if (gantryAxis == Direction.Axis.Z) + if (facing == Direction.DOWN) + angleForTe *= -1; + if (gantryAxis == Direction.Axis.Y) + if (facing == Direction.NORTH || facing == Direction.EAST) + angleForTe *= -1; + + MatrixStack ms = new MatrixStack(); + MatrixStacker.of(ms) + .translate(getFloatingPos()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) + .rotateY(alongFirst ^ facing.getAxis() == Direction.Axis.Z ? 90 : 0) + .translate(0, -9 / 16f, 0) + .multiply(Vector3f.POSITIVE_X.getRadialQuaternion(-angleForTe)) + .translate(0, 9 / 16f, 0) + .unCentre(); + + gantryCogs.getInstance().setTransformNoCopy(ms); + } + + @Override + public void updateLight() { + relight(pos, gantryCogs.getInstance()); + } + + @Override + public void remove() { + super.remove(); + gantryCogs.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageRenderer.java similarity index 73% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java rename to src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageRenderer.java index 0234ca7ae..35b495535 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageRenderer.java @@ -4,11 +4,11 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.MatrixStacker; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -19,9 +19,9 @@ import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3f; -public class GantryPinionRenderer extends KineticTileEntityRenderer { +public class GantryCarriageRenderer extends KineticTileEntityRenderer { - public GantryPinionRenderer(TileEntityRendererDispatcher dispatcher) { + public GantryCarriageRenderer(TileEntityRendererDispatcher dispatcher) { super(dispatcher); } @@ -29,9 +29,12 @@ public class GantryPinionRenderer extends KineticTileEntityRenderer { protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { super.renderSafe(te, partialTicks, ms, buffer, light, overlay); + + if (FastRenderDispatcher.available(te.getWorld())) return; + BlockState state = te.getBlockState(); - Direction facing = state.get(GantryPinionBlock.FACING); - Boolean alongFirst = state.get(GantryPinionBlock.AXIS_ALONG_FIRST_COORDINATE); + Direction facing = state.get(GantryCarriageBlock.FACING); + Boolean alongFirst = state.get(GantryCarriageBlock.AXIS_ALONG_FIRST_COORDINATE); Axis rotationAxis = getRotationAxisOf(te); BlockPos visualPos = facing.getAxisDirection() == AxisDirection.POSITIVE ? te.getPos() : te.getPos() @@ -50,29 +53,24 @@ public class GantryPinionRenderer extends KineticTileEntityRenderer { if (facing == Direction.NORTH || facing == Direction.EAST) angleForTe *= -1; - ms.push(); - - MatrixStacker msr = MatrixStacker.of(ms); - - msr.centre() + SuperByteBuffer cogs = AllBlockPartials.GANTRY_COGS.renderOn(state); + cogs.matrixStacker() + .centre() .rotateY(AngleHelper.horizontalAngle(facing)) .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) - .rotateY(alongFirst ^ facing.getAxis() == Axis.Z ? 90 : 0); + .rotateY(alongFirst ^ facing.getAxis() == Axis.Z ? 90 : 0) + .translate(0, -9 / 16f, 0) + .multiply(Vector3f.POSITIVE_X.getRadialQuaternion(-angleForTe)) + .translate(0, 9 / 16f, 0) + .unCentre(); - ms.translate(0, -9 / 16f, 0); - ms.multiply(Vector3f.POSITIVE_X.getRadialQuaternion(-angleForTe)); - ms.translate(0, 9 / 16f, 0); - - msr.unCentre(); - AllBlockPartials.GANTRY_COGS.renderOn(state) - .light(light) + cogs.light(light) .renderInto(ms, buffer.getBuffer(RenderType.getSolid())); - ms.pop(); } public static float getAngleForTe(KineticTileEntity te, final BlockPos pos, Axis axis) { - float time = AnimationTickHolder.getRenderTick(); + float time = AnimationTickHolder.getRenderTime(te.getWorld()); float offset = getRotationOffsetForPosition(te, pos, axis); return ((time * te.getSpeed() * 3f / 20 + offset) % 360) / 180 * (float) Math.PI; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageTileEntity.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java rename to src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageTileEntity.java index b351131e9..10e5a986f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageTileEntity.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement.gantry; -import static net.minecraft.state.properties.BlockStateProperties.FACING; - import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; @@ -9,7 +7,6 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftTileEntity; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; @@ -18,12 +15,14 @@ import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; -public class GantryPinionTileEntity extends KineticTileEntity implements IDisplayAssemblyExceptions { +import static net.minecraft.state.properties.BlockStateProperties.FACING; + +public class GantryCarriageTileEntity extends KineticTileEntity implements IDisplayAssemblyExceptions { boolean assembleNextTick; protected AssemblyException lastException; - public GantryPinionTileEntity(TileEntityType typeIn) { + public GantryCarriageTileEntity(TileEntityType typeIn) { super(typeIn); } @@ -61,7 +60,7 @@ public class GantryPinionTileEntity extends KineticTileEntity implements IDispla private void tryAssemble() { BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof GantryPinionBlock)) + if (!(blockState.getBlock() instanceof GantryCarriageBlock)) return; Direction direction = blockState.get(FACING); @@ -129,9 +128,9 @@ public class GantryPinionTileEntity extends KineticTileEntity implements IDispla return defaultModifier; Direction direction = Direction.getFacingFromVector(diff.getX(), diff.getY(), diff.getZ()); - if (stateFrom.get(GantryPinionBlock.FACING) != direction.getOpposite()) + if (stateFrom.get(GantryCarriageBlock.FACING) != direction.getOpposite()) return defaultModifier; - return getGantryPinionModifier(stateTo.get(GantryShaftBlock.FACING), stateFrom.get(GantryPinionBlock.FACING)); + return getGantryPinionModifier(stateTo.get(GantryShaftBlock.FACING), stateFrom.get(GantryCarriageBlock.FACING)); } public static float getGantryPinionModifier(Direction shaft, Direction pinionDirection) { @@ -152,9 +151,9 @@ public class GantryPinionTileEntity extends KineticTileEntity implements IDispla private boolean shouldAssemble() { BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof GantryPinionBlock)) + if (!(blockState.getBlock() instanceof GantryCarriageBlock)) return false; - Direction facing = blockState.get(GantryPinionBlock.FACING) + Direction facing = blockState.get(GantryCarriageBlock.FACING) .getOpposite(); BlockState shaftState = world.getBlockState(pos.offset(facing)); if (!(shaftState.getBlock() instanceof GantryShaftBlock)) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java index 0db74075e..2c48a1128 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java @@ -1,12 +1,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.gantry; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.NonStationaryLighter; -import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; - +import com.simibubi.create.content.contraptions.components.structureMovement.*; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -60,7 +55,7 @@ public class GantryContraption extends TranslatingContraption { @Override protected boolean shouldUpdateAfterMovement(BlockInfo info) { - return super.shouldUpdateAfterMovement(info) && !AllBlocks.GANTRY_PINION.has(info.state); + return super.shouldUpdateAfterMovement(info) && !AllBlocks.GANTRY_CARRIAGE.has(info.state); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java index 6467a0ee1..5cde6b092 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java @@ -1,29 +1,27 @@ package com.simibubi.create.content.contraptions.components.structureMovement.glue; -import javax.annotation.Nullable; - -import org.apache.commons.lang3.Validate; - +import com.simibubi.create.AllBlocks; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; import com.simibubi.create.content.schematics.ISpecialEntityItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.BlockFace; - +import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.DirectionalBlock; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntitySize; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.MoverType; -import net.minecraft.entity.Pose; +import net.minecraft.entity.*; import net.minecraft.entity.effect.LightningBoltEntity; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; @@ -31,19 +29,10 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.IPacket; import net.minecraft.network.PacketBuffer; -import net.minecraft.util.ActionResultType; -import net.minecraft.util.DamageSource; -import net.minecraft.util.Direction; +import net.minecraft.state.BooleanProperty; +import net.minecraft.util.*; import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Hand; -import net.minecraft.util.Mirror; -import net.minecraft.util.Rotation; -import net.minecraft.util.SoundEvents; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.*; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; @@ -54,6 +43,9 @@ import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.PacketDistributor; +import org.apache.commons.lang3.Validate; + +import javax.annotation.Nullable; public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnData, ISpecialEntityItemRequirement { @@ -160,6 +152,9 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat public boolean isVisible() { if (!isAlive()) return false; + if (world instanceof WrappedWorld) + return true; + BlockPos pos = hangingPosition; BlockPos pos2 = pos.offset(getFacingDirection().getOpposite()); return isValidFace(world, pos2, getFacingDirection()) != isValidFace(world, pos, @@ -174,6 +169,8 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat if (!isValidFace(world, pos2, getFacingDirection()) && !isValidFace(world, pos, getFacingDirection().getOpposite())) return false; + if (isSideSticky(world, pos2, getFacingDirection()) || isSideSticky(world, pos, getFacingDirection().getOpposite())) + return false; return world.getEntitiesInAABBexcluding(this, getBoundingBox(), e -> e instanceof SuperGlueEntity) .isEmpty(); } @@ -189,6 +186,38 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat return true; } + public static boolean isSideSticky(World world, BlockPos pos, Direction direction) { + BlockState state = world.getBlockState(pos); + if (AllBlocks.STICKY_MECHANICAL_PISTON.has(state)) + return state.get(DirectionalKineticBlock.FACING) == direction; + + if (AllBlocks.STICKER.has(state)) + return state.get(DirectionalBlock.FACING) == direction; + + if (state.getBlock() == Blocks.SLIME_BLOCK) + return true; + if (state.getBlock() == Blocks.HONEY_BLOCK) + return true; + + if (AllBlocks.CART_ASSEMBLER.has(state)) + return Direction.UP == direction; + + if (AllBlocks.GANTRY_CARRIAGE.has(state)) + return state.get(DirectionalKineticBlock.FACING) == direction; + + if (state.getBlock() instanceof BearingBlock) { + return state.get(DirectionalKineticBlock.FACING) == direction; + } + + if (state.getBlock() instanceof AbstractChassisBlock) { + BooleanProperty glueableSide = ((AbstractChassisBlock) state.getBlock()).getGlueableSide(state, direction); + if (glueableSide == null) return false; + return state.get(glueableSide); + } + + return false; + } + @Override public boolean canBeCollidedWith() { return true; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java index fac0fa81f..ebdfe71aa 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java @@ -1,13 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement.mounted; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; @@ -26,7 +18,6 @@ import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.AbstractRailBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -49,13 +40,8 @@ import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.RailShape; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ActionResultType; -import net.minecraft.util.Direction; +import net.minecraft.util.*; import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Hand; -import net.minecraft.util.Rotation; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.SoundEvents; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.MathHelper; @@ -70,6 +56,13 @@ import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.LazyOptional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + public class CartAssemblerBlock extends AbstractRailBlock implements ITE, IWrenchable, ISpecialBlockItemRequirement { @@ -92,11 +85,13 @@ public class CartAssemblerBlock extends AbstractRailBlock } private static Item getRailItem(BlockState state) { - return state.get(RAIL_TYPE).getItem(); + return state.get(RAIL_TYPE) + .getItem(); } public static BlockState getRailBlock(BlockState state) { - AbstractRailBlock railBlock = (AbstractRailBlock) state.get(RAIL_TYPE).getBlock(); + AbstractRailBlock railBlock = (AbstractRailBlock) state.get(RAIL_TYPE) + .getBlock(); BlockState railState = railBlock.getDefaultState() .with(railBlock.getShapeProperty(), state.get(RAIL_SHAPE)); if (railState.contains(ControllerRailBlock.BACKWARDS)) { @@ -193,11 +188,21 @@ public class CartAssemblerBlock extends AbstractRailBlock disassemble(world, pos, cart); if (action == CartAssemblerAction.ASSEMBLE_ACCELERATE) { Direction facing = cart.getAdjustedHorizontalFacing(); + + RailShape railShape = state.get(RAIL_SHAPE); + for (Direction d : Iterate.directionsInAxis(railShape == RailShape.EAST_WEST ? Axis.X : Axis.Z)) + if (world.getBlockState(pos.offset(d)) + .isNormalCube(world, pos.offset(d))) + facing = d.getOpposite(); + float speed = getRailMaxSpeed(state, world, pos, cart); cart.setMotion(facing.getXOffset() * speed, facing.getYOffset() * speed, facing.getZOffset() * speed); } if (action == CartAssemblerAction.ASSEMBLE_ACCELERATE_DIRECTIONAL) { - Vector3i accelerationVector = ControllerRailBlock.getAccelerationVector(AllBlocks.CONTROLLER_RAIL.getDefaultState().with(ControllerRailBlock.SHAPE, state.get(RAIL_SHAPE)).with(ControllerRailBlock.BACKWARDS, state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS)); + Vector3i accelerationVector = ControllerRailBlock.getAccelerationVector( + AllBlocks.CONTROLLER_RAIL.getDefaultState() + .with(ControllerRailBlock.SHAPE, state.get(RAIL_SHAPE)) + .with(ControllerRailBlock.BACKWARDS, state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS)); float speed = getRailMaxSpeed(state, world, pos, cart); cart.setMotion(Vector3d.of(accelerationVector).scale(speed)); } @@ -240,7 +245,8 @@ public class CartAssemblerBlock extends AbstractRailBlock .isEmpty() ? CartAssemblerAction.ASSEMBLE_ACCELERATE : CartAssemblerAction.DISASSEMBLE; if (type == CartAssembleRailType.CONTROLLER_RAIL || type == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS) - return powered ? CartAssemblerAction.ASSEMBLE_ACCELERATE_DIRECTIONAL : CartAssemblerAction.DISASSEMBLE_BRAKE; + return powered ? CartAssemblerAction.ASSEMBLE_ACCELERATE_DIRECTIONAL + : CartAssemblerAction.DISASSEMBLE_BRAKE; return CartAssemblerAction.PASS; } @@ -289,10 +295,9 @@ public class CartAssemblerBlock extends AbstractRailBlock .isCoupledThroughContraption()) return; - Optional assembler = getTileEntityOptional(world, pos); CartMovementMode mode = assembler.map(te -> CartMovementMode.values()[te.movementMode.value]) - .orElse(CartMovementMode.ROTATE); + .orElse(CartMovementMode.ROTATE); MountedContraption contraption = new MountedContraption(mode); try { @@ -400,8 +405,6 @@ public class CartAssemblerBlock extends AbstractRailBlock @Override public void neighborChanged(@Nonnull BlockState state, @Nonnull World worldIn, @Nonnull BlockPos pos, @Nonnull Block blockIn, @Nonnull BlockPos fromPos, boolean isMoving) { - super.neighborChanged(state, worldIn, pos, blockIn, fromPos, isMoving); - if (worldIn.isRemote) return; @@ -409,6 +412,8 @@ public class CartAssemblerBlock extends AbstractRailBlock if (previouslyPowered != worldIn.isBlockPowered(pos)) { worldIn.setBlockState(pos, state.cycle(POWERED), 2); } + + super.neighborChanged(state, worldIn, pos, blockIn, fromPos, isMoving); } @Override @@ -475,7 +480,7 @@ public class CartAssemblerBlock extends AbstractRailBlock @Override public ItemRequirement getRequiredItems(BlockState state) { - ArrayList reuiredItems = new ArrayList(); + ArrayList reuiredItems = new ArrayList<>(); reuiredItems.add(new ItemStack(getRailItem(state))); reuiredItems.add(new ItemStack(asItem())); return new ItemRequirement(ItemUseType.CONSUME, reuiredItems); @@ -536,15 +541,22 @@ public class CartAssemblerBlock extends AbstractRailBlock if (world.isRemote) return ActionResultType.SUCCESS; BlockPos pos = context.getPos(); - BlockState newState = state.with(RAIL_SHAPE, state.get(RAIL_SHAPE) == RailShape.NORTH_SOUTH ? RailShape.EAST_WEST : RailShape.NORTH_SOUTH); - if (state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL || state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS) { - newState = newState.with(RAIL_TYPE, AllBlocks.CONTROLLER_RAIL.get().rotate(AllBlocks.CONTROLLER_RAIL.getDefaultState() - .with(ControllerRailBlock.SHAPE, state.get(RAIL_SHAPE)).with(ControllerRailBlock.BACKWARDS, - state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS), Rotation.CLOCKWISE_90) - .get(ControllerRailBlock.BACKWARDS) ? CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS : CartAssembleRailType.CONTROLLER_RAIL); + BlockState newState = state.with(RAIL_SHAPE, + state.get(RAIL_SHAPE) == RailShape.NORTH_SOUTH ? RailShape.EAST_WEST : RailShape.NORTH_SOUTH); + if (state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL + || state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS) { + newState = newState.with(RAIL_TYPE, AllBlocks.CONTROLLER_RAIL.get() + .rotate(AllBlocks.CONTROLLER_RAIL.getDefaultState() + .with(ControllerRailBlock.SHAPE, state.get(RAIL_SHAPE)) + .with(ControllerRailBlock.BACKWARDS, + state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS), + Rotation.CLOCKWISE_90) + .get(ControllerRailBlock.BACKWARDS) ? CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS + : CartAssembleRailType.CONTROLLER_RAIL); } - context.getWorld().setBlockState(pos, newState, 3); - world.notifyNeighborsOfStateChange(pos.down(), this); + context.getWorld() + .setBlockState(pos, newState, 3); + world.notifyNeighborsOfStateChange(pos.down(), this); return ActionResultType.SUCCESS; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java index 6c38f9c41..81334cda8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java @@ -1,16 +1,10 @@ package com.simibubi.create.content.contraptions.components.structureMovement.mounted; -import java.util.List; -import java.util.Optional; - -import javax.annotation.Nullable; - import com.simibubi.create.AllItems; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; import com.simibubi.create.foundation.utility.NBTHelper; - import net.minecraft.block.AbstractRailBlock; import net.minecraft.block.BlockState; import net.minecraft.block.DispenserBlock; @@ -37,6 +31,10 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Optional; + @EventBusSubscriber public class MinecartContraptionItem extends Item { @@ -169,7 +167,9 @@ public class MinecartContraptionItem extends Item { Contraption mountedContraption = Contraption.fromNBT(world, contraptionTag, false); OrientedContraptionEntity contraptionEntity = - OrientedContraptionEntity.create(world, mountedContraption, intialOrientation); + newFacing == null ? OrientedContraptionEntity.create(world, mountedContraption, intialOrientation) + : OrientedContraptionEntity.createAtYaw(world, mountedContraption, intialOrientation, + newFacing.getHorizontalAngle()); contraptionEntity.startRiding(cart); contraptionEntity.setPosition(cart.getX(), cart.getY(), cart.getZ()); @@ -209,7 +209,8 @@ public class MinecartContraptionItem extends Item { OrientedContraptionEntity contraption = (OrientedContraptionEntity) passengers.get(0); if (!event.getWorld().isRemote) { - player.inventory.placeItemBackInInventory(event.getWorld(), create(type, contraption).setDisplayName(entity.getCustomName())); + player.inventory.placeItemBackInInventory(event.getWorld(), + create(type, contraption).setDisplayName(entity.getCustomName())); contraption.remove(); entity.remove(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java index 9134d040b..8ef835f5b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java @@ -9,7 +9,6 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Dir import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; @@ -47,8 +46,6 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity { if (!(world.getBlockState(pos) .getBlock() instanceof MechanicalPistonBlock)) return; - if (getMovementSpeed() == 0) - return; Direction direction = getBlockState().get(BlockStateProperties.FACING); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java index 7092ef542..171e0421b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java @@ -1,20 +1,13 @@ package com.simibubi.create.content.contraptions.components.structureMovement.piston; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPiston; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; - -import java.util.function.Predicate; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; +import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*; import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ProperDirectionalBlock; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import com.simibubi.create.foundation.utility.placement.util.PoleHelper; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -41,6 +34,10 @@ import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorld; import net.minecraft.world.World; +import java.util.function.Predicate; + +import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*; + public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements IWrenchable, IWaterLoggable { private static final int placementHelperId = PlacementHelpers.register(PlacementHelper.get()); @@ -122,7 +119,7 @@ public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); if (placementHelper.matchesItem(heldItem) && !player.isSneaking()) - return placementHelper.getOffset(world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + return placementHelper.getOffset(player, world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); return ActionResultType.PASS; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java index 182e063bb..1975c0d29 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java @@ -6,7 +6,6 @@ import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.foundation.render.SuperByteBuffer; - import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.MathHelper; @@ -41,9 +40,7 @@ public class PulleyRenderer extends AbstractPulleyRenderer { @Override protected float getOffset(KineticTileEntity te, float partialTicks) { PulleyTileEntity pulley = (PulleyTileEntity) te; - boolean running = pulley.running; - boolean moving = running && (pulley.movedContraption == null || !pulley.movedContraption.isStalled()); - float offset = pulley.getInterpolatedOffset(moving ? partialTicks : 0.5f); + float offset = pulley.getInterpolatedOffset(partialTicks); if (pulley.movedContraption != null) { AbstractContraptionEntity e = pulley.movedContraption; @@ -57,7 +54,7 @@ public class PulleyRenderer extends AbstractPulleyRenderer { @Override protected boolean isRunning(KineticTileEntity te) { - return ((PulleyTileEntity) te).running; + return ((PulleyTileEntity) te).running || te.isVirtual(); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java index 78d057478..af702ae4d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java @@ -9,7 +9,6 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pis import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.IWaterLoggable; @@ -27,6 +26,7 @@ import net.minecraft.util.math.vector.Vector3d; public class PulleyTileEntity extends LinearActuatorTileEntity { protected int initialOffset; + private float prevAnimatedOffset; public PulleyTileEntity(TileEntityType type) { super(type); @@ -41,6 +41,13 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { public double getMaxRenderDistanceSquared() { return super.getMaxRenderDistanceSquared() + offset * offset; } + + @Override + public void tick() { + super.tick(); + if (isVirtual()) + prevAnimatedOffset = offset; + } @Override protected void assemble() throws AssemblyException { @@ -219,4 +226,20 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { return new CenteredSideValueBoxTransform((state, d) -> d == Direction.UP); } + @Override + public float getInterpolatedOffset(float partialTicks) { + if (isVirtual()) + return MathHelper.lerp(partialTicks, prevAnimatedOffset, offset); + boolean moving = running && (movedContraption == null || !movedContraption.isStalled()); + return super.getInterpolatedOffset(moving ? partialTicks : 0.5f); + } + + public void animateOffset(float forcedOffset) { + offset = forcedOffset; + } + + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ActorInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ActorInstance.java new file mode 100644 index 000000000..97d7ecc34 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ActorInstance.java @@ -0,0 +1,29 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.foundation.utility.VecHelper; +import net.minecraft.util.Direction; +import net.minecraft.world.LightType; + +public abstract class ActorInstance { + protected final ContraptionKineticRenderer modelManager; + protected final MovementContext context; + + public ActorInstance(ContraptionKineticRenderer modelManager, MovementContext context) { + this.modelManager = modelManager; + this.context = context; + } + + protected void tick() { } + + protected float getSpeed(Direction facing) { + if (context.contraption.stalled) + return 0; + + return !VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite()) ? context.getAnimationSpeed() : 0; + } + + protected int localBlockLight() { + return modelManager.contraption.renderWorld.getLightLevel(LightType.BLOCK, context.localPos); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java index 6733cd22a..880a7b779 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java @@ -1,22 +1,75 @@ package com.simibubi.create.content.contraptions.components.structureMovement.render; +import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; import com.simibubi.create.content.contraptions.base.RotatingInstancedModel; +import com.simibubi.create.content.contraptions.components.actors.ContraptionActorData; import com.simibubi.create.content.contraptions.components.actors.RotatingActorModel; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel; +import com.simibubi.create.content.logistics.block.FlapInstancedModel; import com.simibubi.create.foundation.render.AllProgramSpecs; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; - +import com.simibubi.create.foundation.render.backend.instancing.impl.BasicInstancedModel; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.gen.feature.template.Template; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nullable; +import java.util.ArrayList; public class ContraptionKineticRenderer extends InstancedTileRenderer { + protected ArrayList actors = new ArrayList<>(); + + public final RenderedContraption contraption; + + ContraptionKineticRenderer(RenderedContraption contraption) { + this.contraption = contraption; + } + @Override public void registerMaterials() { - materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_BELT, BeltInstancedModel::new)); - materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_ROTATING, RotatingInstancedModel::new)); - materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_ACTOR, RotatingActorModel::new)); + materials.put(RenderMaterials.MODELS, new RenderMaterial<>(this, AllProgramSpecs.C_MODEL, BasicInstancedModel::new)); + + materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(this, AllProgramSpecs.C_BELT, BeltInstancedModel::new)); + materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.C_ROTATING, RotatingInstancedModel::new)); + materials.put(KineticRenderMaterials.FLAPS, new RenderMaterial<>(this, AllProgramSpecs.C_FLAPS, FlapInstancedModel::new)); + materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(this, AllProgramSpecs.C_ACTOR, RotatingActorModel::new)); + } + + + @Override + public void beginFrame(double cameraX, double cameraY, double cameraZ) { + super.beginFrame(cameraX, cameraY, cameraZ); + + actors.forEach(ActorInstance::tick); + } + + @Nullable + public ActorInstance createActor(Pair actor) { + Template.BlockInfo blockInfo = actor.getLeft(); + MovementContext context = actor.getRight(); + + MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state); + + if (movementBehaviour != null && movementBehaviour.hasSpecialInstancedRendering()) { + ActorInstance instance = movementBehaviour.createInstance(this, context); + + actors.add(instance); + + return instance; + } + + return null; + } + + public RenderMaterial> getActorMaterial() { + return getMaterial(KineticRenderMaterials.ACTORS); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionModel.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionModel.java index c5bb45e7b..e29b706ad 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionModel.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionModel.java @@ -1,22 +1,70 @@ package com.simibubi.create.content.contraptions.components.structureMovement.render; -import java.nio.ByteBuffer; - import com.simibubi.create.foundation.render.backend.BufferedModel; +import com.simibubi.create.foundation.render.backend.gl.GlBuffer; +import com.simibubi.create.foundation.render.backend.gl.GlPrimitiveType; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; - import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.LightTexture; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL20; + +import java.nio.ByteBuffer; public class ContraptionModel extends BufferedModel { public static final VertexFormat FORMAT = VertexFormat.builder() .addAttributes(ContraptionVertexAttributes.class) .build(); + protected GlPrimitiveType eboIndexType; + protected GlBuffer ebo; + public ContraptionModel(BufferBuilder buf) { super(buf); } + @Override + protected void init() { + super.init(); + + createEBO(); + } + + @Override + protected void doRender() { + modelVBO.bind(); + ebo.bind(); + + setupAttributes(); + GL20.glDrawElements(GL20.GL_QUADS, vertexCount, eboIndexType.getGlConstant(), 0); + + int numAttributes = getTotalShaderAttributeCount(); + for (int i = 0; i <= numAttributes; i++) { + GL20.glDisableVertexAttribArray(i); + } + + ebo.unbind(); + modelVBO.unbind(); + } + + protected final void createEBO() { + ebo = new GlBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER); + eboIndexType = GlPrimitiveType.UINT; // TODO: choose this based on the number of vertices + + int indicesSize = vertexCount * eboIndexType.getSize(); + + ebo.bind(); + + GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesSize, GL15.GL_STATIC_DRAW); + ebo.map(indicesSize, indices -> { + for (int i = 0; i < vertexCount; i++) { + indices.putInt(i); + } + }); + + ebo.unbind(); + } + @Override protected void copyVertex(ByteBuffer to, int vertex) { to.putFloat(getX(template, vertex)); @@ -48,4 +96,10 @@ public class ContraptionModel extends BufferedModel { protected VertexFormat getModelFormat() { return FORMAT; } + + @Override + protected void deleteInternal() { + super.deleteInternal(); + ebo.delete(); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java index a20137d53..2ec5bce4c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java @@ -1,12 +1,11 @@ package com.simibubi.create.content.contraptions.components.structureMovement.render; -import org.lwjgl.opengl.GL20; - import com.simibubi.create.foundation.render.backend.gl.BasicProgram; - +import com.simibubi.create.foundation.render.backend.gl.shader.ProgramFogMode; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.vector.Matrix4f; +import org.lwjgl.opengl.GL20; public class ContraptionProgram extends BasicProgram { protected final int uLightBoxSize; @@ -15,8 +14,8 @@ public class ContraptionProgram extends BasicProgram { protected int uLightVolume; - public ContraptionProgram(ResourceLocation name, int handle) { - super(name, handle); + public ContraptionProgram(ResourceLocation name, int handle, ProgramFogMode.Factory fogFactory) { + super(name, handle, fogFactory); uLightBoxSize = getUniformLocation("uLightBoxSize"); uLightBoxMin = getUniformLocation("uLightBoxMin"); uModel = getUniformLocation("uModel"); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java index 3611eafc1..6a10841c8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java @@ -1,13 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement.render; -import java.util.List; -import java.util.Random; - -import org.apache.commons.lang3.tuple.Pair; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL13; -import org.lwjgl.opengl.GL40; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.CreateClient; @@ -15,29 +7,17 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Abs import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.foundation.render.AllProgramSpecs; -import com.simibubi.create.foundation.render.Compartment; -import com.simibubi.create.foundation.render.SuperByteBuffer; -import com.simibubi.create.foundation.render.SuperByteBufferCache; -import com.simibubi.create.foundation.render.TileEntityRenderHelper; +import com.simibubi.create.foundation.render.*; import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; - import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BlockModelRenderer; -import net.minecraft.client.renderer.BlockRendererDispatcher; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.RenderTypeLookup; -import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; @@ -50,22 +30,29 @@ import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.model.data.EmptyModelData; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL40; + +import java.util.List; +import java.util.Random; public class ContraptionRenderDispatcher { public static final Int2ObjectMap renderers = new Int2ObjectOpenHashMap<>(); public static final Compartment> CONTRAPTION = new Compartment<>(); protected static PlacementSimulationWorld renderWorld; - private static boolean firstLayer = true; - public static void notifyLightUpdate(IBlockDisplayReader world, LightType type, SectionPos pos) { for (RenderedContraption renderer : renderers.values()) { renderer.getLighter().lightVolume.notifyLightUpdate(world, type, pos); } } - public static void renderTick() { - firstLayer = true; + public static void notifyLightPacket(IBlockDisplayReader world, int chunkX, int chunkZ) { + for (RenderedContraption renderer : renderers.values()) { + renderer.getLighter().lightVolume.notifyLightPacket(world, chunkX, chunkZ); + } } public static void renderTileEntities(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, @@ -98,26 +85,23 @@ public class ContraptionRenderDispatcher { return contraption; } + public static void beginFrame(double camX, double camY, double camZ) { + for (RenderedContraption renderer : renderers.values()) { + renderer.beginFrame(camX, camY, camZ); + } + } + public static void renderLayer(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { removeDeadContraptions(); if (renderers.isEmpty()) return; - if (firstLayer) { - - for (RenderedContraption renderer : renderers.values()) { - renderer.beginFrame(camX, camY, camZ); - } - - firstLayer = false; - } - layer.startDrawing(); GL11.glEnable(GL13.GL_TEXTURE_3D); GL13.glActiveTexture(GL40.GL_TEXTURE4); // the shaders expect light volumes to be in texture 4 if (Backend.canUseVBOs()) { - ContraptionProgram structureShader = Backend.getProgram(AllProgramSpecs.CONTRAPTION_STRUCTURE); + ContraptionProgram structureShader = Backend.getProgram(AllProgramSpecs.C_STRUCTURE); structureShader.bind(viewProjection, camX, camY, camZ, FastRenderDispatcher.getDebugMode()); for (RenderedContraption renderer : renderers.values()) { renderer.doRenderLayer(layer, structureShader); @@ -210,12 +194,10 @@ public class ContraptionRenderDispatcher { builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); renderWorld.setTileEntities(c.presentTileEntities.values()); - for (Template.BlockInfo info : c.getBlocks() - .values()) + for (Template.BlockInfo info : c.getBlocks().values()) renderWorld.setBlockState(info.pos, info.state); - for (Template.BlockInfo info : c.getBlocks() - .values()) { + for (Template.BlockInfo info : c.getBlocks().values()) { BlockState state = info.state; if (state.getRenderType() == BlockRenderType.ENTITYBLOCK_ANIMATED) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java deleted file mode 100644 index cf2bd4059..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; - -public class ContraptionRenderer { - - - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionVertexAttributes.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionVertexAttributes.java index 6bfbf8af7..53e9931f9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionVertexAttributes.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionVertexAttributes.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.render; import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IAttribSpec; import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; @@ -26,7 +27,7 @@ public enum ContraptionVertexAttributes implements IVertexAttrib { } @Override - public VertexAttribSpec attribSpec() { + public IAttribSpec attribSpec() { return spec; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java index f178761fa..06c768fb4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java @@ -1,38 +1,18 @@ package com.simibubi.create.content.contraptions.components.structureMovement.render; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Random; - -import org.apache.commons.lang3.tuple.MutablePair; -import org.lwjgl.opengl.GL11; - import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.AllMovementBehaviours; -import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; -import com.simibubi.create.content.contraptions.components.actors.ContraptionActorData; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered; -import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; - import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BlockModelRenderer; -import net.minecraft.client.renderer.BlockRendererDispatcher; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.RenderTypeLookup; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; @@ -46,6 +26,12 @@ import net.minecraft.world.gen.feature.template.Template; import net.minecraft.world.lighting.WorldLightManager; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.model.data.EmptyModelData; +import org.lwjgl.opengl.GL11; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Random; public class RenderedContraption { private final HashMap renderLayers = new HashMap<>(); @@ -64,7 +50,7 @@ public class RenderedContraption { public RenderedContraption(World world, Contraption contraption) { this.contraption = contraption; this.lighter = contraption.makeLighter(); - this.kinetics = new ContraptionKineticRenderer(); + this.kinetics = new ContraptionKineticRenderer(this); this.renderWorld = setupRenderWorld(world, contraption); buildLayers(); @@ -86,10 +72,6 @@ public class RenderedContraption { return lighter; } - public RenderMaterial> getActorMaterial() { - return kinetics.getMaterial(KineticRenderMaterials.ACTORS); - } - public void doRenderLayer(RenderType layer, ContraptionProgram shader) { ContraptionModel structure = renderLayers.get(layer); if (structure != null) { @@ -100,6 +82,8 @@ public class RenderedContraption { } public void beginFrame(double camX, double camY, double camZ) { + kinetics.beginFrame(camX, camY, camZ); + AbstractContraptionEntity entity = contraption.entity; float pt = AnimationTickHolder.getPartialTicks(); @@ -170,18 +154,7 @@ public class RenderedContraption { } private void buildActors() { - List> actors = contraption.getActors(); - - for (MutablePair actor : actors) { - Template.BlockInfo blockInfo = actor.left; - MovementContext context = actor.right; - - MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state); - - if (movementBehaviour != null) { - movementBehaviour.addInstance(this, context); - } - } + contraption.getActors().forEach(kinetics::createActor); } private static ContraptionModel buildStructureModel(PlacementSimulationWorld renderWorld, Contraption c, RenderType layer) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeConnection.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeConnection.java index 9a4038f94..a77de5441 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeConnection.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeConnection.java @@ -1,18 +1,13 @@ package com.simibubi.create.content.contraptions.fluids; -import java.util.Optional; -import java.util.Random; -import java.util.function.Predicate; - import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.LerpedFloat; import com.simibubi.create.foundation.utility.VecHelper; - +import com.simibubi.create.foundation.utility.animation.LerpedFloat; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.nbt.CompoundNBT; @@ -30,6 +25,10 @@ import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fml.DistExecutor; +import java.util.Optional; +import java.util.Random; +import java.util.function.Predicate; + public class PipeConnection { Direction side; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java index 99b4bebec..efca3411e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java @@ -5,20 +5,11 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; -import net.minecraft.tileentity.TileEntityType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; - public class PumpCogInstance extends SingleRotatingInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, PumpCogInstance::new)); - } - public PumpCogInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public PumpCogInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java index 0f60a0b09..ff12d494f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java @@ -1,28 +1,14 @@ package com.simibubi.create.content.contraptions.fluids; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Nullable; - -import org.apache.commons.lang3.mutable.MutableBoolean; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.LerpedFloat; -import com.simibubi.create.foundation.utility.LerpedFloat.Chaser; import com.simibubi.create.foundation.utility.Pair; - +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; @@ -34,6 +20,11 @@ import net.minecraft.world.IWorld; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; +import org.apache.commons.lang3.mutable.MutableBoolean; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.Map.Entry; public class PumpTileEntity extends KineticTileEntity { diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java index a45423dc6..d5d8034a2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java @@ -1,14 +1,11 @@ package com.simibubi.create.content.contraptions.fluids.actors; -import java.util.List; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.fluid.SmartFluidTank; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.LerpedFloat; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - +import com.simibubi.create.foundation.utility.animation.LerpedFloat; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; @@ -22,6 +19,8 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; +import java.util.List; + public class HosePulleyTileEntity extends KineticTileEntity { LerpedFloat offset; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainBlock.java index 16f2a9470..782040a0a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainBlock.java @@ -6,7 +6,7 @@ import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.fluid.FluidHelper; - +import com.simibubi.create.foundation.tileEntity.ComparatorUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -99,4 +99,14 @@ public class ItemDrainBlock extends Block implements IWrenchable, ITE 1 && EmptyingByBasin.canItemBeEmptied(world, inserted)) { returned = ItemHandlerHelper.copyStackWithSize(inserted, inserted.getCount() - 1); inserted = ItemHandlerHelper.copyStackWithSize(inserted, 1); } - + if (simulate) return returned; @@ -91,15 +93,18 @@ public class ItemDrainTileEntity extends SmartTileEntity { @Override public void tick() { super.tick(); + if (heldItem == null) { processingTicks = 0; return; } + boolean onClient = world.isRemote && !isVirtual(); + if (processingTicks > 0) { heldItem.prevBeltPosition = .5f; boolean wasAtBeginning = processingTicks == FILLING_TIME; - if (!world.isRemote || processingTicks < FILLING_TIME) + if (!onClient || processingTicks < FILLING_TIME) processingTicks--; if (!continueProcessing()) { processingTicks = 0; @@ -118,7 +123,7 @@ public class ItemDrainTileEntity extends SmartTileEntity { if (heldItem.beltPosition > 1) { heldItem.beltPosition = 1; - if (world.isRemote) + if (onClient) return; Direction side = heldItem.insertedFrom; @@ -187,7 +192,7 @@ public class ItemDrainTileEntity extends SmartTileEntity { if (!EmptyingByBasin.canItemBeEmptied(world, heldItem.stack)) return; heldItem.beltPosition = .5f; - if (world.isRemote) + if (onClient) return; processingTicks = FILLING_TIME; sendData(); @@ -196,7 +201,7 @@ public class ItemDrainTileEntity extends SmartTileEntity { } protected boolean continueProcessing() { - if (world.isRemote) + if (world.isRemote && !isVirtual()) return true; if (processingTicks < 5) return true; @@ -282,4 +287,9 @@ public class ItemDrainTileEntity extends SmartTileEntity { return super.getCapability(cap, side); } + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + return containedFluidTooltip(tooltip, isPlayerSneaking, getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutBlock.java index f7436a0a7..a2fb4acf4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutBlock.java @@ -3,7 +3,7 @@ package com.simibubi.create.content.contraptions.fluids.actors; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.wrench.IWrenchable; - +import com.simibubi.create.foundation.tileEntity.ComparatorUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntity; @@ -11,6 +11,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; public class SpoutBlock extends Block implements IWrenchable { @@ -34,4 +35,14 @@ public class SpoutBlock extends Block implements IWrenchable { return AllTileEntities.SPOUT.create(); } + @Override + public boolean hasComparatorInputOverride(BlockState state) { + return true; + } + + @Override + public int getComparatorInputOverride(BlockState blockState, World worldIn, BlockPos pos) { + return ComparatorUtil.levelOfSmartFluidTank(worldIn, pos); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java index e592e4060..be66a8911 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java @@ -1,14 +1,7 @@ package com.simibubi.create.content.contraptions.fluids.actors; -import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.HOLD; -import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.PASS; - -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nullable; - import com.simibubi.create.content.contraptions.fluids.FluidFX; +import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; @@ -19,7 +12,6 @@ import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemS import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; import net.minecraft.item.PotionItem; @@ -32,6 +24,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.ITextComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; @@ -41,9 +34,15 @@ import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fml.ModList; -public class SpoutTileEntity extends SmartTileEntity { - private static final boolean IS_TIC_LOADED = ModList.get() - .isLoaded("tconstruct"); +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.HOLD; +import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.PASS; + +public class SpoutTileEntity extends SmartTileEntity implements IHaveGoggleInformation { + private static final boolean IS_TIC_LOADED = ModList.get().isLoaded("tconstruct"); private static final Class CASTING_FLUID_HANDLER_CLASS; static { Class testClass; @@ -70,12 +69,12 @@ public class SpoutTileEntity extends SmartTileEntity { } protected AxisAlignedBB cachedBoundingBox; + @Override @OnlyIn(Dist.CLIENT) public AxisAlignedBB getRenderBoundingBox() { - if (cachedBoundingBox == null) { + if (cachedBoundingBox == null) cachedBoundingBox = super.getRenderBoundingBox().expand(0, -2, 0); - } return cachedBoundingBox; } @@ -137,9 +136,10 @@ public class SpoutTileEntity extends SmartTileEntity { } AllTriggers.triggerForNearbyPlayers(AllTriggers.SPOUT, world, pos, 5); - if (out.getItem() instanceof PotionItem && !PotionUtils.getEffectsFromStack(out).isEmpty()) + if (out.getItem() instanceof PotionItem && !PotionUtils.getEffectsFromStack(out) + .isEmpty()) AllTriggers.triggerForNearbyPlayers(AllTriggers.SPOUT_POTION, world, pos, 5); - + tank.getPrimaryHandler() .setFluid(fluid); sendSplash = true; @@ -282,4 +282,8 @@ public class SpoutTileEntity extends SmartTileEntity { return -1; } + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + return containedFluidTooltip(tooltip, isPlayerSneaking, getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveBlock.java index aa93364de..3756d8b12 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveBlock.java @@ -1,13 +1,10 @@ package com.simibubi.create.content.contraptions.fluids.pipes; -import java.util.Random; - import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; import com.simibubi.create.content.contraptions.fluids.FluidPropagator; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.network.DebugPacketSender; @@ -25,6 +22,9 @@ import net.minecraft.world.TickPriority; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; +import javax.annotation.Nonnull; +import java.util.Random; + public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxisPipe { public static final BooleanProperty ENABLED = BooleanProperty.create("enabled"); @@ -60,9 +60,10 @@ public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxi return AllTileEntities.FLUID_VALVE.create(); } + @Nonnull public static Axis getPipeAxis(BlockState state) { if (!(state.getBlock() instanceof FluidValveBlock)) - return null; + throw new IllegalStateException("Provided BlockState is for a different block."); Direction facing = state.get(FACING); boolean alongFirst = !state.get(AXIS_ALONG_FIRST_COORDINATE); for (Axis axis : Iterate.axes) { @@ -74,7 +75,7 @@ public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxi } return axis; } - return null; + throw new IllegalStateException("Impossible axis."); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveInstance.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveInstance.java new file mode 100644 index 000000000..5125f5d19 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveInstance.java @@ -0,0 +1,88 @@ +package com.simibubi.create.content.contraptions.fluids.pipes; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; +import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; +import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.util.Direction; +import net.minecraft.util.math.MathHelper; + +public class FluidValveInstance extends ShaftInstance implements ITickableInstance { + + protected InstanceKey pointer; + + protected double xRot; + protected double yRot; + protected int pointerRotationOffset; + + public FluidValveInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + super(dispatcher, tile); + } + + @Override + protected void init() { + super.init(); + + Direction facing = lastState.get(FluidValveBlock.FACING); + + yRot = AngleHelper.horizontalAngle(facing); + xRot = facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90; + + Direction.Axis pipeAxis = FluidValveBlock.getPipeAxis(lastState); + Direction.Axis shaftAxis = KineticTileEntityRenderer.getRotationAxisOf(tile); + + pointerRotationOffset = 0; + if (pipeAxis.isHorizontal() && shaftAxis == Direction.Axis.Z || pipeAxis.isVertical()) + pointerRotationOffset = 90; + + pointer = modelManager.basicMaterial().getModel(AllBlockPartials.FLUID_VALVE_POINTER, lastState).createInstance(); + + updateLight(); + transformPointer((FluidValveTileEntity) tile); + } + + @Override + public void tick() { + + FluidValveTileEntity valve = (FluidValveTileEntity) tile; + + if (valve.pointer.settled()) return; + + transformPointer(valve); + } + + private void transformPointer(FluidValveTileEntity valve) { + float pointerRotation = MathHelper.lerp(valve.pointer.getValue(AnimationTickHolder.getPartialTicks()), 0, -90); + + MatrixStack ms = new MatrixStack(); + MatrixStacker.of(ms) + .translate(getFloatingPos()) + .centre() + .rotateY(yRot) + .rotateX(xRot) + .rotateY(pointerRotationOffset + pointerRotation) + .unCentre(); + + pointer.getInstance().setTransform(ms); + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, pointer.getInstance()); + } + + @Override + public void remove() { + super.remove(); + pointer.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java index 729d37d7d..c90fd0dd6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java @@ -5,9 +5,9 @@ import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.MatrixStacker; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -25,6 +25,9 @@ public class FluidValveRenderer extends KineticTileEntityRenderer { @Override protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + + if (FastRenderDispatcher.available(te.getWorld())) return; + super.renderSafe(te, partialTicks, ms, buffer, light, overlay); BlockState blockState = te.getBlockState(); SuperByteBuffer pointer = AllBlockPartials.FLUID_VALVE_POINTER.renderOn(blockState); diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveTileEntity.java index c56e0932f..92bcee149 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveTileEntity.java @@ -1,14 +1,11 @@ package com.simibubi.create.content.contraptions.fluids.pipes; -import java.util.List; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity.StraightPipeFluidTransportBehaviour; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.LerpedFloat; -import com.simibubi.create.foundation.utility.LerpedFloat.Chaser; - +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; @@ -16,6 +13,8 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.MathHelper; import net.minecraftforge.fluids.FluidStack; +import java.util.List; + public class FluidValveTileEntity extends KineticTileEntity { LerpedFloat pointer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java index 243cc52d7..864cab4cf 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java @@ -7,8 +7,7 @@ import com.simibubi.create.foundation.fluid.FluidRenderer; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.LerpedFloat; - +import com.simibubi.create.foundation.utility.animation.LerpedFloat; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluid.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluid.java index da3aa0bce..9ca9fb039 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluid.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluid.java @@ -1,11 +1,8 @@ package com.simibubi.create.content.contraptions.fluids.potion; -import java.util.Collection; -import java.util.List; - import com.simibubi.create.AllFluids; import com.simibubi.create.content.contraptions.fluids.VirtualFluid; - +import com.simibubi.create.foundation.utility.NBTHelper; import net.minecraft.fluid.Fluid; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.ListNBT; @@ -13,17 +10,21 @@ import net.minecraft.potion.EffectInstance; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionUtils; import net.minecraft.potion.Potions; +import net.minecraft.util.IItemProvider; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fluids.FluidAttributes; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.registries.ForgeRegistries; +import java.util.Collection; +import java.util.List; + public class PotionFluid extends VirtualFluid { public enum BottleType { REGULAR, SPLASH, LINGERING; } - + public PotionFluid(Properties properties) { super(properties); } @@ -49,6 +50,16 @@ public class PotionFluid extends VirtualFluid { return color; } + @Override + public String getTranslationKey(FluidStack stack) { + CompoundNBT tag = stack.getOrCreateTag(); + IItemProvider itemFromBottleType = + PotionFluidHandler.itemFromBottleType(NBTHelper.readEnum(tag, "Bottle", BottleType.class)); + return PotionUtils.getPotionTypeFromNBT(tag) + .getNamePrefixed(itemFromBottleType.asItem() + .getTranslationKey() + ".effect."); + } + } public static FluidStack addPotionToFluidStack(FluidStack fs, Potion potion) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluidHandler.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluidHandler.java index 7b850f00b..4e1c3b38b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluidHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluidHandler.java @@ -1,16 +1,11 @@ package com.simibubi.create.content.contraptions.fluids.potion; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - import com.google.common.collect.Lists; import com.simibubi.create.content.contraptions.fluids.potion.PotionFluid.BottleType; import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.fluid.FluidIngredient; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.Pair; - import net.minecraft.entity.ai.attributes.Attribute; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.fluid.Fluids; @@ -18,12 +13,7 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.potion.Effect; -import net.minecraft.potion.EffectInstance; -import net.minecraft.potion.EffectUtils; -import net.minecraft.potion.Potion; -import net.minecraft.potion.PotionUtils; -import net.minecraft.potion.Potions; +import net.minecraft.potion.*; import net.minecraft.util.IItemProvider; import net.minecraft.util.Tuple; import net.minecraft.util.text.ITextComponent; @@ -34,6 +24,10 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fluids.FluidStack; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + public class PotionFluidHandler { public static Pair emptyPotion(ItemStack stack, boolean simulate) { @@ -92,14 +86,6 @@ public class PotionFluidHandler { return potionStack; } - public static ITextComponent getPotionName(FluidStack fs) { - CompoundNBT tag = fs.getOrCreateTag(); - IItemProvider itemFromBottleType = itemFromBottleType(NBTHelper.readEnum(tag, "Bottle", BottleType.class)); - return new TranslationTextComponent(PotionUtils.getPotionTypeFromNBT(tag) - .getNamePrefixed(itemFromBottleType.asItem() - .getTranslationKey() + ".effect.")); - } - // Modified version of PotionUtils#addPotionTooltip @OnlyIn(Dist.CLIENT) public static void addPotionTooltip(FluidStack fs, List tooltip, float p_185182_2_) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java index 9648f3565..e4bbfbea5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java @@ -8,8 +8,8 @@ import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.fluid.FluidHelper.FluidExchange; +import com.simibubi.create.foundation.tileEntity.ComparatorUtil; import com.simibubi.create.foundation.utility.Lang; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.SoundType; @@ -25,14 +25,7 @@ import net.minecraft.state.EnumProperty; import net.minecraft.state.StateContainer.Builder; import net.minecraft.tags.FluidTags; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ActionResultType; -import net.minecraft.util.Hand; -import net.minecraft.util.IStringSerializable; -import net.minecraft.util.Mirror; -import net.minecraft.util.Rotation; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.SoundEvent; -import net.minecraft.util.SoundEvents; +import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.MathHelper; @@ -310,4 +303,17 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE ComparatorUtil.fractionToRedstoneLevel(te.getFillState())) + .orElse(0); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java index a4bf6f79c..673034926 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java @@ -1,19 +1,12 @@ package com.simibubi.create.content.contraptions.fluids.tank; -import static java.lang.Math.abs; - -import java.util.List; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock.Shape; +import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.fluid.SmartFluidTank; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTUtil; @@ -22,6 +15,7 @@ import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; @@ -34,7 +28,13 @@ import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; import net.minecraftforge.fluids.capability.templates.FluidTank; -public class FluidTankTileEntity extends SmartTileEntity { +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +import static java.lang.Math.abs; + +public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleInformation { private static final int MAX_SIZE = 3; @@ -89,14 +89,14 @@ public class FluidTankTileEntity extends SmartTileEntity { if (syncCooldown == 0 && queuedSync) sendData(); } - + if (lastKnownPos == null) lastKnownPos = getPos(); else if (!lastKnownPos.equals(pos) && pos != null) { onPositionChanged(); return; } - + if (updateConnectivity) updateConnectivity(); if (fluidLevel != null) @@ -104,10 +104,8 @@ public class FluidTankTileEntity extends SmartTileEntity { } public boolean isController() { - return controller == null || - pos.getX() == controller.getX() && - pos.getY() == controller.getY() && - pos.getZ() == controller.getZ(); + return controller == null + || pos.getX() == controller.getX() && pos.getY() == controller.getY() && pos.getZ() == controller.getZ(); } @Override @@ -285,6 +283,7 @@ public class FluidTankTileEntity extends SmartTileEntity { } private AxisAlignedBB cachedBoundingBox; + @Override @OnlyIn(Dist.CLIENT) public AxisAlignedBB getRenderBoundingBox() { @@ -312,10 +311,16 @@ public class FluidTankTileEntity extends SmartTileEntity { return null; } + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + return containedFluidTooltip(tooltip, isPlayerSneaking, + getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); + } + @Override protected void fromTag(BlockState state, CompoundNBT compound, boolean clientPacket) { super.fromTag(state, compound, clientPacket); - + BlockPos controllerBefore = controller; int prevSize = width; int prevHeight = height; @@ -438,11 +443,11 @@ public class FluidTankTileEntity extends SmartTileEntity { public static int getMaxHeight() { return AllConfigs.SERVER.fluids.fluidTankMaxHeight.get(); } - + public InterpolatedChasingValue getFluidLevel() { return fluidLevel; } - + public void setFluidLevel(InterpolatedChasingValue fluidLevel) { this.fluidLevel = fluidLevel; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/GogglesModel.java b/src/main/java/com/simibubi/create/content/contraptions/goggles/GogglesModel.java new file mode 100644 index 000000000..7533007ba --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/goggles/GogglesModel.java @@ -0,0 +1,23 @@ +package com.simibubi.create.content.contraptions.goggles; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.foundation.block.render.WrappedBakedModel; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; + +public class GogglesModel extends WrappedBakedModel { + + public GogglesModel(IBakedModel template) { + super(template); + } + + @Override + public IBakedModel handlePerspective(TransformType cameraTransformType, MatrixStack mat) { + if (cameraTransformType == TransformType.HEAD) + return AllBlockPartials.GOGGLES.get() + .handlePerspective(cameraTransformType, mat); + return super.handlePerspective(cameraTransformType, mat); + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java b/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java index 32a54caa5..fd500a67e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java +++ b/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java @@ -1,22 +1,32 @@ package com.simibubi.create.content.contraptions.goggles; -import java.text.DecimalFormat; -import java.util.List; - +import com.simibubi.create.foundation.utility.Lang; +import net.minecraft.client.Minecraft; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; + +import java.text.NumberFormat; +import java.util.List; +import java.util.Locale; +import java.util.Optional; /* * Implement this Interface in the TileEntity class that wants to add info to the screen * */ public interface IHaveGoggleInformation { - DecimalFormat decimalFormat = new DecimalFormat("#.##"); - public static String spacing = " "; - public static ITextComponent componentSpacing = new StringTextComponent(spacing); + Format numberFormat = new Format(); + String spacing = " "; + ITextComponent componentSpacing = new StringTextComponent(spacing); /** - * this method will be called when looking at a TileEntity that implemented this interface + * this method will be called when looking at a TileEntity that implemented this + * interface * * @return {@code true} if the tooltip creation was successful and should be displayed, * or {@code false} if the overlay should not be displayed @@ -26,7 +36,72 @@ public interface IHaveGoggleInformation { } static String format(double d) { - return decimalFormat.format(d); + return numberFormat.get().format(d); + } + + default boolean containedFluidTooltip(List tooltip, boolean isPlayerSneaking, LazyOptional handler) { + tooltip.add(componentSpacing.copy().append(Lang.translate("gui.goggles.fluid_container"))); + TranslationTextComponent mb = Lang.translate("generic.unit.millibuckets"); + Optional resolve = handler.resolve(); + if (!resolve.isPresent()) + return false; + + IFluidHandler tank = resolve.get(); + if (tank.getTanks() == 0) + return false; + + ITextComponent indent = new StringTextComponent(spacing + " "); + + boolean isEmpty = true; + for (int i = 0; i < tank.getTanks(); i++) { + FluidStack fluidStack = tank.getFluidInTank(i); + if (fluidStack.isEmpty()) + continue; + + ITextComponent fluidName = new TranslationTextComponent(fluidStack.getTranslationKey()).formatted(TextFormatting.GRAY); + ITextComponent contained = new StringTextComponent(format(fluidStack.getAmount()) + mb).formatted(TextFormatting.GOLD); + ITextComponent slash = new StringTextComponent(" / ").formatted(TextFormatting.GRAY); + ITextComponent capacity = new StringTextComponent(format(tank.getTankCapacity(i)) + mb).formatted(TextFormatting.DARK_GRAY); + + tooltip.add(indent.copy() + .append(fluidName)); + tooltip.add(indent.copy() + .append(contained) + .append(slash) + .append(capacity)); + + isEmpty = false; + } + + if (tank.getTanks() > 1 || !isEmpty) + return true; + + ITextComponent capacity = Lang.translate("gui.goggles.fluid_container.capacity").formatted(TextFormatting.GRAY); + ITextComponent amount = new StringTextComponent(format(tank.getTankCapacity(0)) + mb).formatted(TextFormatting.GOLD); + + tooltip.add(indent.copy() + .append(capacity) + .append(amount)); + return true; + } + + class Format { + + private NumberFormat format = NumberFormat.getNumberInstance(Locale.ROOT);; + + private Format() {} + + public NumberFormat get() { + return format; + } + + public void update() { + format = NumberFormat.getInstance(Minecraft.getInstance().getLanguageManager().getCurrentLanguage().getJavaLocale()); + format.setMaximumFractionDigits(2); + format.setMinimumFractionDigits(0); + format.setGroupingUsed(true); + } + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java b/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java index 8d16091a6..4cd05968f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java +++ b/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java @@ -5,7 +5,6 @@ import com.simibubi.create.content.contraptions.goggles.GogglesItem; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.particle.IAnimatedSprite; @@ -58,7 +57,7 @@ public class RotationIndicatorParticle extends SimpleAnimatedParticle { super.tick(); radius += (radius2 - radius) * .1f; } - + @Override public void buildGeometry(IVertexBuilder buffer, ActiveRenderInfo renderInfo, float partialTicks) { if (!isVisible) @@ -67,8 +66,10 @@ public class RotationIndicatorParticle extends SimpleAnimatedParticle { } public void move(double x, double y, double z) { - float time = AnimationTickHolder.getTicks(); + float time = AnimationTickHolder.getTicks(world); float angle = (float) ((time * speed) % 360) - (speed / 2 * age * (((float) age) / maxAge)); + if (speed < 0 && axis.isVertical()) + angle += 180; Vector3d position = VecHelper.rotate(this.offset.scale(radius), angle, axis).add(origin); posX = position.x; posY = position.y; @@ -84,10 +85,11 @@ public class RotationIndicatorParticle extends SimpleAnimatedParticle { public Particle makeParticle(RotationIndicatorParticleData data, ClientWorld worldIn, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) { - ClientPlayerEntity player = Minecraft.getInstance().player; - boolean visible = player != null && GogglesItem.canSeeParticles(player); + Minecraft mc = Minecraft.getInstance(); + ClientPlayerEntity player = mc.player; + boolean visible = worldIn != mc.world || player != null && GogglesItem.canSeeParticles(player); return new RotationIndicatorParticle(worldIn, x, y, z, data.color, data.radius1, data.radius2, data.speed, - data.getAxis(), data.lifeSpan, visible, this.spriteSet); + data.getAxis(), data.lifeSpan, visible, this.spriteSet); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java index 8a5f98693..4de4ba7ce 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java @@ -4,7 +4,9 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.fluids.actors.GenericItemFilling; +import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.fluid.FluidHelper; @@ -12,7 +14,6 @@ import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; @@ -170,11 +171,9 @@ public class BasinBlock extends Block implements ITE, IWrenchab @Override public int getComparatorInputOverride(BlockState blockState, World worldIn, BlockPos pos) { - try { - return ItemHelper.calcRedstoneFromInventory(getTileEntity(worldIn, pos).inputInventory); - } catch (TileEntityException e) { - } - return 0; + return getTileEntityOptional(worldIn, pos).map(BasinTileEntity::getInputInventory) + .map(ItemHelper::calcRedstoneFromInventory) + .orElse(0); } @Override @@ -184,15 +183,25 @@ public class BasinBlock extends Block implements ITE, IWrenchab public static boolean canOutputTo(IBlockReader world, BlockPos basinPos, Direction direction) { BlockPos neighbour = basinPos.offset(direction); - if (!world.getBlockState(neighbour) - .getCollisionShape(world, neighbour) - .isEmpty()) - return false; + BlockPos output = neighbour.down(); + BlockState blockState = world.getBlockState(neighbour); + + if (FunnelBlock.isFunnel(blockState)) { + if (FunnelBlock.getFunnelFacing(blockState) == direction) + return false; + } else if (!blockState.getCollisionShape(world, neighbour) + .isEmpty()) { + return false; + } else { + TileEntity tileEntity = world.getTileEntity(output); + if (tileEntity instanceof BeltTileEntity) { + BeltTileEntity belt = (BeltTileEntity) tileEntity; + return belt.getSpeed() == 0 || belt.getMovementFacing() != direction.getOpposite(); + } + } - BlockPos offset = basinPos.down() - .offset(direction); DirectBeltInputBehaviour directBeltInputBehaviour = - TileEntityBehaviour.get(world, offset, DirectBeltInputBehaviour.TYPE); + TileEntityBehaviour.get(world, output, DirectBeltInputBehaviour.TYPE); if (directBeltInputBehaviour != null) return directBeltInputBehaviour.canInsertFromSide(direction); return false; diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java index fa7531b6f..85cf71437 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java @@ -1,18 +1,11 @@ package com.simibubi.create.content.contraptions.processing; -import java.util.Random; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.fluid.FluidRenderer; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; -import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.IntAttached; -import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.VecHelper; - +import com.simibubi.create.foundation.utility.*; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -28,6 +21,8 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; +import java.util.Random; + public class BasinRenderer extends SmartTileEntityRenderer { public BasinRenderer(TileEntityRendererDispatcher dispatcher) { @@ -72,8 +67,9 @@ public class BasinRenderer extends SmartTileEntityRenderer { if (fluidLevel > 0) { ms.translate(0, - (MathHelper.sin(AnimationTickHolder.getRenderTick() / 12f + anglePartition * itemCount) + 1.5f) * 1 - / 32f, + (MathHelper.sin( + AnimationTickHolder.getRenderTime(basin.getWorld()) / 12f + anglePartition * itemCount) + 1.5f) + * 1 / 32f, 0); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java index 1ce9e3394..2c3483fe2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java @@ -1,19 +1,11 @@ package com.simibubi.create.content.contraptions.processing; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Random; - -import javax.annotation.Nonnull; - import com.simibubi.create.AllParticleTypes; import com.simibubi.create.AllTags; import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerTileEntity; import com.simibubi.create.content.contraptions.fluids.FluidFX; import com.simibubi.create.content.contraptions.fluids.particle.FluidParticleData; +import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.foundation.fluid.CombinedTankWrapper; @@ -25,16 +17,9 @@ import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputB import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; -import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.BlockHelper; -import com.simibubi.create.foundation.utility.Couple; -import com.simibubi.create.foundation.utility.IntAttached; -import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.LerpedFloat; -import com.simibubi.create.foundation.utility.LerpedFloat.Chaser; -import com.simibubi.create.foundation.utility.NBTHelper; -import com.simibubi.create.foundation.utility.VecHelper; - +import com.simibubi.create.foundation.utility.*; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; @@ -49,6 +34,7 @@ import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.ITextComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; @@ -64,7 +50,10 @@ import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.wrapper.CombinedInvWrapper; -public class BasinTileEntity extends SmartTileEntity { +import javax.annotation.Nonnull; +import java.util.*; + +public class BasinTileEntity extends SmartTileEntity implements IHaveGoggleInformation { private boolean areFluidsMoving; LerpedFloat ingredientRotationSpeed; @@ -438,7 +427,7 @@ public class BasinTileEntity extends SmartTileEntity { for (ItemStack itemStack : outputItems) { // Catalyst items are never consumed if (itemStack.hasContainerItem() && itemStack.getContainerItem() - .isItemEqual(itemStack)) + .isItemEqual(itemStack)) continue; if (simulate || direction == Direction.DOWN) { @@ -601,6 +590,12 @@ public class BasinTileEntity extends SmartTileEntity { return areFluidsMoving; } + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + return containedFluidTooltip(tooltip, isPlayerSneaking, + getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); + } + class BasinValueBox extends ValueBoxTransform.Sided { @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingInventory.java b/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingInventory.java index 4e2a4d77f..b45c57411 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingInventory.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingInventory.java @@ -1,11 +1,11 @@ package com.simibubi.create.content.contraptions.processing; -import java.util.function.Consumer; - import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraftforge.items.ItemStackHandler; +import java.util.function.Consumer; + public class ProcessingInventory extends ItemStackHandler { public float remainingTime; public float recipeDuration; @@ -55,6 +55,8 @@ public class ProcessingInventory extends ItemStackHandler { recipeDuration = nbt.getFloat("RecipeTime"); appliedRecipe = nbt.getBoolean("AppliedRecipe"); super.deserializeNBT(nbt); + if(isEmpty()) + appliedRecipe = false; } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingRecipe.java index 5f928b1db..791f80266 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingRecipe.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingRecipe.java @@ -1,20 +1,11 @@ package com.simibubi.create.content.contraptions.processing; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import javax.annotation.ParametersAreNonnullByDefault; - -import org.apache.logging.log4j.Logger; - import com.google.gson.JsonObject; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; import com.simibubi.create.foundation.fluid.FluidIngredient; import com.simibubi.create.foundation.utility.Lang; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; @@ -26,6 +17,12 @@ import net.minecraft.network.PacketBuffer; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fluids.FluidStack; +import org.apache.logging.log4j.Logger; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault @@ -180,6 +177,11 @@ public abstract class ProcessingRecipe implements IRecipe< public ResourceLocation getId() { return id; } + + @Override + public boolean isDynamic() { + return true; + } @Override public IRecipeSerializer getSerializer() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java index a2b7abd5c..bbf74d0f9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java @@ -7,7 +7,6 @@ import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; @@ -27,7 +26,7 @@ public class BlazeBurnerRenderer extends SafeTileEntityRenderer PART = EnumProperty.create("part", Part.class); @@ -73,7 +72,7 @@ public class GantryShaftBlock extends DirectionalKineticBlock { if (!placementHelper.matchesItem(heldItem)) return ActionResultType.PASS; - return placementHelper.getOffset(world, state, pos, ray).placeInWorld(world, ((BlockItem) heldItem.getItem()), player, hand, ray); + return placementHelper.getOffset(player, world, state, pos, ray).placeInWorld(world, ((BlockItem) heldItem.getItem()), player, hand, ray); } @Override @@ -259,6 +258,16 @@ public class GantryShaftBlock extends DirectionalKineticBlock { return super.areStatesKineticallyEquivalent(oldState, newState) && oldState.get(POWERED) == newState.get(POWERED); } + + @Override + public float getParticleTargetRadius() { + return .35f; + } + + @Override + public float getParticleInitialRadius() { + return .25f; + } public static class PlacementHelper extends PoleHelper { @@ -273,12 +282,10 @@ public class GantryShaftBlock extends DirectionalKineticBlock { } @Override - public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { - PlacementOffset offset = super.getOffset(world, state, pos, ray); - if (!offset.isSuccessful()) - return offset; - return PlacementOffset.success(offset.getPos(), offset.getTransform() - .andThen(s -> s.with(POWERED, state.get(POWERED)))); + public PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + PlacementOffset offset = super.getOffset(player, world, state, pos, ray); + offset.withTransform(offset.getTransform().andThen(s -> s.with(POWERED, state.get(POWERED)))); + return offset; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftTileEntity.java index 338123dc8..b54685651 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftTileEntity.java @@ -2,10 +2,9 @@ package com.simibubi.create.content.contraptions.relays.advanced; import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryPinionBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryPinionTileEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageTileEntity; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; @@ -31,13 +30,13 @@ public class GantryShaftTileEntity extends KineticTileEntity { continue; BlockPos offset = pos.offset(d); BlockState pinionState = world.getBlockState(offset); - if (!AllBlocks.GANTRY_PINION.has(pinionState)) + if (!AllBlocks.GANTRY_CARRIAGE.has(pinionState)) continue; - if (pinionState.get(GantryPinionBlock.FACING) != d) + if (pinionState.get(GantryCarriageBlock.FACING) != d) continue; TileEntity tileEntity = world.getTileEntity(offset); - if (tileEntity instanceof GantryPinionTileEntity) - ((GantryPinionTileEntity) tileEntity).queueAssembly(); + if (tileEntity instanceof GantryCarriageTileEntity) + ((GantryCarriageTileEntity) tileEntity).queueAssembly(); } } @@ -52,24 +51,24 @@ public class GantryShaftTileEntity extends KineticTileEntity { return defaultModifier; if (!stateFrom.get(GantryShaftBlock.POWERED)) return defaultModifier; - if (!AllBlocks.GANTRY_PINION.has(stateTo)) + if (!AllBlocks.GANTRY_CARRIAGE.has(stateTo)) return defaultModifier; Direction direction = Direction.getFacingFromVector(diff.getX(), diff.getY(), diff.getZ()); - if (stateTo.get(GantryPinionBlock.FACING) != direction) + if (stateTo.get(GantryCarriageBlock.FACING) != direction) return defaultModifier; - return GantryPinionTileEntity.getGantryPinionModifier(stateFrom.get(GantryShaftBlock.FACING), - stateTo.get(GantryPinionBlock.FACING)); + return GantryCarriageTileEntity.getGantryPinionModifier(stateFrom.get(GantryShaftBlock.FACING), + stateTo.get(GantryCarriageBlock.FACING)); } @Override public boolean isCustomConnection(KineticTileEntity other, BlockState state, BlockState otherState) { - if (!AllBlocks.GANTRY_PINION.has(otherState)) + if (!AllBlocks.GANTRY_CARRIAGE.has(otherState)) return false; final BlockPos diff = other.getPos() .subtract(pos); Direction direction = Direction.getFacingFromVector(diff.getX(), diff.getY(), diff.getZ()); - return otherState.get(GantryPinionBlock.FACING) == direction; + return otherState.get(GantryCarriageBlock.FACING) == direction; } public boolean canAssembleOn() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java index 1d39ccbd5..90d8667f6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.contraptions.relays.advanced; -import java.util.function.Predicate; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; @@ -12,7 +10,6 @@ import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import com.simibubi.create.foundation.utility.placement.PlacementOffset; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -31,6 +28,8 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import java.util.function.Predicate; + public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements ITE { private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); @@ -69,7 +68,7 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements ItemStack heldItem = player.getHeldItem(hand); IPlacementHelper helper = PlacementHelpers.get(placementHelperId); if (helper.matchesItem(heldItem)) - return helper.getOffset(world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + return helper.getOffset(player, world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); return ActionResultType.PASS; } @@ -92,7 +91,7 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements } @Override - public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + public PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { BlockPos newPos = pos.up(); if (!world.getBlockState(newPos) .getMaterial() @@ -107,15 +106,6 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements return PlacementOffset.success(newPos, s -> s.with(CogWheelBlock.AXIS, newAxis)); } - - @Override - public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) { - //IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), - // Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, - // state.get(HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X)); - - displayGhost(offset); - } } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java index f4e324071..8dc0407a4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java @@ -8,7 +8,6 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -41,11 +40,12 @@ public class SpeedControllerRenderer extends SmartTileEntityRenderer instructions; @@ -151,6 +150,8 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { @Override public float getRotationSpeedModifier(Direction face) { + if (isVirtual()) + return 1; return (!hasSource() || face == getSourceFacing()) ? 1 : getModifier(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltData.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltData.java index 9f6db3daf..25cb9e3ac 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltData.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltData.java @@ -1,14 +1,14 @@ package com.simibubi.create.content.contraptions.relays.belt; -import java.nio.ByteBuffer; - import com.simibubi.create.content.contraptions.base.KineticData; import com.simibubi.create.content.contraptions.base.KineticVertexAttributes; import com.simibubi.create.foundation.block.render.SpriteShiftEntry; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; - import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.math.vector.Quaternion; + +import java.nio.ByteBuffer; public class BeltData extends KineticData { public static VertexFormat FORMAT = VertexFormat.builder() @@ -16,9 +16,10 @@ public class BeltData extends KineticData { .addAttributes(BeltVertexAttributes.class) .build(); - private float rotX; - private float rotY; - private float rotZ; + private float qX; + private float qY; + private float qZ; + private float qW; private float sourceU; private float sourceV; private float minU; @@ -31,10 +32,11 @@ public class BeltData extends KineticData { super(owner); } - public BeltData setRotation(float rotX, float rotY, float rotZ) { - this.rotX = rotX; - this.rotY = rotY; - this.rotZ = rotZ; + public BeltData setRotation(Quaternion q) { + this.qX = q.getX(); + this.qY = q.getY(); + this.qZ = q.getZ(); + this.qW = q.getW(); return this; } @@ -61,7 +63,7 @@ public class BeltData extends KineticData { public void write(ByteBuffer buf) { super.write(buf); - putVec3(buf, rotX, rotY, rotZ); + putVec4(buf, qX, qY, qZ, qW); putVec2(buf, sourceU, sourceV); putVec4(buf, minU, minV, maxU, maxV); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java index 7b8c7997a..90e118f75 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java @@ -1,9 +1,5 @@ package com.simibubi.create.content.contraptions.relays.belt; -import java.util.ArrayList; -import java.util.function.Consumer; -import java.util.function.Supplier; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; @@ -12,24 +8,18 @@ import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.foundation.block.render.SpriteShiftEntry; import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.MatrixStacker; - import net.minecraft.item.DyeColor; -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Quaternion; import net.minecraft.world.LightType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; + +import java.util.ArrayList; +import java.util.function.Supplier; public class BeltInstance extends KineticTileInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, BeltInstance::new)); - } private boolean upward; private boolean diagonal; @@ -72,9 +62,8 @@ public class BeltInstance extends KineticTileInstance { SpriteShiftEntry spriteShift = BeltRenderer.getSpriteShiftEntry(color, diagonal, bottom); InstancedModel beltModel = beltPartial.renderOnBelt(modelManager, lastState); - Consumer setupFunc = setupFunc(bottom, spriteShift); - keys.add(beltModel.setupInstance(setupFunc)); + keys.add(setup(beltModel.createInstance(), bottom, spriteShift)); if (diagonal) break; } @@ -82,7 +71,7 @@ public class BeltInstance extends KineticTileInstance { if (tile.hasPulley()) { InstancedModel pulleyModel = getPulleyModel(); - pulleyKey = pulleyModel.setupInstance(setupFunc(tile.getSpeed(), getRotationAxis())); + pulleyKey = setup(pulleyModel.createInstance(), tile.getSpeed(), getRotationAxis()); } } @@ -94,9 +83,10 @@ public class BeltInstance extends KineticTileInstance { for (InstanceKey key : keys) { SpriteShiftEntry spriteShiftEntry = BeltRenderer.getSpriteShiftEntry(color, diagonal, bottom); - key.modifyInstance(data -> data.setScrollTexture(spriteShiftEntry) - .setColor(tile.network) - .setRotationalSpeed(getScrollSpeed())); + key.getInstance() + .setScrollTexture(spriteShiftEntry) + .setColor(tile.network) + .setRotationalSpeed(getScrollSpeed()); bottom = false; } @@ -107,11 +97,9 @@ public class BeltInstance extends KineticTileInstance { @Override public void updateLight() { - for (InstanceKey key : keys) { - key.modifyInstance(this::relight); - } + relight(pos, keys.stream().map(InstanceKey::getInstance)); - if (pulleyKey != null) pulleyKey.modifyInstance(this::relight); + if (pulleyKey != null) relight(pos, pulleyKey.getInstance()); } @Override @@ -125,10 +113,10 @@ public class BeltInstance extends KineticTileInstance { private float getScrollSpeed() { float speed = tile.getSpeed(); if (((facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ^ upward) ^ - ((alongX && !diagonal) || (alongZ && diagonal)) ^ (vertical && facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE)) { + ((alongX && !diagonal) || (alongZ && diagonal))) { speed = -speed; } - if (sideways && (facing == Direction.SOUTH || facing == Direction.WEST)) + if (sideways && (facing == Direction.SOUTH || facing == Direction.WEST) || (vertical && facing == Direction.EAST)) speed = -speed; return speed; @@ -165,22 +153,25 @@ public class BeltInstance extends KineticTileInstance { return dir; } - private Consumer setupFunc(boolean bottom, SpriteShiftEntry spriteShift) { - return data -> { - float rotX = (!diagonal && beltSlope != BeltSlope.HORIZONTAL ? 90 : 0) + (beltSlope == BeltSlope.DOWNWARD ? 180 : 0); - float rotY = facing.getHorizontalAngle() + (upward ? 180 : 0) + (sideways ? 90 : 0); - float rotZ = sideways ? 90 : ((vertical && facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ? 180 : 0); + private InstanceKey setup(InstanceKey key, boolean bottom, SpriteShiftEntry spriteShift) { + boolean downward = beltSlope == BeltSlope.DOWNWARD; + float rotX = (!diagonal && beltSlope != BeltSlope.HORIZONTAL ? 90 : 0) + (downward ? 180 : 0) + (sideways ? 90 : 0) + (vertical && alongZ ? 180 : 0); + float rotY = facing.getHorizontalAngle() + ((diagonal ^ alongX) && !downward ? 180 : 0) + (sideways && alongZ ? 180 : 0) + (vertical && alongX ? 90 : 0); + float rotZ = (sideways ? 90 : 0) + (vertical && alongX ? 90 : 0); - BlockPos pos = tile.getPos(); - data.setTileEntity(tile) - .setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) - .setSkyLight(world.getLightLevel(LightType.SKY, pos)) - .setRotation(rotX, rotY, rotZ) - .setRotationalSpeed(getScrollSpeed()) - .setRotationOffset(bottom ? 0.5f : 0f) - .setScrollTexture(spriteShift) - .setScrollMult(diagonal ? 3f / 8f : 0.5f); - }; + Quaternion q = new Quaternion(rotX, rotY, rotZ, true); + + key.getInstance() + .setTileEntity(tile) + .setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) + .setSkyLight(world.getLightLevel(LightType.SKY, pos)) + .setRotation(q) + .setRotationalSpeed(getScrollSpeed()) + .setRotationOffset(bottom ? 0.5f : 0f) + .setScrollTexture(spriteShift) + .setScrollMult(diagonal ? 3f / 8f : 0.5f); + + return key; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java index ea662764d..75388e44a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.contraptions.relays.belt; -import java.util.Random; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; @@ -19,7 +17,7 @@ import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.MatrixStacker; - +import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -38,6 +36,8 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3f; import net.minecraft.util.math.vector.Vector3i; +import java.util.Random; + public class BeltRenderer extends SafeTileEntityRenderer { public BeltRenderer(TileEntityRendererDispatcher dispatcher) { @@ -46,7 +46,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { @Override public boolean isGlobalRenderer(BeltTileEntity te) { - return BeltBlock.canTransportObjects(te.getBlockState()); + return te.isController(); } @Override @@ -71,11 +71,11 @@ public class BeltRenderer extends SafeTileEntityRenderer { boolean sideways = beltSlope == BeltSlope.SIDEWAYS; boolean alongX = facing.getAxis() == Axis.X; - MatrixStacker msr = MatrixStacker.of(ms); + MatrixStack localTransforms = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(localTransforms); IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid()); - float renderTick = AnimationTickHolder.getRenderTick(); + float renderTick = AnimationTickHolder.getRenderTime(te.getWorld()); - ms.push(); msr.centre(); msr.rotateY(AngleHelper.horizontalAngle(facing) + (upward ? 180 : 0) + (sideways ? 270 : 0)); msr.rotateZ(sideways ? 90 : 0); @@ -110,19 +110,20 @@ public class BeltRenderer extends SafeTileEntityRenderer { float spriteSize = spriteShift.getTarget().getMaxV() - spriteShift.getTarget().getMinV(); - double scroll = speed * time / (36 * 16) + (bottom ? 0.5 : 0.0); + double scroll = speed * time / (31.5 * 16) + (bottom ? 0.5 : 0.0); scroll = scroll - Math.floor(scroll); scroll = scroll * spriteSize * scrollMult; beltBuffer.shiftUVScrolling(spriteShift, (float) scroll); } - beltBuffer.renderInto(ms, vb); + beltBuffer + .transform(localTransforms) + .renderInto(ms, vb); // Diagonal belt do not have a separate bottom model if (diagonal) break; } - ms.pop(); if (te.hasPulley()) { // TODO 1.15 find a way to cache this model matrix computation @@ -190,6 +191,8 @@ public class BeltRenderer extends SafeTileEntityRenderer { boolean slopeAlongX = beltFacing .getAxis() == Axis.X; + boolean onContraption = te.getWorld() instanceof WrappedWorld; + for (TransportedItemStack transported : te.getInventory() .getTransportedItems()) { ms.push(); @@ -204,7 +207,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { sideOffset = transported.sideOffset; } - int stackLight = getPackedLight(te, offset); + int stackLight = onContraption ? light : getPackedLight(te, offset); if (offset < .5) verticalMovement = 0; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java index 5b834bed2..59af9d694 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java @@ -1,34 +1,18 @@ package com.simibubi.create.content.contraptions.relays.belt; -import static com.simibubi.create.content.contraptions.relays.belt.BeltPart.MIDDLE; -import static com.simibubi.create.content.contraptions.relays.belt.BeltSlope.HORIZONTAL; -import static net.minecraft.util.Direction.AxisDirection.NEGATIVE; -import static net.minecraft.util.Direction.AxisDirection.POSITIVE; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.IRotate; import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltInventory; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler; +import com.simibubi.create.content.contraptions.relays.belt.transport.*; import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler.TransportedEntityInfo; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler; -import com.simibubi.create.content.contraptions.relays.belt.transport.ItemHandlerBeltSegment; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.backend.light.ILightListener; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; import com.simibubi.create.foundation.utility.NBTHelper; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; @@ -56,7 +40,15 @@ import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; -public class BeltTileEntity extends KineticTileEntity { +import java.util.*; +import java.util.function.Function; + +import static com.simibubi.create.content.contraptions.relays.belt.BeltPart.MIDDLE; +import static com.simibubi.create.content.contraptions.relays.belt.BeltSlope.HORIZONTAL; +import static net.minecraft.util.Direction.AxisDirection.NEGATIVE; +import static net.minecraft.util.Direction.AxisDirection.POSITIVE; + +public class BeltTileEntity extends KineticTileEntity implements ILightListener { public Map passengers; public Optional color; @@ -510,7 +502,6 @@ public class BeltTileEntity extends KineticTileEntity { @Override public void onChunkLightUpdate() { - super.onChunkLightUpdate(); updateLight(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltVertexAttributes.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltVertexAttributes.java index ca2125848..b5888c49b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltVertexAttributes.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltVertexAttributes.java @@ -1,11 +1,12 @@ package com.simibubi.create.content.contraptions.relays.belt; import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IAttribSpec; import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; public enum BeltVertexAttributes implements IVertexAttrib { - INSTANCE_ROTATION("aInstanceRot", CommonAttributes.VEC3), + INSTANCE_ROTATION("aInstanceRot", CommonAttributes.QUATERNION), SOURCE_TEX("aSourceTexture", CommonAttributes.UV), SCROLL_TEX("aScrollTexture", CommonAttributes.VEC4), SCROLL_MULT("aScrollMult", CommonAttributes.NORMALIZED_BYTE), @@ -25,7 +26,7 @@ public enum BeltVertexAttributes implements IVertexAttrib { } @Override - public VertexAttribSpec attribSpec() { + public IAttribSpec attribSpec() { return spec; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java index 38849fa78..a29a48828 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java @@ -6,8 +6,6 @@ import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape; import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; -import com.simibubi.create.foundation.utility.BlockHelper; - import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; @@ -98,6 +96,7 @@ public class BeltFunnelInteractionHandler { remainder = ItemHandlerHelper.copyStackWithSize(currentItem.stack, notFilled); funnelTE.flap(true); + funnelTE.onTransfer(toInsert); currentItem.stack = remainder; beltInventory.belt.sendData(); if (blocking) diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java index a063473c4..956f0bc12 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java @@ -1,13 +1,5 @@ package com.simibubi.create.content.contraptions.relays.belt.transport; -import static com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler.flapTunnel; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.Function; - import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; @@ -20,7 +12,6 @@ import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemS import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; @@ -31,6 +22,14 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants.NBT; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Function; + +import static com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler.flapTunnel; + public class BeltInventory { final BeltTileEntity belt; @@ -82,7 +81,7 @@ public class BeltInventory { .get(BeltBlock.SLOPE) == BeltSlope.HORIZONTAL; float spacing = 1; World world = belt.getWorld(); - boolean onClient = world.isRemote; + boolean onClient = world.isRemote && !belt.isVirtual(); // resolve ending only when items will reach it this tick Ending ending = Ending.UNRESOLVED; @@ -105,7 +104,7 @@ public class BeltInventory { movement *= ServerSpeedProvider.get(); // Don't move if held by processing (client) - if (onClient && currentItem.locked) + if (world.isRemote && currentItem.locked) continue; // Don't move if other items are waiting in front @@ -436,5 +435,5 @@ public class BeltInventory { public List getTransportedItems() { return items; } - + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java index 81ea8fc27..a576ecb45 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java @@ -1,18 +1,11 @@ package com.simibubi.create.content.contraptions.relays.belt.transport; -import static net.minecraft.entity.MoverType.SELF; -import static net.minecraft.util.Direction.AxisDirection.NEGATIVE; -import static net.minecraft.util.Direction.AxisDirection.POSITIVE; - -import java.util.List; - import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; import com.simibubi.create.content.contraptions.relays.belt.BeltPart; import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; - import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; @@ -30,6 +23,12 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3i; import net.minecraft.world.World; +import java.util.List; + +import static net.minecraft.entity.MoverType.SELF; +import static net.minecraft.util.Direction.AxisDirection.NEGATIVE; +import static net.minecraft.util.Direction.AxisDirection.POSITIVE; + public class BeltMovementHandler { public static class TransportedEntityInfo { @@ -137,13 +136,13 @@ public class BeltMovementHandler { if (movingDown) movement = movement.add(0, -Math.abs(axis.getCoordinate(movement.x, movement.y, movement.z)), 0); - Vector3d centering = Vector3d.of(centeringDirection) - .scale(diffCenter * Math.min(Math.abs(movementSpeed), .1f) * 4); - movement = movement.add(centering); - + Vector3d centering = Vector3d.of(centeringDirection).scale(diffCenter * Math.min(Math.abs(movementSpeed), .1f) * 4); float step = entityIn.stepHeight; - if (!isPlayer) + + if (!isPlayer) { + movement = movement.add(centering); entityIn.stepHeight = 1; + } // Entity Collisions if (Math.abs(movementSpeed) < .5f) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java index 7e23d2129..b786fc9c7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java @@ -1,10 +1,5 @@ package com.simibubi.create.content.contraptions.relays.elementary; -import static com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock.AXIS; - -import java.util.List; -import java.util.function.Predicate; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; @@ -15,7 +10,6 @@ import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import com.simibubi.create.foundation.utility.placement.PlacementOffset; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -31,6 +25,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.World; +import java.util.List; +import java.util.function.Predicate; + +import static com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock.AXIS; + public class CogwheelBlockItem extends BlockItem { boolean large; @@ -56,14 +55,14 @@ public class CogwheelBlockItem extends BlockItem { PlayerEntity player = context.getPlayer(); BlockRayTraceResult ray = new BlockRayTraceResult(context.getHitVec(), context.getFace(), pos, true); if (helper.matchesState(state) && player != null && !player.isSneaking()) { - return helper.getOffset(world, state, pos, ray).placeInWorld(world, this, player, context.getHand(), ray); + return helper.getOffset(player, world, state, pos, ray).placeInWorld(world, this, player, context.getHand(), ray); } if (integratedCogHelperId != -1) { helper = PlacementHelpers.get(integratedCogHelperId); if (helper.matchesState(state) && player != null && !player.isSneaking()) { - return helper.getOffset(world, state, pos, ray).placeInWorld(world, this, player, context.getHand(), ray); + return helper.getOffset(player, world, state, pos, ray).placeInWorld(world, this, player, context.getHand(), ray); } } @@ -119,7 +118,7 @@ public class CogwheelBlockItem extends BlockItem { } @Override - public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + public PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { if (hitOnShaft(state, ray)) return PlacementOffset.fail(); @@ -145,16 +144,7 @@ public class CogwheelBlockItem extends BlockItem { return PlacementOffset.fail(); } - return super.getOffset(world, state, pos, ray); - } - - @Override - public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) { - //IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), - // Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)), - // ((CogWheelBlock) state.getBlock()).isLarge ? 1.5D : 0.75D); - - displayGhost(offset); + return super.getOffset(player, world, state, pos, ray); } } @@ -167,7 +157,7 @@ public class CogwheelBlockItem extends BlockItem { } @Override - public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + public PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { if (hitOnShaft(state, ray)) return PlacementOffset.fail(); @@ -190,7 +180,7 @@ public class CogwheelBlockItem extends BlockItem { return PlacementOffset.fail(); } - return super.getOffset(world, state, pos, ray); + return super.getOffset(player, world, state, pos, ray); } } @@ -203,7 +193,7 @@ public class CogwheelBlockItem extends BlockItem { } @Override - public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + public PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { // diagonal gears of different size Direction closest = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getHitVec(), state.get(AXIS)) .get(0); @@ -227,14 +217,6 @@ public class CogwheelBlockItem extends BlockItem { return PlacementOffset.fail(); } - @Override - public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) { - //IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), - // Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(AXIS)), 1D); - - displayGhost(offset); - } - protected boolean hitOnShaft(BlockState state, BlockRayTraceResult ray) { return AllShapes.SIX_VOXEL_POLE.get(state.get(AXIS)) .getBoundingBox() @@ -284,7 +266,7 @@ public class CogwheelBlockItem extends BlockItem { } @Override - public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + public PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { Direction face = ray.getFace(); Axis newAxis; @@ -321,15 +303,5 @@ public class CogwheelBlockItem extends BlockItem { return PlacementOffset.fail(); } - - @Override - public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) { - //IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), - // Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, offset.getTransform() - // .apply(AllBlocks.LARGE_COGWHEEL.getDefaultState()) - // .get(AXIS))); - - displayGhost(offset); - } } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java index 3b0bb2e8d..56cb322ad 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.contraptions.relays.elementary; -import java.util.function.Predicate; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.content.contraptions.base.KineticTileEntity; @@ -10,7 +8,6 @@ import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import com.simibubi.create.foundation.utility.placement.util.PoleHelper; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -26,6 +23,8 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import java.util.function.Predicate; + public class ShaftBlock extends AbstractShaftBlock { private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); @@ -45,12 +44,12 @@ public class ShaftBlock extends AbstractShaftBlock { @Override public float getParticleTargetRadius() { - return .25f; + return .35f; } @Override public float getParticleInitialRadius() { - return 0f; + return .125f; } @Override @@ -78,7 +77,7 @@ public class ShaftBlock extends AbstractShaftBlock { IPlacementHelper helper = PlacementHelpers.get(placementHelperId); if (helper.matchesItem(heldItem)) - return helper.getOffset(world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + return helper.getOffset(player, world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); return ActionResultType.PASS; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java index a1b4de97b..aa3350ca9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java @@ -1,7 +1,6 @@ package com.simibubi.create.content.contraptions.relays.encased; import com.simibubi.create.content.contraptions.base.KineticTileEntity; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; @@ -50,6 +49,8 @@ public class AdjustablePulleyTileEntity extends KineticTileEntity { @Override public void tick() { super.tick(); + if (world.isRemote) + return; if (signalChanged) { signalChanged = false; analogSignalChanged(world.getRedstonePowerFromNeighbors(pos)); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java index 3dd04f582..c8e8de375 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java @@ -2,22 +2,12 @@ package com.simibubi.create.content.contraptions.relays.encased; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; - import net.minecraft.block.BlockState; -import net.minecraft.tileentity.TileEntityType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; public class ShaftInstance extends SingleRotatingInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, ShaftInstance::new)); - } - - public ShaftInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + public ShaftInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { super(dispatcher, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java index 1ac7476bb..4e6285722 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java @@ -1,32 +1,24 @@ package com.simibubi.create.content.contraptions.relays.encased; -import java.util.ArrayList; - import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.IRotate; +import com.simibubi.create.content.contraptions.base.KineticData; import com.simibubi.create.content.contraptions.base.KineticTileInstance; import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.block.Block; -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; + +import java.util.ArrayList; public class SplitShaftInstance extends KineticTileInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, SplitShaftInstance::new)); - } protected ArrayList> keys; - public SplitShaftInstance(InstancedTileRenderer modelManager, SplitShaftTileEntity tile) { + public SplitShaftInstance(InstancedTileRenderer modelManager, SplitShaftTileEntity tile) { super(modelManager, tile); } @@ -45,7 +37,7 @@ public class SplitShaftInstance extends KineticTileInstance key : keys) { - key.modifyInstance(this::relight); - } + keys.forEach(key -> relight(pos, ((InstanceKey>) key).getInstance())); } @Override @@ -75,13 +65,12 @@ public class SplitShaftInstance extends KineticTileInstance key, Direction dir) { - key.modifyInstance(data -> { - Direction.Axis axis = dir.getAxis(); + Direction.Axis axis = dir.getAxis(); - data.setColor(tile.network) - .setRotationalSpeed(tile.getSpeed() * tile.getRotationSpeedModifier(dir)) - .setRotationOffset(getRotationOffset(axis)) - .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()); - }); + key.getInstance() + .setColor(tile.network) + .setRotationalSpeed(tile.getSpeed() * tile.getRotationSpeedModifier(dir)) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java index 8aca8cccd..3b3980a5d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java @@ -9,7 +9,6 @@ import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.block.Block; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -32,7 +31,7 @@ public class SplitShaftRenderer extends KineticTileEntityRenderer { Block block = te.getBlockState().getBlock(); final Axis boxAxis = ((IRotate) block).getRotationAxis(te.getBlockState()); final BlockPos pos = te.getPos(); - float time = AnimationTickHolder.getRenderTick(); + float time = AnimationTickHolder.getRenderTime(te.getWorld()); for (Direction direction : Iterate.directions) { Axis axis = direction.getAxis(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeInstance.java new file mode 100644 index 000000000..625f3daa6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeInstance.java @@ -0,0 +1,176 @@ +package com.simibubi.create.content.contraptions.relays.gauge; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.Couple; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.util.Direction; +import net.minecraft.util.math.MathHelper; + +import java.util.ArrayList; + +public abstract class GaugeInstance extends ShaftInstance implements ITickableInstance { + + protected ArrayList faces; + + protected MatrixStack ms; + + protected GaugeInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + super(dispatcher, tile); + } + + @Override + protected void init() { + super.init(); + + faces = new ArrayList<>(2); + + GaugeTileEntity gaugeTile = (GaugeTileEntity) tile; + GaugeBlock gaugeBlock = (GaugeBlock) lastState.getBlock(); + + InstancedModel dialModel = modelManager.getMaterial(RenderMaterials.MODELS).getModel(AllBlockPartials.GAUGE_DIAL, lastState); + InstancedModel headModel = getHeadModel(); + + ms = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(ms); + msr.translate(getFloatingPos()); + + float progress = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), gaugeTile.prevDialState, gaugeTile.dialState); + + for (Direction facing : Iterate.directions) { + if (!gaugeBlock.shouldRenderHeadOnFace(world, pos, lastState, facing)) + continue; + + DialFace face = makeFace(facing, dialModel, headModel); + + faces.add(face); + + face.setupTransform(msr, progress); + } + + updateLight(); + } + + private DialFace makeFace(Direction face, InstancedModel dialModel, InstancedModel headModel) { + return new DialFace(face, dialModel.createInstance(), headModel.createInstance()); + } + + @Override + public void tick() { + GaugeTileEntity gaugeTile = (GaugeTileEntity) tile; + + if (MathHelper.epsilonEquals(gaugeTile.prevDialState, gaugeTile.dialState)) + return; + + float progress = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), gaugeTile.prevDialState, gaugeTile.dialState); + + MatrixStacker msr = MatrixStacker.of(ms); + + for (DialFace faceEntry : faces) { + faceEntry.updateTransform(msr, progress); + } + } + + @Override + public void updateLight() { + super.updateLight(); + + relight(pos, faces.stream() + .flatMap(Couple::stream) + .map(InstanceKey::getInstance)); + } + + @Override + public void remove() { + super.remove(); + + faces.forEach(DialFace::delete); + } + + protected abstract InstancedModel getHeadModel(); + + private class DialFace extends Couple> { + + Direction face; + + public DialFace(Direction face, InstanceKey first, InstanceKey second) { + super(first, second); + this.face = face; + } + + private void setupTransform(MatrixStacker msr, float progress) { + float dialPivot = 5.75f / 16; + + ms.push(); + rotateToFace(msr); + + getSecond().getInstance().setTransform(ms); + + msr.translate(0, dialPivot, dialPivot) + .rotate(Direction.EAST, (float) (Math.PI / 2 * -progress)) + .translate(0, -dialPivot, -dialPivot); + + getFirst().getInstance().setTransform(ms); + + ms.pop(); + } + + private void updateTransform(MatrixStacker msr, float progress) { + float dialPivot = 5.75f / 16; + + ms.push(); + + rotateToFace(msr) + .translate(0, dialPivot, dialPivot) + .rotate(Direction.EAST, (float) (Math.PI / 2 * -progress)) + .translate(0, -dialPivot, -dialPivot); + + getFirst().getInstance().setTransform(ms); + + ms.pop(); + } + + protected MatrixStacker rotateToFace(MatrixStacker msr) { + return msr.centre() + .rotate(Direction.UP, (float) ((-face.getHorizontalAngle() - 90) / 180 * Math.PI)) + .unCentre(); + } + + private void delete() { + getFirst().delete(); + getSecond().delete(); + } + } + + public static class Speed extends GaugeInstance { + public Speed(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + super(dispatcher, tile); + } + + @Override + protected InstancedModel getHeadModel() { + return modelManager.getMaterial(RenderMaterials.MODELS).getModel(AllBlockPartials.GAUGE_HEAD_SPEED, lastState); + } + } + + public static class Stress extends GaugeInstance { + public Stress(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + super(dispatcher, tile); + } + + @Override + protected InstancedModel getHeadModel() { + return modelManager.getMaterial(RenderMaterials.MODELS).getModel(AllBlockPartials.GAUGE_HEAD_STRESS, lastState); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java index 3085dae58..232b18d1c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java @@ -7,8 +7,8 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.relays.gauge.GaugeBlock.Type; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -37,6 +37,8 @@ public class GaugeRenderer extends KineticTileEntityRenderer { @Override protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + if (FastRenderDispatcher.available(te.getWorld())) return; + super.renderSafe(te, partialTicks, ms, buffer, light, overlay); BlockState gaugeState = te.getBlockState(); GaugeTileEntity gaugeTE = (GaugeTileEntity) te; @@ -47,14 +49,14 @@ public class GaugeRenderer extends KineticTileEntityRenderer { .renderOn(gaugeState); SuperByteBuffer dialBuffer = AllBlockPartials.GAUGE_DIAL.renderOn(gaugeState); + float dialPivot = 5.75f / 16; + float progress = MathHelper.lerp(partialTicks, gaugeTE.prevDialState, gaugeTE.dialState); + for (Direction facing : Iterate.directions) { if (!((GaugeBlock) gaugeState.getBlock()).shouldRenderHeadOnFace(te.getWorld(), te.getPos(), gaugeState, facing)) continue; - float dialPivot = 5.75f / 16; - float progress = MathHelper.lerp(partialTicks, gaugeTE.prevDialState, gaugeTE.dialState); - IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid()); rotateBufferTowards(dialBuffer, facing).translate(0, dialPivot, dialPivot) .rotate(Direction.EAST, (float) (Math.PI / 2 * -progress)) diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java index a6c0aa405..9d5d33db3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java @@ -1,20 +1,19 @@ package com.simibubi.create.content.contraptions.relays.gauge; -import java.util.List; - import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; import com.simibubi.create.content.contraptions.goggles.GogglesItem; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.Lang; - import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextFormatting; -public class SpeedGaugeTileEntity extends GaugeTileEntity{ +import java.util.List; + +public class SpeedGaugeTileEntity extends GaugeTileEntity { public SpeedGaugeTileEntity(TileEntityType type) { super(type); @@ -24,28 +23,37 @@ public class SpeedGaugeTileEntity extends GaugeTileEntity{ public void onSpeedChanged(float prevSpeed) { super.onSpeedChanged(prevSpeed); float speed = Math.abs(getSpeed()); - float medium = AllConfigs.SERVER.kinetics.mediumSpeed.get().floatValue(); - float fast = AllConfigs.SERVER.kinetics.fastSpeed.get().floatValue(); - float max = AllConfigs.SERVER.kinetics.maxRotationSpeed.get().floatValue(); - color = ColorHelper.mixColors(SpeedLevel.of(speed).getColor(), 0xffffff, .25f); + color = speed == 0 ? 0x333333 + : ColorHelper.mixColors(SpeedLevel.of(speed) + .getColor(), 0xffffff, .25f); if (speed == 69) - AllTriggers.triggerForNearbyPlayers(AllTriggers.SPEED_READ, world, pos, 6, - GogglesItem::canSeeParticles); - if (speed == 0) { - dialTarget = 0; - color = 0x333333; - } else if (speed < medium) { - dialTarget = MathHelper.lerp(speed / medium, 0, .45f); - } else if (speed < fast) { - dialTarget = MathHelper.lerp((speed - medium) / (fast - medium), .45f, .75f); - } else { - dialTarget = MathHelper.lerp((speed - fast) / (max - fast), .75f, 1.125f); - } - + AllTriggers.triggerForNearbyPlayers(AllTriggers.SPEED_READ, world, pos, 6, GogglesItem::canSeeParticles); + + dialTarget = getDialTarget(speed); markDirty(); } + public static float getDialTarget(float speed) { + speed = Math.abs(speed); + float medium = AllConfigs.SERVER.kinetics.mediumSpeed.get() + .floatValue(); + float fast = AllConfigs.SERVER.kinetics.fastSpeed.get() + .floatValue(); + float max = AllConfigs.SERVER.kinetics.maxRotationSpeed.get() + .floatValue(); + float target = 0; + if (speed == 0) + target = 0; + else if (speed < medium) + target = MathHelper.lerp(speed / medium, 0, .45f); + else if (speed < fast) + target = MathHelper.lerp((speed - medium) / (fast - medium), .45f, .75f); + else + target = MathHelper.lerp((speed - fast) / (max - fast), .75f, 1.125f); + return target; + } + @Override public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { super.addToGoggleTooltip(tooltip, isPlayerSneaking); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java index 1d597f8ec..e0c10fe92 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java @@ -1,35 +1,26 @@ package com.simibubi.create.content.contraptions.relays.gearbox; -import java.util.EnumMap; -import java.util.Map; - import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileInstance; import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.LightType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; + +import java.util.EnumMap; +import java.util.Map; public class GearboxInstance extends KineticTileInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, GearboxInstance::new)); - } protected EnumMap> keys; protected Direction sourceFacing; - public GearboxInstance(InstancedTileRenderer modelManager, GearboxTileEntity tile) { + public GearboxInstance(InstancedTileRenderer modelManager, GearboxTileEntity tile) { super(modelManager, tile); } @@ -50,14 +41,16 @@ public class GearboxInstance extends KineticTileInstance { InstancedModel shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState, direction); - InstanceKey key = shaft.setupInstance(data -> { - data.setBlockLight(blockLight) - .setSkyLight(skyLight) - .setRotationalSpeed(getSpeed(direction)) - .setRotationOffset(getRotationOffset(axis)) - .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) - .setTileEntity(tile); - }); + InstanceKey key = shaft.createInstance(); + + key.getInstance() + .setBlockLight(blockLight) + .setSkyLight(skyLight) + .setRotationalSpeed(getSpeed(direction)) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) + .setTileEntity(tile); + keys.put(direction, key); } } @@ -87,26 +80,21 @@ public class GearboxInstance extends KineticTileInstance { public void onUpdate() { updateSourceFacing(); for (Map.Entry> key : keys.entrySet()) { - key.getValue().modifyInstance(data -> { - Direction direction = key.getKey(); - Direction.Axis axis = direction.getAxis(); + Direction direction = key.getKey(); + Direction.Axis axis = direction.getAxis(); - data.setColor(tile.network) - .setRotationalSpeed(getSpeed(direction)) - .setRotationOffset(getRotationOffset(axis)) - .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()); - }); + key.getValue() + .getInstance() + .setColor(tile.network) + .setRotationalSpeed(getSpeed(direction)) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()); } } @Override public void updateLight() { - int blockLight = tile.getWorld().getLightLevel(LightType.BLOCK, pos); - int skyLight = tile.getWorld().getLightLevel(LightType.SKY, pos); - - for (InstanceKey key : keys.values()) { - key.modifyInstance(data -> data.setBlockLight(blockLight).setSkyLight(skyLight)); - } + relight(pos, keys.values().stream().map(InstanceKey::getInstance)); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java index bd74bcdf8..38cc2965b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java @@ -8,7 +8,6 @@ import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; @@ -30,7 +29,7 @@ public class GearboxRenderer extends KineticTileEntityRenderer { final Axis boxAxis = te.getBlockState().get(BlockStateProperties.AXIS); final BlockPos pos = te.getPos(); - float time = AnimationTickHolder.getRenderTick(); + float time = AnimationTickHolder.getRenderTime(te.getWorld()); for (Direction direction : Iterate.directions) { final Axis axis = direction.getAxis(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItemRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItemRenderer.java index 6c984fb4c..1ce92b68f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItemRenderer.java @@ -3,8 +3,8 @@ package com.simibubi.create.content.contraptions.wrench; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.block.render.CustomRenderedItemModelRenderer; import com.simibubi.create.foundation.item.PartialItemModelRenderer; +import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueHandler; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.item.ItemStack; import net.minecraft.util.math.vector.Vector3f; @@ -16,11 +16,9 @@ public class WrenchItemRenderer extends CustomRenderedItemModelRenderer> rangeModifier = - new LazyValue>(() -> - // Holding an ExtendoGrip - ImmutableMultimap.of( - ForgeMod.REACH_DISTANCE.get(), - new AttributeModifier(UUID.fromString("7f7dbdb2-0d0d-458a-aa40-ac7633691f66"), "Range modifier", 3, - AttributeModifier.Operation.ADDITION)) - ); + public static final AttributeModifier singleRangeAttributeModifier = new AttributeModifier(UUID.fromString("7f7dbdb2-0d0d-458a-aa40-ac7633691f66"), "Range modifier", 3, AttributeModifier.Operation.ADDITION); + public static final AttributeModifier doubleRangeAttributeModifier = new AttributeModifier(UUID.fromString("8f7dbdb2-0d0d-458a-aa40-ac7633691f66"), "Range modifier", 5, AttributeModifier.Operation.ADDITION); - static LazyValue> doubleRangeModifier = - new LazyValue>(() -> - // Holding two ExtendoGrips o.O - ImmutableMultimap.of( - ForgeMod.REACH_DISTANCE.get(), - new AttributeModifier(UUID.fromString("8f7dbdb2-0d0d-458a-aa40-ac7633691f66"), "Range modifier", 5, - AttributeModifier.Operation.ADDITION)) - ); + static LazyValue> rangeModifier = + new LazyValue<>(() -> + // Holding an ExtendoGrip + ImmutableMultimap.of(ForgeMod.REACH_DISTANCE.get(), singleRangeAttributeModifier) + ); + + static LazyValue> doubleRangeModifier = + new LazyValue<>(() -> + // Holding two ExtendoGrips o.O + ImmutableMultimap.of(ForgeMod.REACH_DISTANCE.get(), doubleRangeAttributeModifier) + ); public ExtendoGripItem(Properties properties) { super(properties.maxStackSize(1) diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java index 64167a651..50cd6a226 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java @@ -6,7 +6,6 @@ import com.simibubi.create.foundation.block.render.CustomRenderedItemModelRender import com.simibubi.create.foundation.item.PartialItemModelRenderer; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.MatrixStacker; - import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.item.ItemStack; @@ -97,7 +96,7 @@ public class ExtendoGripItemRenderer extends CustomRenderedItemModelRenderer { @Override @@ -33,7 +28,7 @@ public class BlockzapperItemRenderer extends ZapperItemRenderer { @Override @@ -25,7 +24,7 @@ public class WorldshaperItemRenderer extends ZapperItemRenderer owner) { + super(owner); + } + + public FlapData setPosition(BlockPos pos) { + return setPosition(pos.getX(), pos.getY(), pos.getZ()); + } + + public FlapData setPosition(Vector3f pos) { + return setPosition(pos.getX(), pos.getY(), pos.getZ()); + } + + public FlapData setPosition(int x, int y, int z) { + BlockPos origin = owner.renderer.getOriginCoordinate(); + + return setPosition((float) (x - origin.getX()), + (float) (y - origin.getY()), + (float) (z - origin.getZ())); + } + + public FlapData setPosition(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + public FlapData setBlockLight(int blockLight) { + this.blockLight = (byte) ((blockLight & 0xF) << 4); + return this; + } + + public FlapData setSkyLight(int skyLight) { + this.skyLight = (byte) ((skyLight & 0xF) << 4); + return this; + } + + public FlapData setSegmentOffset(float x, float y, float z) { + this.segmentOffsetX = x; + this.segmentOffsetY = y; + this.segmentOffsetZ = z; + return this; + } + + public FlapData setIntensity(float intensity) { + this.intensity = intensity; + return this; + } + + public FlapData setHorizontalAngle(float horizontalAngle) { + this.horizontalAngle = horizontalAngle; + return this; + } + + public FlapData setFlapScale(float flapScale) { + this.flapScale = flapScale; + return this; + } + + public FlapData setFlapness(float flapness) { + this.flapness = flapness; + return this; + } + + public FlapData setPivotVoxelSpace(float x, float y, float z) { + pivotX = x / 16f; + pivotY = y / 16f; + pivotZ = z / 16f; + return this; + } + + @Override + public void write(ByteBuffer buf) { + putVec3(buf, x, y, z); + putVec2(buf, blockLight, skyLight); + + putVec3(buf, segmentOffsetX, segmentOffsetY, segmentOffsetZ); + putVec3(buf, pivotX, pivotY, pivotZ); + + put(buf, horizontalAngle); + put(buf, intensity); + put(buf, flapScale); + + put(buf, flapness); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/FlapInstancedModel.java b/src/main/java/com/simibubi/create/content/logistics/block/FlapInstancedModel.java new file mode 100644 index 000000000..d9502bb4d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/FlapInstancedModel.java @@ -0,0 +1,22 @@ +package com.simibubi.create.content.logistics.block; + +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import net.minecraft.client.renderer.BufferBuilder; + +public class FlapInstancedModel extends InstancedModel { + public FlapInstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(renderer, buf); + } + + @Override + protected FlapData newInstance() { + return new FlapData(this); + } + + @Override + protected VertexFormat getInstanceFormat() { + return FlapData.FORMAT; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/FlapVertexAttributes.java b/src/main/java/com/simibubi/create/content/logistics/block/FlapVertexAttributes.java new file mode 100644 index 000000000..6bf8a85d5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/FlapVertexAttributes.java @@ -0,0 +1,46 @@ +package com.simibubi.create.content.logistics.block; + +import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IAttribSpec; +import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; + +public enum FlapVertexAttributes implements IVertexAttrib { + INSTANCE_POSITION("aInstancePos",CommonAttributes.VEC3), + LIGHT("aLight", CommonAttributes.LIGHT), + SEGMENT_OFFSET("aSegmentOffset", CommonAttributes.VEC3), + PIVOT("aPivot", CommonAttributes.VEC3), + HORIZONTAL_ANGLE("aHorizontalAngle", CommonAttributes.FLOAT), + INTENSITY("aIntensity", CommonAttributes.FLOAT), + FLAP_SCALE("aFlapScale", CommonAttributes.FLOAT), + FLAPNESS("aFlapness", CommonAttributes.FLOAT), + ; + + private final String name; + private final VertexAttribSpec spec; + + FlapVertexAttributes(String name, VertexAttribSpec spec) { + this.name = name; + this.spec = spec; + } + + @Override + public String attribName() { + return name; + } + + @Override + public IAttribSpec attribSpec() { + return spec; + } + + @Override + public int getDivisor() { + return 1; + } + + @Override + public int getBufferIndex() { + return 1; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java index 95e1da224..4cb2166b9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java @@ -11,7 +11,6 @@ import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.BlockItemUseContext; @@ -26,6 +25,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.IStringSerializable; +import net.minecraft.util.Rotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; @@ -211,6 +211,14 @@ public class BeltTunnelBlock extends Block implements ITE, return ActionResultType.SUCCESS; } + @Override + public BlockState rotate(BlockState state, Rotation rotation) { + Direction fromAxis = Direction.getFacingFromAxis(AxisDirection.POSITIVE, state.get(HORIZONTAL_AXIS)); + Direction rotated = rotation.rotate(fromAxis); + + return state.with(HORIZONTAL_AXIS, rotated.getAxis()); + } + @Override public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java new file mode 100644 index 000000000..956ac0d97 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java @@ -0,0 +1,108 @@ +package com.simibubi.create.content.logistics.block.belts.tunnel; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; +import com.simibubi.create.content.logistics.block.FlapData; +import com.simibubi.create.foundation.gui.widgets.InterpolatedValue; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import net.minecraft.util.Direction; +import net.minecraft.world.LightType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.Map; + +public class BeltTunnelInstance extends TileEntityInstance implements ITickableInstance { + + + private Map>> tunnelFlaps; + + public BeltTunnelInstance(InstancedTileRenderer modelManager, BeltTunnelTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + tunnelFlaps = new EnumMap<>(Direction.class); + + InstancedModel model = modelManager.getMaterial(KineticRenderMaterials.FLAPS) + .getModel(AllBlockPartials.BELT_TUNNEL_FLAP, lastState); + + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + tile.flaps.forEach((direction, flapValue) -> { + + float flapness = flapValue.get(AnimationTickHolder.getPartialTicks()); + + float horizontalAngle = direction.getOpposite().getHorizontalAngle(); + + float flapScale = direction.getAxis() == Direction.Axis.X ? 1 : -1; + + ArrayList> flaps = new ArrayList<>(4); + + for (int segment = 0; segment <= 3; segment++) { + float intensity = segment == 3 ? 1.5f : segment + 1; + float segmentOffset = -3 / 16f * segment; + + InstanceKey key = model.createInstance(); + + key.getInstance() + .setPosition(pos) + .setSegmentOffset(segmentOffset, 0, 0) + .setBlockLight(blockLight) + .setSkyLight(skyLight) + .setHorizontalAngle(horizontalAngle) + .setFlapness(flapness) + .setFlapScale(flapScale) + .setPivotVoxelSpace(0, 10, 1) + .setIntensity(intensity); + + flaps.add(key); + } + + tunnelFlaps.put(direction, flaps); + }); + } + + @Override + public void tick() { + tunnelFlaps.forEach((direction, keys) -> { + InterpolatedValue flapValue = tile.flaps.get(direction); + if (flapValue == null) { + return; + } + + float flapness = flapValue.get(AnimationTickHolder.getPartialTicks()); + for (InstanceKey key : keys) { + key.getInstance().setFlapness(flapness); + } + }); + } + + @Override + protected void onUpdate() { } + + @Override + public void updateLight() { + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + for (ArrayList> instanceKeys : tunnelFlaps.values()) { + for (InstanceKey it : instanceKeys) { + it.getInstance().setBlockLight(blockLight) + .setSkyLight(skyLight); + } + } + } + + @Override + public void remove() { + tunnelFlaps.values() + .stream() + .flatMap(Collection::stream) + .forEach(InstanceKey::delete); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java index fe4d3353a..61b5a4090 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java @@ -4,12 +4,12 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; @@ -28,6 +28,9 @@ public class BeltTunnelRenderer extends SmartTileEntityRenderer flaps; +public class BeltTunnelTileEntity extends SmartTileEntity implements IInstanceRendered { + + public Map flaps; public Set sides; protected LazyOptional cap = LazyOptional.empty(); @@ -43,7 +43,7 @@ public class BeltTunnelTileEntity extends SmartTileEntity { public BeltTunnelTileEntity(TileEntityType type) { super(type); - flaps = new HashMap<>(); + flaps = new EnumMap<>(Direction.class); sides = new HashSet<>(); flapsToSend = new LinkedList<>(); } @@ -67,22 +67,6 @@ public class BeltTunnelTileEntity extends SmartTileEntity { compound.put("Sides", sidesNBT); super.write(compound, clientPacket); - - if (!clientPacket) - return; - - flapsNBT = new ListNBT(); - if (!flapsToSend.isEmpty()) { - for (Pair pair : flapsToSend) { - CompoundNBT flap = new CompoundNBT(); - flap.putInt("Flap", pair.getKey() - .getIndex()); - flap.putBoolean("FlapInward", pair.getValue()); - flapsNBT.add(flap); - } - compound.put("TriggerFlaps", flapsNBT); - flapsToSend.clear(); - } } @Override @@ -113,16 +97,8 @@ public class BeltTunnelTileEntity extends SmartTileEntity { super.fromTag(state, compound, clientPacket); - if (!clientPacket) - return; - if (!compound.contains("TriggerFlaps")) - return; - flapsNBT = compound.getList("TriggerFlaps", NBT.TAG_COMPOUND); - for (INBT inbt : flapsNBT) { - CompoundNBT flap = (CompoundNBT) inbt; - Direction side = Direction.byIndex(flap.getInt("Flap")); - flap(side, flap.getBoolean("FlapInward")); - } + if (clientPacket) + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> FastRenderDispatcher.enqueueUpdate(this)); } public void updateTunnelConnections() { @@ -154,8 +130,8 @@ public class BeltTunnelTileEntity extends SmartTileEntity { continue; flaps.put(direction, new InterpolatedChasingValue().start(.25f) - .target(0) - .withSpeed(.05f)); + .target(0) + .withSpeed(.05f)); } sendData(); } @@ -174,7 +150,7 @@ public class BeltTunnelTileEntity extends SmartTileEntity { @Override public void initialize() { super.initialize(); -// updateTunnelConnections(); + updateTunnelConnections(); } @Override @@ -182,12 +158,18 @@ public class BeltTunnelTileEntity extends SmartTileEntity { super.tick(); if (!world.isRemote) { if (!flapsToSend.isEmpty()) - sendData(); + sendFlaps(); return; } flaps.forEach((d, value) -> value.tick()); } + private void sendFlaps() { + AllPackets.channel.send(packetTarget(), new TunnelFlapPacket(this, flapsToSend)); + + flapsToSend.clear(); + } + @Override public void addBehaviours(List behaviours) {} @@ -211,5 +193,4 @@ public class BeltTunnelTileEntity extends SmartTileEntity { } return this.cap.cast(); } - } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/AbstractChuteBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/AbstractChuteBlock.java index 513a0c454..4ad4242fa 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/AbstractChuteBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/chute/AbstractChuteBlock.java @@ -1,14 +1,11 @@ package com.simibubi.create.content.logistics.block.chute; -import javax.annotation.Nullable; - import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.particle.ParticleManager; @@ -29,6 +26,9 @@ import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.util.LazyOptional; + +import javax.annotation.Nullable; public abstract class AbstractChuteBlock extends Block implements IWrenchable, ITE { @@ -156,9 +156,10 @@ public abstract class AbstractChuteBlock extends Block implements IWrenchable, I @Override public void neighborChanged(BlockState p_220069_1_, World world, BlockPos pos, Block p_220069_4_, BlockPos neighbourPos, boolean p_220069_6_) { - if (pos.down() - .equals(neighbourPos)) + if (pos.down().equals(neighbourPos)) withTileEntityDo(world, pos, ChuteTileEntity::blockBelowChanged); + else if (pos.up().equals(neighbourPos)) + withTileEntityDo(world, pos, chute -> chute.capAbove = LazyOptional.empty()); } public abstract BlockState updateChuteState(BlockState state, BlockState above, IBlockReader world, BlockPos pos); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java index f4292db81..53c466fff 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java @@ -1,11 +1,5 @@ package com.simibubi.create.content.logistics.block.chute; -import java.util.LinkedList; -import java.util.List; - -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; - import com.simibubi.create.AllBlocks; import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.components.fan.AirCurrent; @@ -27,7 +21,6 @@ import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.VecHelper; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -53,6 +46,11 @@ import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.LinkedList; +import java.util.List; + @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault /* @@ -273,6 +271,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor public void blockBelowChanged() { updateAirFlow = true; + capBelow = LazyOptional.empty(); } private void spawnParticles(float itemMotion) { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractDirectionalFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractDirectionalFunnelBlock.java new file mode 100644 index 000000000..43dd71869 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractDirectionalFunnelBlock.java @@ -0,0 +1,40 @@ +package com.simibubi.create.content.logistics.block.funnel; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.StateContainer.Builder; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; +import net.minecraft.util.Mirror; +import net.minecraft.util.Rotation; + +public class AbstractDirectionalFunnelBlock extends AbstractFunnelBlock { + + public static final DirectionProperty FACING = BlockStateProperties.FACING; + + protected AbstractDirectionalFunnelBlock(Properties p_i48377_1_) { + super(p_i48377_1_); + } + + @Override + protected void fillStateContainer(Builder builder) { + super.fillStateContainer(builder.add(FACING)); + } + + @Override + protected Direction getFacing(BlockState state) { + return state.get(FACING); + } + + @Override + public BlockState rotate(BlockState state, Rotation rot) { + return state.with(FACING, rot.rotate(state.get(FACING))); + } + + @Override + public BlockState mirror(BlockState state, Mirror mirrorIn) { + return state.rotate(mirrorIn.toRotation(state.get(FACING))); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractFunnelBlock.java index 758ee2417..18c402dda 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractFunnelBlock.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.logistics.block.funnel; -import javax.annotation.Nullable; - import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ITE; @@ -9,10 +7,8 @@ import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; import com.simibubi.create.foundation.utility.BlockHelper; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; -import net.minecraft.block.HorizontalBlock; import net.minecraft.client.particle.ParticleManager; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; @@ -28,7 +24,9 @@ import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public abstract class AbstractFunnelBlock extends HorizontalBlock implements ITE, IWrenchable { +import javax.annotation.Nullable; + +public abstract class AbstractFunnelBlock extends Block implements ITE, IWrenchable { public static final BooleanProperty POWERED = BlockStateProperties.POWERED; @@ -39,16 +37,13 @@ public abstract class AbstractFunnelBlock extends HorizontalBlock implements ITE @Override public BlockState getStateForPlacement(BlockItemUseContext context) { - Direction facing = context.getPlacementHorizontalFacing() - .getOpposite(); - return getDefaultState().with(HORIZONTAL_FACING, facing) - .with(POWERED, context.getWorld() - .isBlockPowered(context.getPos())); + return getDefaultState().with(POWERED, context.getWorld() + .isBlockPowered(context.getPos())); } @Override protected void fillStateContainer(Builder builder) { - super.fillStateContainer(builder.add(POWERED, HORIZONTAL_FACING)); + super.fillStateContainer(builder.add(POWERED)); } @Override @@ -63,6 +58,9 @@ public abstract class AbstractFunnelBlock extends HorizontalBlock implements ITE boolean isMoving) { if (worldIn.isRemote) return; + InvManipulationBehaviour behaviour = TileEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); + if (behaviour != null) + behaviour.onNeighborChanged(fromPos); boolean previouslyPowered = state.get(POWERED); if (previouslyPowered != worldIn.isBlockPowered(pos)) worldIn.setBlockState(pos, state.cycle(POWERED), 2); @@ -120,9 +118,7 @@ public abstract class AbstractFunnelBlock extends HorizontalBlock implements ITE return ((AbstractFunnelBlock) state.getBlock()).getFacing(state); } - protected Direction getFacing(BlockState state) { - return state.get(BlockStateProperties.HORIZONTAL_FACING); - } + protected abstract Direction getFacing(BlockState state); @Override public void onReplaced(BlockState p_196243_1_, World p_196243_2_, BlockPos p_196243_3_, BlockState p_196243_4_, diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractHorizontalFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractHorizontalFunnelBlock.java new file mode 100644 index 000000000..87b2f1321 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractHorizontalFunnelBlock.java @@ -0,0 +1,40 @@ +package com.simibubi.create.content.logistics.block.funnel; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.StateContainer.Builder; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; +import net.minecraft.util.Mirror; +import net.minecraft.util.Rotation; + +public abstract class AbstractHorizontalFunnelBlock extends AbstractFunnelBlock { + + public static final DirectionProperty HORIZONTAL_FACING = BlockStateProperties.HORIZONTAL_FACING; + + protected AbstractHorizontalFunnelBlock(Properties p_i48377_1_) { + super(p_i48377_1_); + } + + @Override + protected void fillStateContainer(Builder builder) { + super.fillStateContainer(builder.add(HORIZONTAL_FACING)); + } + + @Override + protected Direction getFacing(BlockState state) { + return state.get(HORIZONTAL_FACING); + } + + @Override + public BlockState rotate(BlockState p_185499_1_, Rotation p_185499_2_) { + return p_185499_1_.with(HORIZONTAL_FACING, p_185499_2_.rotate(p_185499_1_.get(HORIZONTAL_FACING))); + } + + @Override + public BlockState mirror(BlockState p_185471_1_, Mirror p_185471_2_) { + return p_185471_1_.rotate(p_185471_2_.toRotation(p_185471_1_.get(HORIZONTAL_FACING))); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AndesiteFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/AndesiteFunnelBlock.java index 6db0b2b2f..3b5961870 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AndesiteFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/AndesiteFunnelBlock.java @@ -1,7 +1,6 @@ package com.simibubi.create.content.logistics.block.funnel; import com.simibubi.create.AllBlocks; - import net.minecraft.block.BlockState; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -15,7 +14,7 @@ public class AndesiteFunnelBlock extends FunnelBlock { @Override public BlockState getEquivalentBeltFunnel(IBlockReader world, BlockPos pos, BlockState state) { - Direction facing = state.get(HORIZONTAL_FACING); + Direction facing = getFunnelFacing(state); return AllBlocks.ANDESITE_BELT_FUNNEL.getDefaultState() .with(BeltFunnelBlock.HORIZONTAL_FACING, facing) .with(POWERED, state.get(POWERED)); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java index 80d91c888..f66d2209e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java @@ -12,7 +12,6 @@ import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputB import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.VoxelShaper; import com.tterrag.registrate.util.entry.BlockEntry; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.item.ItemEntity; @@ -34,7 +33,7 @@ import net.minecraft.world.IWorld; import net.minecraft.world.IWorldReader; import net.minecraft.world.World; -public class BeltFunnelBlock extends AbstractFunnelBlock implements ISpecialBlockItemRequirement { +public class BeltFunnelBlock extends AbstractHorizontalFunnelBlock implements ISpecialBlockItemRequirement { private BlockEntry parent; @@ -124,7 +123,7 @@ public class BeltFunnelBlock extends AbstractFunnelBlock implements ISpecialBloc parentState = parentState.with(POWERED, true); if (state.get(SHAPE) == Shape.PUSHING) parentState = parentState.with(FunnelBlock.EXTRACTING, true); - return parentState.with(FunnelBlock.HORIZONTAL_FACING, state.get(HORIZONTAL_FACING)); + return parentState.with(FunnelBlock.FACING, state.get(HORIZONTAL_FACING)); } Shape updatedShape = getShapeForPosition(world, pos, state.get(HORIZONTAL_FACING), state.get(SHAPE) == Shape.PUSHING); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BrassFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/BrassFunnelBlock.java index 290c44154..7a1fe0670 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BrassFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/BrassFunnelBlock.java @@ -1,7 +1,6 @@ package com.simibubi.create.content.logistics.block.funnel; import com.simibubi.create.AllBlocks; - import net.minecraft.block.BlockState; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -15,7 +14,7 @@ public class BrassFunnelBlock extends FunnelBlock { @Override public BlockState getEquivalentBeltFunnel(IBlockReader world, BlockPos pos, BlockState state) { - Direction facing = state.get(HORIZONTAL_FACING); + Direction facing = getFacing(state); return AllBlocks.BRASS_BELT_FUNNEL.getDefaultState() .with(BeltFunnelBlock.HORIZONTAL_FACING, facing) .with(POWERED, state.get(POWERED)); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java index 2a5558b30..387ad758f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java @@ -4,7 +4,6 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; @@ -14,10 +13,7 @@ import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; import net.minecraft.state.BooleanProperty; -import net.minecraft.state.EnumProperty; import net.minecraft.state.StateContainer.Builder; -import net.minecraft.state.properties.AttachFace; -import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Direction.AxisDirection; @@ -31,15 +27,13 @@ import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorld; import net.minecraft.world.World; -public abstract class FunnelBlock extends AbstractFunnelBlock { +public abstract class FunnelBlock extends AbstractDirectionalFunnelBlock { - public static final EnumProperty FACE = BlockStateProperties.FACE; public static final BooleanProperty EXTRACTING = BooleanProperty.create("extracting"); public FunnelBlock(Properties p_i48415_1_) { super(p_i48415_1_); - setDefaultState(getDefaultState().with(FACE, AttachFace.WALL) - .with(EXTRACTING, false)); + setDefaultState(getDefaultState().with(EXTRACTING, false)); } public abstract BlockState getEquivalentBeltFunnel(IBlockReader world, BlockPos pos, BlockState state); @@ -53,13 +47,7 @@ public abstract class FunnelBlock extends AbstractFunnelBlock { state = state.with(EXTRACTING, !sneak); for (Direction direction : context.getNearestLookingDirections()) { - BlockState blockstate; - if (direction.getAxis() == Direction.Axis.Y) - blockstate = state.with(FACE, direction == Direction.UP ? AttachFace.CEILING : AttachFace.FLOOR) - .with(HORIZONTAL_FACING, context.getPlacementHorizontalFacing()); - else - blockstate = state.with(FACE, AttachFace.WALL) - .with(HORIZONTAL_FACING, direction.getOpposite()); + BlockState blockstate = state.with(FACING, direction.getOpposite()); if (blockstate.isValidPosition(context.getWorld(), context.getPos())) return blockstate.with(POWERED, state.get(POWERED)); } @@ -69,7 +57,7 @@ public abstract class FunnelBlock extends AbstractFunnelBlock { @Override protected void fillStateContainer(Builder builder) { - super.fillStateContainer(builder.add(FACE, EXTRACTING)); + super.fillStateContainer(builder.add(EXTRACTING)); } @Override @@ -137,26 +125,17 @@ public abstract class FunnelBlock extends AbstractFunnelBlock { return !state.get(POWERED) && !state.get(EXTRACTING); } - @Override - protected Direction getFacing(BlockState state) { - if (state.get(FACE) == AttachFace.CEILING) - return Direction.DOWN; - if (state.get(FACE) == AttachFace.FLOOR) - return Direction.UP; - return super.getFacing(state); - } - @Override public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { - AttachFace attachFace = state.get(FACE); - return attachFace == AttachFace.CEILING ? AllShapes.FUNNEL_CEILING - : attachFace == AttachFace.FLOOR ? AllShapes.FUNNEL_FLOOR - : AllShapes.FUNNEL.get(state.get(HORIZONTAL_FACING)); + Direction facing = state.get(FACING); + return facing == Direction.DOWN ? AllShapes.FUNNEL_CEILING + : facing == Direction.UP ? AllShapes.FUNNEL_FLOOR : AllShapes.FUNNEL_WALL.get(facing); } @Override public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { - if (context.getEntity() instanceof ItemEntity && state.get(FACE) == AttachFace.WALL) + if (context.getEntity() instanceof ItemEntity && getFacing(state).getAxis() + .isHorizontal()) return AllShapes.FUNNEL_COLLISION.get(getFacing(state)); return getShape(state, world, pos, context); } @@ -164,7 +143,8 @@ public abstract class FunnelBlock extends AbstractFunnelBlock { @Override public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState p_196271_3_, IWorld world, BlockPos pos, BlockPos p_196271_6_) { - if (state.get(FACE) != AttachFace.WALL || direction != Direction.DOWN) + if (getFacing(state).getAxis() + .isVertical() || direction != Direction.DOWN) return state; BlockState equivalentFunnel = getEquivalentBeltFunnel(null, null, state); if (BeltFunnelBlock.isOnValidBelt(equivalentFunnel, world, pos)) diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelFilterSlotPositioning.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelFilterSlotPositioning.java index 3ba0cf72e..8fab3a0a2 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelFilterSlotPositioning.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelFilterSlotPositioning.java @@ -6,9 +6,7 @@ import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; -import net.minecraft.state.properties.AttachFace; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.vector.Vector3d; @@ -36,50 +34,24 @@ public class FunnelFilterSlotPositioning extends ValueBoxTransform.Sided { } } - if (state.getBlock() instanceof FunnelBlock) { - if (state.get(FunnelBlock.FACE) == AttachFace.WALL) - return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.1, 8.7f), horizontalAngle, Axis.Y); - Vector3d southLocation = VecHelper.voxelSpace(8, funnelFacing == Direction.DOWN ? 6.5f : 9.5f, 13f); - return VecHelper.rotateCentered(southLocation, - AngleHelper.horizontalAngle(state.get(AbstractFunnelBlock.HORIZONTAL_FACING)), Axis.Y); + if (!funnelFacing.getAxis() + .isHorizontal()) { + Vector3d southLocation = VecHelper.voxelSpace(8, funnelFacing == Direction.DOWN ? 14 : 2, 15.5f); + return VecHelper.rotateCentered(southLocation, horizontalAngle, Axis.Y); } - return Vector3d.ZERO; - -// if (!funnelFacing.getAxis() -// .isHorizontal()) { -// Vector3d southLocation = VecHelper.voxelSpace(8, funnelFacing == Direction.DOWN ? 3 : 13, 15.5f); -// return VecHelper.rotateCentered(southLocation, horizontalAngle, Axis.Y); -// } -// -// Direction verticalDirection = DirectionHelper.rotateAround(getSide(), funnelFacing.rotateY() -// .getAxis()); -// if (funnelFacing.getAxis() == Axis.Z) -// verticalDirection = verticalDirection.getOpposite(); -// float yRot = -AngleHelper.horizontalAngle(verticalDirection) + 180; -// float xRot = -90; -// boolean alongX = funnelFacing.getAxis() == Axis.X; -// float zRotLast = alongX ^ funnelFacing.getAxisDirection() == AxisDirection.POSITIVE ? 180 : 0; -// -// Vector3d vec = VecHelper.voxelSpace(8, 13, .5f); -// vec = vec.subtract(.5, .5, .5); -// vec = VecHelper.rotate(vec, zRotLast, Axis.Z); -// vec = VecHelper.rotate(vec, yRot, Axis.Y); -// vec = VecHelper.rotate(vec, alongX ? 0 : xRot, Axis.X); -// vec = VecHelper.rotate(vec, alongX ? xRot : 0, Axis.Z); -// vec = vec.add(.5, .5, .5); -// return vec; + return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.1, 8.7f), horizontalAngle, Axis.Y); } @Override protected void rotate(BlockState state, MatrixStack ms) { Direction facing = FunnelBlock.getFunnelFacing(state); -// if (facing.getAxis() -// .isVertical()) { -// super.rotate(state, ms); -// return; -// } + if (facing.getAxis() + .isVertical()) { + super.rotate(state, ms); + return; + } boolean isBeltFunnel = state.getBlock() instanceof BeltFunnelBlock; if (isBeltFunnel && state.get(BeltFunnelBlock.SHAPE) != Shape.EXTENDED) { @@ -92,15 +64,13 @@ public class FunnelFilterSlotPositioning extends ValueBoxTransform.Sided { } if (state.getBlock() instanceof FunnelBlock) { - if (state.get(FunnelBlock.FACE) == AttachFace.WALL) { - super.rotate(state, ms); - MatrixStacker.of(ms) - .rotateX(-22.5f); - return; - } + super.rotate(state, ms); + MatrixStacker.of(ms) + .rotateX(-22.5f); + return; } - float yRot = AngleHelper.horizontalAngle(state.get(AbstractFunnelBlock.HORIZONTAL_FACING)) + float yRot = AngleHelper.horizontalAngle(AbstractFunnelBlock.getFunnelFacing(state)) + (facing == Direction.DOWN ? 180 : 0); MatrixStacker.of(ms) .rotateY(yRot) @@ -113,6 +83,10 @@ public class FunnelFilterSlotPositioning extends ValueBoxTransform.Sided { if (facing == null) return false; + if (facing.getAxis() + .isVertical()) + return direction.getAxis() + .isHorizontal(); if (state.getBlock() instanceof BeltFunnelBlock && state.get(BeltFunnelBlock.SHAPE) == Shape.EXTENDED) return direction == Direction.UP; return direction == facing; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelGenerator.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelGenerator.java new file mode 100644 index 000000000..12cd17b3d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelGenerator.java @@ -0,0 +1,81 @@ +package com.simibubi.create.content.logistics.block.funnel; + +import com.simibubi.create.Create; +import com.simibubi.create.foundation.data.SpecialBlockStateGen; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateBlockstateProvider; +import com.tterrag.registrate.providers.RegistrateItemModelProvider; +import com.tterrag.registrate.util.nullness.NonNullBiConsumer; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.item.Item; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.generators.BlockModelBuilder; +import net.minecraftforge.client.model.generators.ModelFile; + +public class FunnelGenerator extends SpecialBlockStateGen { + + private String type; + private ResourceLocation particleTexture; + private boolean hasFilter; + + public FunnelGenerator(String type, boolean hasFilter) { + this.type = type; + this.hasFilter = hasFilter; + this.particleTexture = Create.asResource("block/" + type + "_casing"); + } + + @Override + protected int getXRotation(BlockState state) { + return state.get(FunnelBlock.FACING) == Direction.DOWN ? 180 : 0; + } + + @Override + protected int getYRotation(BlockState state) { + return horizontalAngle(state.get(FunnelBlock.FACING)) + 180; + } + + @Override + public ModelFile getModel(DataGenContext c, RegistrateBlockstateProvider p, + BlockState s) { + String powered = s.get(FunnelBlock.POWERED) ? "_powered" : ""; + String closed = s.get(FunnelBlock.POWERED) ? "_closed" : "_open"; + String extracting = s.get(FunnelBlock.EXTRACTING) ? "_push" : "_pull"; + Direction facing = s.get(FunnelBlock.FACING); + boolean horizontal = facing.getAxis() + .isHorizontal(); + String parent = horizontal ? "horizontal" : hasFilter ? "vertical" : "vertical_filterless"; + + BlockModelBuilder model = p.models() + .withExistingParent("block/" + type + "_funnel_" + parent + extracting + powered, + p.modLoc("block/funnel/block_" + parent)) + .texture("particle", particleTexture) + .texture("7", p.modLoc("block/" + type + "_funnel_plating")) + .texture("5", p.modLoc("block/" + type + "_funnel_tall" + powered)) + .texture("2_2", p.modLoc("block/" + type + "_funnel" + extracting)) + .texture("3", p.modLoc("block/" + type + "_funnel_back")); + + if (horizontal) + return model.texture("6", p.modLoc("block/" + type + "_funnel" + powered)); + + return model.texture("8", particleTexture) + .texture("9", p.modLoc("block/" + type + "_funnel_slope")) + .texture("10", p.modLoc("block/funnel" + closed)); + } + + public static NonNullBiConsumer, RegistrateItemModelProvider> itemModel( + String type) { + ResourceLocation particleTexture = Create.asResource("block/" + type + "_casing"); + return (c, p) -> { + p.withExistingParent("item/" + type + "_funnel", p.modLoc("block/funnel/item")) + .texture("particle", particleTexture) + .texture("7", p.modLoc("block/" + type + "_funnel_plating")) + .texture("2", p.modLoc("block/" + type + "_funnel_neutral")) + .texture("6", p.modLoc("block/" + type + "_funnel")) + .texture("5", p.modLoc("block/" + type + "_funnel_tall")) + .texture("3", p.modLoc("block/" + type + "_funnel_back")); + }; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java new file mode 100644 index 000000000..64d87de29 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java @@ -0,0 +1,92 @@ +package com.simibubi.create.content.logistics.block.funnel; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; +import com.simibubi.create.content.logistics.block.FlapData; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import net.minecraft.util.Direction; +import net.minecraft.world.LightType; + +import java.util.ArrayList; + +public class FunnelInstance extends TileEntityInstance implements ITickableInstance { + + private ArrayList> flaps; + + public FunnelInstance(InstancedTileRenderer modelManager, FunnelTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + flaps = new ArrayList<>(4); + + if (!tile.hasFlap()) return; + + AllBlockPartials flapPartial = (lastState.getBlock() instanceof FunnelBlock ? AllBlockPartials.FUNNEL_FLAP + : AllBlockPartials.BELT_FUNNEL_FLAP); + InstancedModel model = modelManager.getMaterial(KineticRenderMaterials.FLAPS) + .getModel(flapPartial, lastState); + + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + Direction direction = FunnelBlock.getFunnelFacing(lastState); + + float flapness = tile.flap.get(AnimationTickHolder.getPartialTicks()); + float horizontalAngle = direction.getOpposite().getHorizontalAngle(); + + for (int segment = 0; segment <= 3; segment++) { + float intensity = segment == 3 ? 1.5f : segment + 1; + float segmentOffset = -3 / 16f * segment; + + InstanceKey key = model.createInstance(); + + key.getInstance() + .setPosition(pos) + .setSegmentOffset(segmentOffset, 0, -tile.getFlapOffset()) + .setBlockLight(blockLight) + .setSkyLight(skyLight) + .setHorizontalAngle(horizontalAngle) + .setFlapness(flapness) + .setFlapScale(-1) + .setPivotVoxelSpace(0, 10, 9.5f) + .setIntensity(intensity); + + flaps.add(key); + } + } + + @Override + public void tick() { + if (flaps == null) return; + + float flapness = tile.flap.get(AnimationTickHolder.getPartialTicks()); + + for (InstanceKey key : flaps) { + key.getInstance().setFlapness(flapness); + } + } + + @Override + public void updateLight() { + if (flaps == null) return; + + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + for (InstanceKey it : flaps) { + it.getInstance() + .setBlockLight(blockLight) + .setSkyLight(skyLight); + } + } + + @Override + public void remove() { + if (flaps == null) return; + + flaps.forEach(InstanceKey::delete); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelItem.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelItem.java index c7a0a6357..6be897d1c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelItem.java @@ -1,12 +1,10 @@ package com.simibubi.create.content.logistics.block.funnel; import com.simibubi.create.foundation.advancement.AllTriggers; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItemUseContext; -import net.minecraft.state.properties.AttachFace; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -38,10 +36,12 @@ public class FunnelItem extends BlockItem { return state; if (!(state.getBlock() instanceof FunnelBlock)) return state; - if (state.get(FunnelBlock.FACE) != AttachFace.WALL) + if (state.get(FunnelBlock.FACING) + .getAxis() + .isVertical()) return state; - Direction direction = state.get(FunnelBlock.HORIZONTAL_FACING); + Direction direction = state.get(FunnelBlock.FACING); FunnelBlock block = (FunnelBlock) getBlock(); Block beltFunnelBlock = block.getEquivalentBeltFunnel(world, pos, state) .getBlock(); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java index ab0af8375..175ec34b0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java @@ -1,19 +1,23 @@ package com.simibubi.create.content.logistics.block.funnel; -import java.util.List; - import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.logistics.item.filter.FilterItem; - +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.item.ItemHelper; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; +import net.minecraft.util.Direction; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvents; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.items.ItemHandlerHelper; +import java.util.List; + public class FunnelMovementBehaviour extends MovementBehaviour { private final boolean hasFilter; @@ -32,14 +36,67 @@ public class FunnelMovementBehaviour extends MovementBehaviour { @Override public Vector3d getActiveAreaOffset(MovementContext context) { - return Vector3d.of(FunnelBlock.getFunnelFacing(context.state) - .getDirectionVec()).scale(.65); + Direction facing = FunnelBlock.getFunnelFacing(context.state); + Vector3d vec = Vector3d.of(facing.getDirectionVec()); + if (facing != Direction.UP) + return vec.scale(context.state.get(FunnelBlock.EXTRACTING) ? .15 : .65); + + return vec.scale(.65); } @Override public void visitNewPosition(MovementContext context, BlockPos pos) { super.visitNewPosition(context, pos); + if (context.state.get(FunnelBlock.EXTRACTING)) + extract(context, pos); + else + succ(context, pos); + + + } + + private void extract(MovementContext context, BlockPos pos) { + World world = context.world; + + Vector3d entityPos = context.position; + if (context.state.get(FunnelBlock.FACING) != Direction.DOWN) + entityPos = entityPos.add(0, -.5f, 0); + + if (!world.getBlockState(pos).getCollisionShape(world, pos).isEmpty()) + return;//only drop items if the target block is a empty space + + if (!world.getEntitiesWithinAABB(ItemEntity.class, new AxisAlignedBB(new BlockPos(entityPos))).isEmpty()) + return;//don't drop items if there already are any in the target block space + + ItemStack filter = getFilter(context); + int filterAmount = context.tileData.getInt("FilterAmount"); + if (filterAmount <= 0) + filterAmount = hasFilter ? AllConfigs.SERVER.logistics.defaultExtractionLimit.get() : 1; + + ItemStack extract = ItemHelper.extract( + context.contraption.inventory, + s -> FilterItem.test(world, s, filter), + ItemHelper.ExtractionCountMode.UPTO, + filterAmount, + false); + + if (extract.isEmpty()) + return; + + if (world.isRemote) + return; + + + + ItemEntity entity = new ItemEntity(world, entityPos.x, entityPos.y, entityPos.z, extract); + entity.setMotion(Vector3d.ZERO); + entity.setPickupDelay(5); + world.playSound(null, pos, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, 1/16f, .1f); + world.addEntity(entity); + } + + private void succ(MovementContext context, BlockPos pos) { World world = context.world; List items = world.getEntitiesWithinAABB(ItemEntity.class, new AxisAlignedBB(pos)); ItemStack filter = getFilter(context); @@ -61,7 +118,6 @@ public class FunnelMovementBehaviour extends MovementBehaviour { item.setItem(remainder); } - } private ItemStack getFilter(MovementContext context) { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java index a172dbfc7..1ef640218 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java @@ -4,11 +4,11 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -27,7 +27,7 @@ public class FunnelRenderer extends SmartTileEntityRenderer { int light, int overlay) { super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - if (!te.hasFlap()) + if (!te.hasFlap() || FastRenderDispatcher.available(te.getWorld())) return; BlockState blockState = te.getBlockState(); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java index 7a18d58da..7fdc583de 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java @@ -1,8 +1,5 @@ package com.simibubi.create.content.logistics.block.funnel; -import java.lang.ref.WeakReference; -import java.util.List; - import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation; @@ -11,9 +8,13 @@ import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity; import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape; +import com.simibubi.create.content.logistics.packet.FunnelFlapPacket; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; @@ -21,12 +22,10 @@ import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBe import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.state.properties.AttachFace; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; @@ -35,11 +34,16 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; -public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringInformation { +import java.lang.ref.WeakReference; +import java.util.List; + +public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringInformation, IInstanceRendered { private FilteringBehaviour filtering; private InvManipulationBehaviour invManipulation; @@ -47,7 +51,6 @@ public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringIn private WeakReference lastObserved; // In-world Extractors only - int sendFlap; InterpolatedChasingValue flap; static enum Mode { @@ -260,7 +263,7 @@ public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringIn return false; if (!(blockState.getBlock() instanceof FunnelBlock)) return false; - return blockState.get(FunnelBlock.FACE) == AttachFace.FLOOR; + return FunnelBlock.getFunnelFacing(blockState) == Direction.UP; } private boolean supportsFiltering() { @@ -282,8 +285,11 @@ public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringIn } public void flap(boolean inward) { - sendFlap = inward ? 1 : -1; - sendData(); + if (!world.isRemote) { + AllPackets.channel.send(packetTarget(), new FunnelFlapPacket(this, inward)); + } else { + flap.set(inward ? 1 : -1); + } } public boolean hasFlap() { @@ -315,20 +321,15 @@ public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringIn protected void write(CompoundNBT compound, boolean clientPacket) { super.write(compound, clientPacket); compound.putInt("TransferCooldown", extractionCooldown); - if (clientPacket && sendFlap != 0) { - compound.putInt("Flap", sendFlap); - sendFlap = 0; - } } @Override protected void fromTag(BlockState state, CompoundNBT compound, boolean clientPacket) { super.fromTag(state, compound, clientPacket); extractionCooldown = compound.getInt("TransferCooldown"); - if (clientPacket && compound.contains("Flap")) { - int direction = compound.getInt("Flap"); - flap.set(direction); - } + + if (clientPacket) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> FastRenderDispatcher.enqueueUpdate(this)); } @Override @@ -383,4 +384,9 @@ public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringIn return true; } + @Override + public boolean shouldRenderAsTE() { + return true; + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateBlock.java index 2d5b0c2af..99ef3e3ea 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateBlock.java @@ -3,7 +3,6 @@ package com.simibubi.create.content.logistics.block.inventories; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTileEntities; import com.simibubi.create.foundation.item.ItemHelper; - import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; @@ -111,7 +110,7 @@ public class AdjustableCrateBlock extends CrateBlock { public int getComparatorInputOverride(BlockState blockState, World worldIn, BlockPos pos) { TileEntity te = worldIn.getTileEntity(pos); if (te instanceof AdjustableCrateTileEntity) { - AdjustableCrateTileEntity flexcrateTileEntity = (AdjustableCrateTileEntity) te; + AdjustableCrateTileEntity flexcrateTileEntity = ((AdjustableCrateTileEntity) te).getMainCrate(); return ItemHelper.calcRedstoneFromInventory(flexcrateTileEntity.inventory); } return 0; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java index c4600dcf2..c3cf73af8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java @@ -1,29 +1,164 @@ package com.simibubi.create.content.logistics.block.mechanicalArm; +import com.google.common.collect.Lists; +import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; -import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +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.MatrixStacker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; -import net.minecraft.tileentity.TileEntityType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; +import java.util.ArrayList; -public class ArmInstance extends SingleRotatingInstance { - public static void register(TileEntityType type) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - InstancedTileRenderRegistry.instance.register(type, ArmInstance::new)); +public class ArmInstance extends SingleRotatingInstance implements ITickableInstance { + + private InstanceKey base; + private InstanceKey lowerBody; + private InstanceKey upperBody; + private InstanceKey head; + private InstanceKey claw; + private ArrayList> clawGrips; + + private ArrayList> models; + + private boolean firstTick = true; + + public ArmInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); } - public ArmInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { - super(modelManager, tile); + @Override + protected void init() { + super.init(); + + RenderMaterial> mat = modelManager.getMaterial(RenderMaterials.MODELS); + + base = mat.getModel(AllBlockPartials.ARM_BASE, lastState).createInstance(); + lowerBody = mat.getModel(AllBlockPartials.ARM_LOWER_BODY, lastState).createInstance(); + upperBody = mat.getModel(AllBlockPartials.ARM_UPPER_BODY, lastState).createInstance(); + head = mat.getModel(AllBlockPartials.ARM_HEAD, lastState).createInstance(); + claw = mat.getModel(AllBlockPartials.ARM_CLAW_BASE, lastState).createInstance(); + + InstancedModel clawHalfModel = mat.getModel(AllBlockPartials.ARM_CLAW_GRIP, lastState); + InstanceKey clawGrip1 = clawHalfModel.createInstance(); + InstanceKey clawGrip2 = clawHalfModel.createInstance(); + + clawGrips = Lists.newArrayList(clawGrip1, clawGrip2); + models = Lists.newArrayList(base, lowerBody, upperBody, head, claw, clawGrip1, clawGrip2); + + firstTick = true; + tick(); + updateLight(); + } + + @Override + public void tick() { + ArmTileEntity arm = (ArmTileEntity) tile; + + boolean settled = arm.baseAngle.settled() && arm.lowerArmAngle.settled() && arm.upperArmAngle.settled() && arm.headAngle.settled(); + boolean rave = arm.phase == ArmTileEntity.Phase.DANCING; + + if (!settled || rave || firstTick) + transformModels(arm, rave); + + if (settled) + firstTick = false; + } + + private void transformModels(ArmTileEntity arm, boolean rave) { + float pt = AnimationTickHolder.getPartialTicks(); + 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); + + if (rave) { + float renderTick = AnimationTickHolder.getRenderTime(arm.getWorld()) + (tile.hashCode() % 64); + 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.getTicks() * 100); + } + + + MatrixStack msLocal = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(msLocal); + msr.translate(getFloatingPos()); + msr.centre(); + + if (lastState.get(ArmBlock.CEILING)) + msr.rotateX(180); + + ArmRenderer.transformBase(msr, baseAngle); + base.getInstance() + .setTransform(msLocal); + + ArmRenderer.transformLowerArm(msr, lowerArmAngle); + lowerBody.getInstance() + .setColor(color) + .setTransform(msLocal); + + ArmRenderer.transformUpperArm(msr, upperArmAngle); + upperBody.getInstance() + .setColor(color) + .setTransform(msLocal); + + ArmRenderer.transformHead(msr, headAngle); + head.getInstance() + .setTransform(msLocal); + + ArmRenderer.transformClaw(msr); + claw.getInstance() + .setTransform(msLocal); + + ItemStack item = arm.heldItem; + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + boolean hasItem = !item.isEmpty(); + boolean isBlockItem = hasItem && (item.getItem() instanceof BlockItem) + && itemRenderer.getItemModelWithOverrides(item, Minecraft.getInstance().world, null) + .isGui3d(); + + for (int index : Iterate.zeroAndOne) { + msLocal.push(); + int flip = index * 2 - 1; + ArmRenderer.transformClawHalf(msr, hasItem, isBlockItem, flip); + clawGrips.get(index) + .getInstance() + .setTransform(msLocal); + msLocal.pop(); + } + } + + @Override + public void updateLight() { + super.updateLight(); + + relight(pos, models.stream().map(InstanceKey::getInstance)); } @Override protected InstancedModel getModel() { return AllBlockPartials.ARM_COG.renderOnRotating(modelManager, tile.getBlockState()); } + + @Override + public void remove() { + super.remove(); + models.forEach(InstanceKey::delete); + } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java index 8a869f1b7..3f7f79b68 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java @@ -1,9 +1,5 @@ package com.simibubi.create.content.logistics.block.mechanicalArm; -import java.util.function.Supplier; - -import javax.annotation.Nullable; - import com.google.common.collect.ImmutableMap; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; @@ -25,10 +21,10 @@ import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBe import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.ComposterBlock; 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.MusicDiscItem; @@ -50,10 +46,14 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.wrapper.InvWrapper; + +import javax.annotation.Nullable; +import java.util.function.Supplier; public abstract class ArmInteractionPoint { - static enum Mode { + enum Mode { DEPOSIT, TAKE } @@ -65,20 +65,21 @@ public abstract class ArmInteractionPoint { private ArmAngleTarget cachedAngles; private static ImmutableMap> POINTS = - ImmutableMap.>builder() - .put(new Saw(), Saw::new) - .put(new Belt(), Belt::new) - .put(new Depot(), Depot::new) - .put(new Chute(), Chute::new) - .put(new Basin(), Basin::new) - .put(new Funnel(), Funnel::new) - .put(new Jukebox(), Jukebox::new) - .put(new Crafter(), Crafter::new) - .put(new Deployer(), Deployer::new) - .put(new Millstone(), Millstone::new) - .put(new BlazeBurner(), BlazeBurner::new) - .put(new CrushingWheels(), CrushingWheels::new) - .build(); + ImmutableMap.>builder() + .put(new Saw(), Saw::new) + .put(new Belt(), Belt::new) + .put(new Depot(), Depot::new) + .put(new Chute(), Chute::new) + .put(new Basin(), Basin::new) + .put(new Funnel(), Funnel::new) + .put(new Jukebox(), Jukebox::new) + .put(new Crafter(), Crafter::new) + .put(new Deployer(), Deployer::new) + .put(new Composter(), Composter::new) + .put(new Millstone(), Millstone::new) + .put(new BlazeBurner(), BlazeBurner::new) + .put(new CrushingWheels(), CrushingWheels::new) + .build(); public ArmInteractionPoint() { cachedHandler = LazyOptional.empty(); @@ -118,8 +119,8 @@ public abstract class ArmInteractionPoint { ArmAngleTarget getTargetAngles(BlockPos armPos, boolean ceiling) { if (cachedAngles == null) - cachedAngles = - new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection(), ceiling); + cachedAngles = new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection(), ceiling); + return cachedAngles; } @@ -166,8 +167,7 @@ public abstract class ArmInteractionPoint { for (ArmInteractionPoint armInteractionPoint : POINTS.keySet()) if (armInteractionPoint.isValid(world, pos, state)) - point = POINTS.get(armInteractionPoint) - .get(); + point = POINTS.get(armInteractionPoint).get(); if (point != null) { point.state = state; @@ -222,7 +222,7 @@ public abstract class ArmInteractionPoint { @Override boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) { return AllBlocks.MECHANICAL_SAW.has(state) && state.get(SawBlock.FACING) == Direction.UP - && ((KineticTileEntity) reader.getTileEntity(pos)).getSpeed() != 0; + && ((KineticTileEntity) reader.getTileEntity(pos)).getSpeed() != 0; } } @@ -245,6 +245,25 @@ public abstract class ArmInteractionPoint { } + static class Composter extends TopFaceArmInteractionPoint { + + @Override + Vector3d getInteractionPositionVector() { + return Vector3d.of(pos).add(.5f, 13 / 16f, .5f); + } + + @Override + boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) { + return Blocks.COMPOSTER.equals(state.getBlock()); + } + + @Nullable + @Override + IItemHandler getHandler(World world) { + return new InvWrapper(((ComposterBlock) Blocks.COMPOSTER).createInventory(world.getBlockState(pos), world, pos)); + } + } + static class Deployer extends ArmInteractionPoint { @Override @@ -254,8 +273,7 @@ public abstract class ArmInteractionPoint { @Override Direction getInteractionDirection() { - return state.get(DeployerBlock.FACING) - .getOpposite(); + return state.get(DeployerBlock.FACING).getOpposite(); } @Override @@ -281,15 +299,13 @@ public abstract class ArmInteractionPoint { @Override ItemStack insert(World world, ItemStack stack, boolean simulate) { ItemStack input = stack.copy(); - if (!BlazeBurnerBlock.tryInsert(state, world, pos, input, false, true) - .getResult() - .isEmpty()) { + if (!BlazeBurnerBlock.tryInsert(state, world, pos, input, false, true).getResult().isEmpty()) { return stack; } ActionResult res = BlazeBurnerBlock.tryInsert(state, world, pos, input, false, simulate); return res.getType() == ActionResultType.SUCCESS - ? ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - 1) - : stack; + ? ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - 1) + : stack; } @Override @@ -306,8 +322,7 @@ public abstract class ArmInteractionPoint { @Override Direction getInteractionDirection() { - return state.get(MechanicalCrafterBlock.HORIZONTAL_FACING) - .getOpposite(); + return state.get(MechanicalCrafterBlock.HORIZONTAL_FACING).getOpposite(); } @Override @@ -361,8 +376,7 @@ public abstract class ArmInteractionPoint { return stack; JukeboxBlock jukeboxBlock = (JukeboxBlock) state.getBlock(); JukeboxTileEntity jukeboxTE = (JukeboxTileEntity) tileEntity; - if (!jukeboxTE.getRecord() - .isEmpty()) + if (!jukeboxTE.getRecord().isEmpty()) return stack; if (!(stack.getItem() instanceof MusicDiscItem)) return stack; @@ -370,7 +384,7 @@ public abstract class ArmInteractionPoint { 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())); + world.playEvent(null, 1010, pos, Item.getIdFromItem(toInsert.getItem())); AllTriggers.triggerForNearbyPlayers(AllTriggers.MUSICAL_ARM, world, pos, 10); } return remainder; @@ -401,8 +415,7 @@ public abstract class ArmInteractionPoint { @Override boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) { - return AllBlocks.BELT.has(state) && !(reader.getBlockState(pos.up()) - .getBlock() instanceof BeltTunnelBlock); + return AllBlocks.BELT.has(state) && !(reader.getBlockState(pos.up()).getBlock() instanceof BeltTunnelBlock); } } @@ -435,8 +448,7 @@ public abstract class ArmInteractionPoint { @Override Direction getInteractionDirection() { - return FunnelBlock.getFunnelFacing(state) - .getOpposite(); + return FunnelBlock.getFunnelFacing(state).getOpposite(); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java index 8e9a47e8c..5cffe0e56 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java @@ -7,11 +7,11 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; 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.MatrixStacker; - import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -39,9 +39,26 @@ public class ArmRenderer extends KineticTileEntityRenderer { int overlay) { super.renderSafe(te, pt, ms, buffer, light, overlay); ArmTileEntity arm = (ArmTileEntity) te; + + boolean usingFlywheel = FastRenderDispatcher.available(te.getWorld()); + + ItemStack item = arm.heldItem; + boolean hasItem = !item.isEmpty(); + + if (usingFlywheel && !hasItem) return; + + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + + boolean isBlockItem = hasItem && (item.getItem() instanceof BlockItem) + && itemRenderer.getItemModelWithOverrides(item, Minecraft.getInstance().world, null) + .isGui3d(); + IVertexBuilder builder = buffer.getBuffer(RenderType.getSolid()); BlockState blockState = te.getBlockState(); - MatrixStacker msr = MatrixStacker.of(ms); + + MatrixStack msLocal = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(msLocal); int color = 0xFFFFFF; float baseAngle = arm.baseAngle.get(pt); @@ -50,7 +67,7 @@ public class ArmRenderer extends KineticTileEntityRenderer { float headAngle = arm.headAngle.get(pt); boolean rave = arm.phase == Phase.DANCING; - float renderTick = AnimationTickHolder.getRenderTick() + (te.hashCode() % 64); + float renderTick = AnimationTickHolder.getRenderTime(te.getWorld()) + (te.hashCode() % 64); if (rave) { baseAngle = (renderTick * 10) % 360; lowerArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 4) + 1) / 2, -45, 15); @@ -58,9 +75,34 @@ public class ArmRenderer extends KineticTileEntityRenderer { headAngle = -lowerArmAngle; color = ColorHelper.rainbowColor(AnimationTickHolder.getTicks() * 100); } - - ms.push(); + msr.centre(); + + if (blockState.get(ArmBlock.CEILING)) + msr.rotateX(180); + + if (usingFlywheel) + doItemTransforms(msr, baseAngle, lowerArmAngle, upperArmAngle, headAngle); + else + renderArm(builder, ms, msLocal, msr, blockState, color, baseAngle, lowerArmAngle, upperArmAngle, headAngle, hasItem, isBlockItem, light); + + if (hasItem) { + ms.push(); + float itemScale = isBlockItem ? .5f : .625f; + msr.rotateX(90); + msLocal.translate(0, -4 / 16f, 0); + msLocal.scale(itemScale, itemScale, itemScale); + + ms.peek().getModel().multiply(msLocal.peek().getModel()); + + itemRenderer + .renderItem(item, TransformType.FIXED, light, overlay, ms, buffer); + ms.pop(); + } + + } + + private void renderArm(IVertexBuilder builder, MatrixStack ms, MatrixStack msLocal, MatrixStacker msr, BlockState blockState, int color, float baseAngle, float lowerArmAngle, float upperArmAngle, float headAngle, boolean hasItem, boolean isBlockItem, int light) { SuperByteBuffer base = AllBlockPartials.ARM_BASE.renderOn(blockState).light(light); SuperByteBuffer lowerBody = AllBlockPartials.ARM_LOWER_BODY.renderOn(blockState).light(light); SuperByteBuffer upperBody = AllBlockPartials.ARM_UPPER_BODY.renderOn(blockState).light(light); @@ -68,58 +110,73 @@ public class ArmRenderer extends KineticTileEntityRenderer { SuperByteBuffer claw = AllBlockPartials.ARM_CLAW_BASE.renderOn(blockState).light(light); SuperByteBuffer clawGrip = AllBlockPartials.ARM_CLAW_GRIP.renderOn(blockState); - msr.centre(); - - if (blockState.get(ArmBlock.CEILING)) - msr.rotateX(180); + transformBase(msr, baseAngle); + base.transform(msLocal) + .renderInto(ms, builder); - ms.translate(0, 4 / 16d, 0); - msr.rotateY(baseAngle); - base.renderInto(ms, builder); - - ms.translate(0, 1 / 16d, -2 / 16d); - msr.rotateX(lowerArmAngle); - ms.translate(0, -1 / 16d, 0); + transformLowerArm(msr, lowerArmAngle); lowerBody.color(color) - .renderInto(ms, builder); + .transform(msLocal) + .renderInto(ms, builder); - ms.translate(0, 12 / 16d, 12 / 16d); - msr.rotateX(upperArmAngle); + transformUpperArm(msr, upperArmAngle); upperBody.color(color) + .transform(msLocal) + .renderInto(ms, builder); + + transformHead(msr, headAngle); + head.transform(msLocal) .renderInto(ms, builder); - ms.translate(0, 11 / 16d, -11 / 16d); - msr.rotateX(headAngle); - head.renderInto(ms, builder); + transformClaw(msr); + claw.transform(msLocal) + .renderInto(ms, builder); - ms.translate(0, 0, -4 / 16d); - claw.renderInto(ms, builder); - ItemStack item = arm.heldItem; - ItemRenderer itemRenderer = Minecraft.getInstance() - .getItemRenderer(); - boolean hasItem = !item.isEmpty(); - boolean isBlockItem = hasItem && (item.getItem() instanceof BlockItem) - && itemRenderer.getItemModelWithOverrides(item, Minecraft.getInstance().world, null) - .isGui3d(); - for (int flip : Iterate.positiveAndNegative) { - ms.push(); - ms.translate(0, flip * 3 / 16d, -1 / 16d); - msr.rotateX(flip * (hasItem ? isBlockItem ? 0 : -35 : 0)); - clawGrip.light(light).renderInto(ms, builder); - ms.pop(); + msLocal.push(); + transformClawHalf(msr, hasItem, isBlockItem, flip); + clawGrip.light(light).transform(msLocal).renderInto(ms, builder); + msLocal.pop(); } + } - if (hasItem) { - float itemScale = isBlockItem ? .5f : .625f; - msr.rotateX(90); - ms.translate(0, -4 / 16f, 0); - ms.scale(itemScale, itemScale, itemScale); - itemRenderer - .renderItem(item, TransformType.FIXED, light, overlay, ms, buffer); - } + private void doItemTransforms(MatrixStacker msr, float baseAngle, float lowerArmAngle, float upperArmAngle, float headAngle) { - ms.pop(); + transformBase(msr, baseAngle); + transformLowerArm(msr, lowerArmAngle); + transformUpperArm(msr, upperArmAngle); + transformHead(msr, headAngle); + transformClaw(msr); + } + + public static void transformClawHalf(MatrixStacker msr, boolean hasItem, boolean isBlockItem, int flip) { + msr.translate(0, flip * 3 / 16d, -1 / 16d); + msr.rotateX(flip * (hasItem ? isBlockItem ? 0 : -35 : 0)); + } + + public static void transformClaw(MatrixStacker msr) { + msr.translate(0, 0, -4 / 16d); + } + + public static void transformHead(MatrixStacker msr, float headAngle) { + msr.translate(0, 11 / 16d, -11 / 16d); + msr.rotateX(headAngle); + } + + public static void transformUpperArm(MatrixStacker msr, float upperArmAngle) { + msr.translate(0, 12 / 16d, 12 / 16d); + msr.rotateX(upperArmAngle); + } + + public static void transformLowerArm(MatrixStacker msr, float lowerArmAngle) { + msr.translate(0, 1 / 16d, -2 / 16d); + msr.rotateX(lowerArmAngle); + msr.translate(0, -1 / 16d, 0); + } + + public static void transformBase(MatrixStacker msr, float baseAngle) { + msr.translate(0, 4 / 16d, 0); + msr.rotateY(baseAngle); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java index 813b899cd..930de6e3f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java @@ -1,10 +1,5 @@ package com.simibubi.create.content.logistics.block.mechanicalArm; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nullable; - 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; @@ -21,7 +16,6 @@ import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.block.JukeboxBlock; import net.minecraft.item.ItemStack; @@ -38,6 +32,10 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.util.Constants.NBT; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + public class ArmTileEntity extends KineticTileEntity { // Server @@ -78,12 +76,16 @@ public class ArmTileEntity extends KineticTileEntity { interactionPointTag = new ListNBT(); heldItem = ItemStack.EMPTY; phase = Phase.SEARCH_INPUTS; - baseAngle = new InterpolatedAngle(); - lowerArmAngle = new InterpolatedAngle(); - upperArmAngle = new InterpolatedAngle(); - headAngle = new InterpolatedAngle(); - clawAngle = new InterpolatedAngle(); previousTarget = ArmAngleTarget.NO_TARGET; + baseAngle = new InterpolatedAngle(); + baseAngle.set(previousTarget.baseAngle); + lowerArmAngle = new InterpolatedAngle(); + lowerArmAngle.set(previousTarget.lowerArmAngle); + upperArmAngle = new InterpolatedAngle(); + upperArmAngle.set(previousTarget.upperArmAngle); + headAngle = new InterpolatedAngle(); + headAngle.set(previousTarget.headAngle); + clawAngle = new InterpolatedAngle(); previousBaseAngle = previousTarget.baseAngle; updateInteractionPoints = true; redstoneLocked = false; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverInstance.java new file mode 100644 index 000000000..99680aac1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverInstance.java @@ -0,0 +1,88 @@ +package com.simibubi.create.content.logistics.block.redstone; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.state.properties.AttachFace; +import net.minecraft.util.Direction; + +public class AnalogLeverInstance extends TileEntityInstance implements ITickableInstance { + + protected InstanceKey handle; + protected InstanceKey indicator; + + private float rX; + private float rY; + + public AnalogLeverInstance(InstancedTileRenderer modelManager, AnalogLeverTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + RenderMaterial> mat = modelManager.getMaterial(RenderMaterials.MODELS); + + handle = mat.getModel(AllBlockPartials.ANALOG_LEVER_HANDLE, lastState).createInstance(); + indicator = mat.getModel(AllBlockPartials.ANALOG_LEVER_INDICATOR, lastState).createInstance(); + + AttachFace face = lastState.get(AnalogLeverBlock.FACE); + rX = face == AttachFace.FLOOR ? 0 : face == AttachFace.WALL ? 90 : 180; + rY = AngleHelper.horizontalAngle(lastState.get(AnalogLeverBlock.HORIZONTAL_FACING)); + + setupModel(); + updateLight(); + } + + @Override + public void tick() { + if (!tile.clientState.settled()) + setupModel(); + } + + protected void setupModel() { + MatrixStack ms = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(ms); + + msr.translate(getFloatingPos()); + transform(msr); + + float state = tile.clientState.get(AnimationTickHolder.getPartialTicks()); + + int color = ColorHelper.mixColors(0x2C0300, 0xCD0000, state / 15f); + indicator.getInstance() + .setTransform(ms) + .setColor(color); + + float angle = (float) ((state / 15) * 90 / 180 * Math.PI); + msr.translate(1 / 2f, 1 / 16f, 1 / 2f) + .rotate(Direction.EAST, angle) + .translate(-1 / 2f, -1 / 16f, -1 / 2f); + + handle.getInstance() + .setTransformNoCopy(ms); + } + + @Override + public void remove() { + handle.delete(); + indicator.delete(); + } + + @Override + public void updateLight() { + relight(pos, handle.getInstance(), indicator.getInstance()); + } + + private void transform(MatrixStacker msr) { + msr.centre() + .rotate(Direction.UP, (float) (rY / 180 * Math.PI)) + .rotate(Direction.EAST, (float) (rX / 180 * Math.PI)) + .unCentre(); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java index 7ed7acc93..54f71a879 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java @@ -4,10 +4,10 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.ColorHelper; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -25,6 +25,9 @@ public class AnalogLeverRenderer extends SafeTileEntityRenderer, IWrenchable { public static final BooleanProperty POWERED = BlockStateProperties.POWERED; @@ -129,6 +129,14 @@ public class ContentObserverBlock extends HorizontalBlock implements ITE extends AbstractSimiContainerScreen { protected AllGuiTextures background; + private List extraAreas = Collections.EMPTY_LIST; private IconButton resetButton; private IconButton confirmButton; @@ -39,14 +41,15 @@ public abstract class AbstractFilterScreen ex @Override protected void init() { - setWindowSize(background.width + 80, background.height + PLAYER_INVENTORY.height + 20); + setWindowSize(PLAYER_INVENTORY.width, background.height + PLAYER_INVENTORY.height + 20); super.init(); widgets.clear(); + int x = guiLeft - 50; + int offset = guiTop < 30 ? 30 - guiTop : 0; + extraAreas = ImmutableList.of(new Rectangle2d(x, guiTop + offset, background.width + 70, background.height - offset)); - resetButton = - new IconButton(guiLeft + background.width - 62, guiTop + background.height - 24, AllIcons.I_TRASH); - confirmButton = - new IconButton(guiLeft + background.width - 33, guiTop + background.height - 24, AllIcons.I_CONFIRM); + resetButton = new IconButton(x + background.width - 62, guiTop + background.height - 24, AllIcons.I_TRASH); + confirmButton = new IconButton(x + background.width - 33, guiTop + background.height - 24, AllIcons.I_CONFIRM); widgets.add(resetButton); widgets.add(confirmButton); @@ -54,20 +57,20 @@ public abstract class AbstractFilterScreen ex @Override protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { - int x = guiLeft; + int x = guiLeft - 50; int y = guiTop; background.draw(ms, this, x, y); - int invX = x + 50; + int invX = guiLeft; int invY = y + background.height + 10; PLAYER_INVENTORY.draw(ms, this, invX, invY); textRenderer.draw(ms, playerInventory.getDisplayName(), invX + 7, invY + 6, 0x666666); textRenderer.draw(ms, I18n.format(container.filterItem.getTranslationKey()), x + 15, y + 3, 0xdedede); GuiGameElement.of(container.filterItem) - .at(guiLeft + background.width, guiTop + background.height + 25, -150) - .scale(5) - .render(ms); + .at(x + background.width, guiTop + background.height - 60) + .scale(5) + .render(ms); } @@ -156,4 +159,8 @@ public abstract class AbstractFilterScreen ex AllPackets.channel.sendToServer(new FilterScreenPacket(option)); } + @Override + public List getExtraAreas() { + return extraAreas; + } } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java index 0f8204619..c4a16244e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java @@ -1,11 +1,7 @@ package com.simibubi.create.content.logistics.item.filter; -import java.util.ArrayList; -import java.util.List; - import com.simibubi.create.AllContainerTypes; import com.simibubi.create.foundation.utility.Pair; - import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.ClickType; @@ -21,6 +17,9 @@ import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.SlotItemHandler; +import java.util.ArrayList; +import java.util.List; + public class AttributeFilterContainer extends AbstractFilterContainer { public enum WhitelistMode { @@ -62,8 +61,8 @@ public class AttributeFilterContainer extends AbstractFilterContainer { } protected void addFilterSlots() { - this.addSlot(new SlotItemHandler(filterInventory, 0, 16, 22)); - this.addSlot(new SlotItemHandler(filterInventory, 1, 22, 57) { + this.addSlot(new SlotItemHandler(filterInventory, 0, -34, 22)); + this.addSlot(new SlotItemHandler(filterInventory, 1, -28, 57) { @Override public boolean canTakeStack(PlayerEntity playerIn) { return false; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java index aab75d2ff..862df6ed6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java @@ -1,10 +1,5 @@ package com.simibubi.create.content.logistics.item.filter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.logistics.item.filter.AttributeFilterContainer.WhitelistMode; import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket.Option; @@ -17,7 +12,6 @@ import com.simibubi.create.foundation.gui.widgets.SelectionScrollInput; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Pair; - import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; @@ -26,6 +20,11 @@ import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + public class AttributeFilterScreen extends AbstractFilterScreen { private static final String PREFIX = "gui.attribute_filter."; @@ -62,7 +61,7 @@ public class AttributeFilterScreen extends AbstractFilterScreen { + + private final boolean inwards; + + public FunnelFlapPacket(PacketBuffer buffer) { + super(buffer); + + inwards = buffer.readBoolean(); + } + + public FunnelFlapPacket(FunnelTileEntity tile, boolean inwards) { + super(tile.getPos()); + this.inwards = inwards; + } + + @Override + protected void writeData(PacketBuffer buffer) { + buffer.writeBoolean(inwards); + } + + @Override + protected void handlePacket(FunnelTileEntity tile) { + tile.flap(inwards); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/packet/TunnelFlapPacket.java b/src/main/java/com/simibubi/create/content/logistics/packet/TunnelFlapPacket.java new file mode 100644 index 000000000..4661ad804 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/packet/TunnelFlapPacket.java @@ -0,0 +1,53 @@ +package com.simibubi.create.content.logistics.packet; + +import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity; +import com.simibubi.create.foundation.networking.TileEntityDataPacket; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.Direction; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.List; + +public class TunnelFlapPacket extends TileEntityDataPacket { + + private List> flaps; + + public TunnelFlapPacket(PacketBuffer buffer) { + super(buffer); + + byte size = buffer.readByte(); + + this.flaps = new ArrayList<>(size); + + for (int i = 0; i < size; i++) { + Direction direction = Direction.byIndex(buffer.readByte()); + boolean inwards = buffer.readBoolean(); + + flaps.add(Pair.of(direction, inwards)); + } + } + + public TunnelFlapPacket(BeltTunnelTileEntity tile, List> flaps) { + super(tile.getPos()); + + this.flaps = new ArrayList<>(flaps); + } + + @Override + protected void writeData(PacketBuffer buffer) { + buffer.writeByte(flaps.size()); + + for (Pair flap : flaps) { + buffer.writeByte(flap.getLeft().getIndex()); + buffer.writeBoolean(flap.getRight()); + } + } + + @Override + protected void handlePacket(BeltTunnelTileEntity tile) { + for (Pair flap : flaps) { + tile.flap(flap.getLeft(), flap.getRight()); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/schematics/ClientSchematicLoader.java b/src/main/java/com/simibubi/create/content/schematics/ClientSchematicLoader.java index 1d37c5358..847f69773 100644 --- a/src/main/java/com/simibubi/create/content/schematics/ClientSchematicLoader.java +++ b/src/main/java/com/simibubi/create/content/schematics/ClientSchematicLoader.java @@ -1,26 +1,11 @@ package com.simibubi.create.content.schematics; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - import com.simibubi.create.Create; import com.simibubi.create.content.schematics.packet.SchematicUploadPacket; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.FilesHelper; import com.simibubi.create.foundation.utility.Lang; - import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.util.text.ITextComponent; @@ -28,6 +13,11 @@ import net.minecraft.util.text.StringTextComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.*; +import java.util.*; + @OnlyIn(Dist.CLIENT) public class ClientSchematicLoader { @@ -145,6 +135,58 @@ public class ClientSchematicLoader { e.printStackTrace(); } + availableSchematics.sort((aT, bT) -> { + String a = aT.getString(); + String b = bT.getString(); + if (a.endsWith(".nbt")) + a = a.substring(0, a.length() - 4); + if (b.endsWith(".nbt")) + b = b.substring(0, b.length() - 4); + int aLength = a.length(); + int bLength = b.length(); + int minSize = Math.min(aLength, bLength); + char aChar, bChar; + boolean aNumber, bNumber; + boolean asNumeric = false; + int lastNumericCompare = 0; + for (int i = 0; i < minSize; i++) { + aChar = a.charAt(i); + bChar = b.charAt(i); + aNumber = aChar >= '0' && aChar <= '9'; + bNumber = bChar >= '0' && bChar <= '9'; + if (asNumeric) + if (aNumber && bNumber) { + if (lastNumericCompare == 0) + lastNumericCompare = aChar - bChar; + } else if (aNumber) + return 1; + else if (bNumber) + return -1; + else if (lastNumericCompare == 0) { + if (aChar != bChar) + return aChar - bChar; + asNumeric = false; + } else + return lastNumericCompare; + else if (aNumber && bNumber) { + asNumeric = true; + if (lastNumericCompare == 0) + lastNumericCompare = aChar - bChar; + } else if (aChar != bChar) + return aChar - bChar; + } + if (asNumeric) + if (aLength > bLength && a.charAt(bLength) >= '0' && a.charAt(bLength) <= '9') // as number + return 1; // a has bigger size, thus b is smaller + else if (bLength > aLength && b.charAt(aLength) >= '0' && b.charAt(aLength) <= '9') // as number + return -1; // b has bigger size, thus a is smaller + else if (lastNumericCompare == 0) + return aLength - bLength; + else + return lastNumericCompare; + else + return aLength - bLength; + }); } public List getAvailableSchematics() { diff --git a/src/main/java/com/simibubi/create/content/schematics/SchematicWorld.java b/src/main/java/com/simibubi/create/content/schematics/SchematicWorld.java index 143c4a2ef..dbc4ad82e 100644 --- a/src/main/java/com/simibubi/create/content/schematics/SchematicWorld.java +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicWorld.java @@ -1,18 +1,8 @@ package com.simibubi.create.content.schematics; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Stream; - import com.simibubi.create.Create; -import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; - +import net.minecraft.block.AbstractFurnaceBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -27,29 +17,30 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MutableBoundingBox; -import net.minecraft.world.EmptyTickList; -import net.minecraft.world.IServerWorld; -import net.minecraft.world.ITickList; -import net.minecraft.world.LightType; -import net.minecraft.world.World; +import net.minecraft.world.*; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.BiomeRegistry; import net.minecraft.world.server.ServerWorld; +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Stream; + public class SchematicWorld extends WrappedWorld implements IServerWorld { - private Map blocks; - private Map tileEntities; - private List renderedTileEntities; - private List entities; - private MutableBoundingBox bounds; + protected Map blocks; + protected Map tileEntities; + protected List renderedTileEntities; + protected List entities; + protected MutableBoundingBox bounds; + public BlockPos anchor; public boolean renderMode; public SchematicWorld(World original) { this(BlockPos.ZERO, original); } - + public SchematicWorld(BlockPos anchor, World original) { super(original); this.blocks = new HashMap<>(); @@ -114,12 +105,8 @@ public class SchematicWorld extends WrappedWorld implements IServerWorld { if (pos.getY() - bounds.minY == -1 && !renderMode) return Blocks.GRASS_BLOCK.getDefaultState(); - if (getBounds().isVecInside(pos) && blocks.containsKey(pos)) { - BlockState blockState = blocks.get(pos); - if (BlockHelper.hasBlockStateProperty(blockState, BlockStateProperties.LIT)) - blockState = blockState.with(BlockStateProperties.LIT, false); - return blockState; - } + if (getBounds().isVecInside(pos) && blocks.containsKey(pos)) + return processBlockStateForPrinting(blocks.get(pos)); return Blocks.AIR.getDefaultState(); } @@ -180,9 +167,23 @@ public class SchematicWorld extends WrappedWorld implements IServerWorld { @Override public boolean setBlockState(BlockPos pos, BlockState arg1, int arg2) { - pos = pos.subtract(anchor); + pos = pos.toImmutable() + .subtract(anchor); bounds.expandTo(new MutableBoundingBox(pos, pos)); blocks.put(pos, arg1); + if (tileEntities.containsKey(pos)) { + TileEntity tileEntity = tileEntities.get(pos); + if (!tileEntity.getType() + .isValidBlock(arg1.getBlock())) { + tileEntities.remove(pos); + renderedTileEntities.remove(tileEntity); + } + } + + TileEntity tileEntity = getTileEntity(pos); + if (tileEntity != null) + tileEntities.put(pos, tileEntity); + return true; } @@ -204,6 +205,12 @@ public class SchematicWorld extends WrappedWorld implements IServerWorld { return renderedTileEntities; } + protected BlockState processBlockStateForPrinting(BlockState state) { + if (state.getBlock() instanceof AbstractFurnaceBlock && state.contains(BlockStateProperties.LIT)) + state = state.with(BlockStateProperties.LIT, false); + return state; + } + @Override public ServerWorld getWorld() { if (this.world instanceof ServerWorld) { diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java index 95bc3f84d..dd11d7d37 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java @@ -1,11 +1,5 @@ package com.simibubi.create.content.schematics.block; -import static com.simibubi.create.foundation.gui.AllGuiTextures.SCHEMATIC_TABLE; -import static com.simibubi.create.foundation.gui.AllGuiTextures.SCHEMATIC_TABLE_PROGRESS; - -import java.nio.file.Paths; -import java.util.List; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllBlocks; @@ -20,8 +14,8 @@ import com.simibubi.create.foundation.gui.widgets.Label; import com.simibubi.create.foundation.gui.widgets.ScrollInput; import com.simibubi.create.foundation.gui.widgets.SelectionScrollInput; import com.simibubi.create.foundation.utility.Lang; - import net.minecraft.client.gui.IHasContainer; +import net.minecraft.client.renderer.Rectangle2d; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.util.Util; @@ -29,6 +23,13 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import static com.simibubi.create.foundation.gui.AllGuiTextures.SCHEMATIC_TABLE; +import static com.simibubi.create.foundation.gui.AllGuiTextures.SCHEMATIC_TABLE_PROGRESS; + public class SchematicTableScreen extends AbstractSimiContainerScreen implements IHasContainer { @@ -37,6 +38,7 @@ public class SchematicTableScreen extends AbstractSimiContainerScreen extraAreas; private final ITextComponent title = Lang.translate("gui.schematicTable.title"); private final ITextComponent uploading = Lang.translate("gui.schematicTable.uploading"); @@ -89,6 +91,9 @@ public class SchematicTableScreen extends AbstractSimiContainerScreen(); + extraAreas.add(new Rectangle2d(mainLeft, mainTop, SCHEMATIC_TABLE.width, SCHEMATIC_TABLE.height)); } @Override @@ -208,4 +213,8 @@ public class SchematicTableScreen extends AbstractSimiContainerScreen getExtraAreas() { + return extraAreas; + } } diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlock.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlock.java index b67ed740b..b04e43335 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlock.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlock.java @@ -4,7 +4,6 @@ import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.item.ItemHelper; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.material.PushReaction; @@ -71,4 +70,10 @@ public class SchematicannonBlock extends Block implements ITE te.neighbourCheckCooldown = 0); + } + } diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInstance.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInstance.java new file mode 100644 index 000000000..d549ab9ec --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInstance.java @@ -0,0 +1,74 @@ +package com.simibubi.create.content.schematics.block; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.foundation.render.backend.RenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.util.Direction; + +public class SchematicannonInstance extends TileEntityInstance implements ITickableInstance { + + private InstanceKey connector; + private InstanceKey pipe; + + public SchematicannonInstance(InstancedTileRenderer modelManager, SchematicannonTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + + RenderMaterial> mat = modelManager.getMaterial(RenderMaterials.MODELS); + + connector = mat.getModel(AllBlockPartials.SCHEMATICANNON_CONNECTOR, lastState).createInstance(); + pipe = mat.getModel(AllBlockPartials.SCHEMATICANNON_PIPE, lastState).createInstance(); + + updateLight(); + } + + @Override + public void tick() { + float partialTicks = AnimationTickHolder.getPartialTicks(); + + double[] cannonAngles = SchematicannonRenderer.getCannonAngles(tile, pos, partialTicks); + + double pitch = cannonAngles[0]; + double yaw = cannonAngles[1]; + + double recoil = SchematicannonRenderer.getRecoil(tile, partialTicks); + + MatrixStack ms = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(ms); + + msr.translate(getFloatingPos()); + + ms.push(); + msr.centre(); + msr.rotate(Direction.UP, (float) ((yaw + 90) / 180 * Math.PI)); + msr.unCentre(); + connector.getInstance().setTransform(ms); + ms.pop(); + + msr.translate(.5f, 15 / 16f, .5f); + msr.rotate(Direction.UP, (float) ((yaw + 90) / 180 * Math.PI)); + msr.rotate(Direction.SOUTH, (float) (pitch / 180 * Math.PI)); + msr.translate(-.5f, -15 / 16f, -.5f); + msr.translate(0, -recoil / 100, 0); + + pipe.getInstance().setTransformNoCopy(ms); + } + + @Override + public void remove() { + connector.delete(); + pipe.delete(); + } + + @Override + public void updateLight() { + relight(pos, connector.getInstance(), pipe.getInstance()); + } +} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java index 0dc7af321..b1b66da25 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java @@ -1,15 +1,13 @@ package com.simibubi.create.content.schematics.block; -import java.util.Random; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.schematics.block.LaunchedItem.ForBlockState; import com.simibubi.create.content.schematics.block.LaunchedItem.ForEntity; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -25,6 +23,8 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3f; import net.minecraftforge.client.model.data.EmptyModelData; +import java.util.Random; + public class SchematicannonRenderer extends SafeTileEntityRenderer { public SchematicannonRenderer(TileEntityRendererDispatcher dispatcher) { @@ -40,105 +40,20 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer launched.totalTicks - 10) - recoil = Math.max(recoil, (launched.ticksRemaining + 1 - partialTicks) - launched.totalTicks + 10); - - // Render particles for launch - if (launched.ticksRemaining == launched.totalTicks && tileEntityIn.firstRenderTick) { - tileEntityIn.firstRenderTick = false; - for (int i = 0; i < 10; i++) { - Random r = tileEntityIn.getWorld().getRandom(); - double sX = cannonOffset.x * .01f; - double sY = (cannonOffset.y + 1) * .01f; - double sZ = cannonOffset.z * .01f; - double rX = r.nextFloat() - sX * 40; - double rY = r.nextFloat() - sY * 40; - double rZ = r.nextFloat() - sZ * 40; - tileEntityIn.getWorld().addParticle(ParticleTypes.CLOUD, start.x + rX, start.y + rY, - start.z + rZ, sX, sY, sZ); - } - } - - } - } + double recoil = getRecoil(tileEntityIn, partialTicks); ms.push(); BlockState state = tileEntityIn.getBlockState(); @@ -163,4 +78,115 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer launched.totalTicks - 10) + recoil = Math.max(recoil, (launched.ticksRemaining + 1 - partialTicks) - launched.totalTicks + 10); + } + + return recoil; + } + + private static void renderLaunchedBlocks(SchematicannonTileEntity tileEntityIn, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + for (LaunchedItem launched : tileEntityIn.flyingBlocks) { + + if (launched.ticksRemaining == 0) + continue; + + // Calculate position of flying block + Vector3d start = Vector3d.of(tileEntityIn.getPos().add(.5f, 1, .5f)); + Vector3d target = Vector3d.of(launched.target).add(-.5, 0, 1); + Vector3d distance = target.subtract(start); + + double targetY = target.y - start.y; + double throwHeight = Math.sqrt(distance.lengthSquared()) * .6f + targetY; + Vector3d cannonOffset = distance.add(0, throwHeight, 0).normalize().scale(2); + start = start.add(cannonOffset); + + float progress = + ((float) launched.totalTicks - (launched.ticksRemaining + 1 - partialTicks)) / launched.totalTicks; + Vector3d blockLocationXZ = new Vector3d(.5, .5, .5).add(target.subtract(start).scale(progress).mul(1, 0, 1)); + + // Height is determined through a bezier curve + float t = progress; + double yOffset = 2 * (1 - t) * t * throwHeight + t * t * targetY; + Vector3d blockLocation = blockLocationXZ.add(0, yOffset + 1, 0).add(cannonOffset); + + // Offset to position + ms.push(); + ms.translate(blockLocation.x, blockLocation.y, blockLocation.z); + + ms.multiply(new Vector3f(0, 1, 0).getDegreesQuaternion(360 * t * 2)); + ms.multiply(new Vector3f(1, 0, 0).getDegreesQuaternion(360 * t * 2)); + + // Render the Block + if (launched instanceof ForBlockState) { + float scale = .3f; + ms.scale(scale, scale, scale); + Minecraft.getInstance().getBlockRendererDispatcher().renderBlock(((ForBlockState) launched).state, ms, buffer, light, overlay, EmptyModelData.INSTANCE); + } + + // Render the item + if (launched instanceof ForEntity) { + float scale = 1.2f; + ms.scale(scale, scale, scale); + Minecraft.getInstance().getItemRenderer().renderItem(launched.stack, TransformType.GROUND, light, overlay, ms, buffer); + } + + ms.pop(); + + // Render particles for launch + if (launched.ticksRemaining == launched.totalTicks && tileEntityIn.firstRenderTick) { + tileEntityIn.firstRenderTick = false; + for (int i = 0; i < 10; i++) { + Random r = tileEntityIn.getWorld().getRandom(); + double sX = cannonOffset.x * .01f; + double sY = (cannonOffset.y + 1) * .01f; + double sZ = cannonOffset.z * .01f; + double rX = r.nextFloat() - sX * 40; + double rY = r.nextFloat() - sY * 40; + double rZ = r.nextFloat() - sZ * 40; + tileEntityIn.getWorld().addParticle(ParticleTypes.CLOUD, start.x + rX, start.y + rY, + start.z + rZ, sX, sY, sZ); + } + } + + } + } + } diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java index b402ea977..ad30fafb4 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java @@ -1,11 +1,5 @@ package com.simibubi.create.content.schematics.block; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; @@ -24,12 +18,12 @@ import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.CSchematics; import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; +import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.NBTProcessors; - import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.PistonHeadBlock; @@ -67,8 +61,15 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.wrapper.EmptyHandler; -public class SchematicannonTileEntity extends SmartTileEntity implements INamedContainerProvider { +import javax.annotation.Nullable; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +public class SchematicannonTileEntity extends SmartTileEntity implements INamedContainerProvider, IInstanceRendered { public static final int NEIGHBOUR_CHECKING = 100; public static final int MAX_ANCHOR_DISTANCE = 256; @@ -100,7 +101,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC public BlockPos target; public BlockPos previousTarget; - public List attachedInventories; + public LinkedHashSet> attachedInventories; public List flyingBlocks; public MaterialChecklist checklist; @@ -135,14 +136,13 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC public SchematicannonTileEntity(TileEntityType tileEntityTypeIn) { super(tileEntityTypeIn); setLazyTickRate(30); - attachedInventories = new LinkedList<>(); + attachedInventories = new LinkedHashSet<>(); flyingBlocks = new LinkedList<>(); inventory = new SchematicannonInventory(this); statusMsg = "idle"; state = State.STOPPED; printingEntityIndex = -1; replaceMode = 2; - neighbourCheckCooldown = NEIGHBOUR_CHECKING; checklist = new MaterialChecklist(); } @@ -162,7 +162,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC LazyOptional capability = tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()); if (capability.isPresent()) { - attachedInventories.add(capability.orElse(null)); + attachedInventories.add(capability); } } } @@ -286,7 +286,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC public void tick() { super.tick(); - if (neighbourCheckCooldown-- <= 0) { + if (state != State.STOPPED && neighbourCheckCooldown-- <= 0) { neighbourCheckCooldown = NEIGHBOUR_CHECKING; findInventories(); } @@ -575,9 +575,12 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC if (hasCreativeCrate) return true; + attachedInventories.removeIf(cap -> !cap.isPresent()); + // Find and apply damage if (usage == ItemUseType.DAMAGE) { - for (IItemHandler iItemHandler : attachedInventories) { + for (LazyOptional cap : attachedInventories) { + IItemHandler iItemHandler = cap.orElse(EmptyHandler.INSTANCE); for (int slot = 0; slot < iItemHandler.getSlots(); slot++) { ItemStack extractItem = iItemHandler.extractItem(slot, 1, true); if (!ItemRequirement.validate(required, extractItem)) @@ -606,8 +609,8 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC boolean success = false; if (usage == ItemUseType.CONSUME) { int amountFound = 0; - for (IItemHandler iItemHandler : attachedInventories) { - + for (LazyOptional cap : attachedInventories) { + IItemHandler iItemHandler = cap.orElse(EmptyHandler.INSTANCE); amountFound += ItemHelper .extract(iItemHandler, s -> ItemRequirement.validate(required, s), ExtractionCountMode.UPTO, required.getCount(), true) @@ -623,7 +626,8 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC if (!simulate && success) { int amountFound = 0; - for (IItemHandler iItemHandler : attachedInventories) { + for (LazyOptional cap : attachedInventories) { + IItemHandler iItemHandler = cap.orElse(EmptyHandler.INSTANCE); amountFound += ItemHelper .extract(iItemHandler, s -> ItemRequirement.validate(required, s), ExtractionCountMode.UPTO, required.getCount(), false) @@ -915,7 +919,11 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC } checklist.gathered.clear(); - for (IItemHandler inventory : attachedInventories) { + findInventories(); + for (LazyOptional cap : attachedInventories) { + if (!cap.isPresent()) + continue; + IItemHandler inventory = cap.orElse(EmptyHandler.INSTANCE); for (int slot = 0; slot < inventory.getSlots(); slot++) { ItemStack stackInSlot = inventory.getStackInSlot(slot); if (inventory.extractItem(slot, 1, true) @@ -936,4 +944,8 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC findInventories(); } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java index d8ca648d3..581a00cd1 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java @@ -1,21 +1,11 @@ package com.simibubi.create.content.schematics.client; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.lwjgl.opengl.GL11; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.schematics.SchematicWorld; import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.TileEntityRenderHelper; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.utility.MatrixStacker; - import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BlockRendererDispatcher; @@ -23,9 +13,13 @@ import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderTypeLookup; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.model.data.EmptyModelData; +import org.lwjgl.opengl.GL11; + +import java.util.*; public class SchematicRenderer { @@ -110,8 +104,12 @@ public class SchematicRenderer { BufferBuilder bufferBuilder = buffers.get(blockRenderLayer); if (startedBufferBuilders.add(blockRenderLayer)) bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); + + TileEntity tileEntity = blockAccess.getTileEntity(localPos); + if (blockRendererDispatcher.renderModel(state, pos, blockAccess, ms, bufferBuilder, true, - minecraft.world.rand, EmptyModelData.INSTANCE)) { + minecraft.world.rand, + tileEntity != null ? tileEntity.getModelData() : EmptyModelData.INSTANCE)) { usedBlockRenderLayers.add(blockRenderLayer); } blockstates.add(state); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java index 996d7937c..449ef1b7d 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java @@ -7,7 +7,6 @@ import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.outliner.AABBOutline; - import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTUtil; import net.minecraft.util.math.AxisAlignedBB; @@ -67,7 +66,7 @@ public class DeployTool extends PlacementToolBase { .translateBack(origin); AABBOutline outline = schematicHandler.getOutline(); - outline.render(ms, buffer); + outline.render(ms, buffer, pt); outline.getParams() .clearTextures(); ms.pop(); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/FlipTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/FlipTool.java index e77b7c35e..efacf8ba2 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/FlipTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/FlipTool.java @@ -3,8 +3,8 @@ package com.simibubi.create.content.schematics.client.tools; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.outliner.AABBOutline; - import net.minecraft.util.Direction; import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.math.AxisAlignedBB; @@ -74,7 +74,7 @@ public class FlipTool extends PlacementToolBase { .disableNormals() .colored(0xdddddd) .withFaceTextures(tex, tex); - outline.render(ms, buffer); + outline.render(ms, buffer, AnimationTickHolder.getPartialTicks()); super.renderOnSchematic(ms, buffer); } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/RotateTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/RotateTool.java index e76135f63..4cd4859f2 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/RotateTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/RotateTool.java @@ -2,8 +2,8 @@ package com.simibubi.create.content.schematics.client.tools; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.outliner.LineOutline; - import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.vector.Vector3d; @@ -35,7 +35,7 @@ public class RotateTool extends PlacementToolBase { .colored(0xdddddd) .lineWidth(1 / 16f); line.set(start, end) - .render(ms, buffer); + .render(ms, buffer, AnimationTickHolder.getPartialTicks()); super.renderOnSchematic(ms, buffer); } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java index 7133cbb8e..0e8ca4ef2 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java @@ -1,8 +1,5 @@ package com.simibubi.create.content.schematics.client.tools; -import java.util.Arrays; -import java.util.List; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllKeys; import com.simibubi.create.AllSpecialTextures; @@ -15,7 +12,6 @@ import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.outliner.AABBOutline; - import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -26,6 +22,9 @@ import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.vector.Vector3d; +import java.util.Arrays; +import java.util.List; + public abstract class SchematicToolBase implements ISchematicTool { protected SchematicHandler schematicHandler; @@ -143,7 +142,7 @@ public abstract class SchematicToolBase implements ISchematicTool { .colored(0x6886c5) .withFaceTexture(AllSpecialTextures.CHECKERED) .lineWidth(1 / 16f); - outline.render(ms, buffer); + outline.render(ms, buffer, AnimationTickHolder.getPartialTicks()); outline.getParams() .clearTextures(); ms.pop(); diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index ecb20279b..752831763 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -1,8 +1,5 @@ package com.simibubi.create.events; -import java.util.ArrayList; -import java.util.List; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllFluids; @@ -17,6 +14,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.tra import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; import com.simibubi.create.content.contraptions.components.turntable.TurntableHandler; +import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorHandler; import com.simibubi.create.content.curiosities.tools.ExtendoGripRenderHandler; import com.simibubi.create.content.curiosities.zapper.ZapperItem; @@ -25,21 +23,22 @@ import com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperRen import com.simibubi.create.content.curiosities.zapper.terrainzapper.WorldshaperRenderHandler; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPointHandler; import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.LeftClickPacket; +import com.simibubi.create.foundation.ponder.PonderTooltipHandler; +import com.simibubi.create.foundation.render.KineticRenderer; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.render.backend.RenderWork; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer; import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkRenderer; +import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueHandler; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueRenderer; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.ServerSpeedProvider; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; - import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -56,6 +55,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.EntityViewRenderEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType; +import net.minecraftforge.client.event.RenderTooltipEvent; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.event.TickEvent.ClientTickEvent; import net.minecraftforge.event.TickEvent.Phase; @@ -66,6 +66,9 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import java.util.ArrayList; +import java.util.List; + @EventBusSubscriber(value = Dist.CLIENT) public class ClientEvents { @@ -83,6 +86,7 @@ public class ClientEvents { AnimationTickHolder.tick(); FastRenderDispatcher.tick(); + ScrollValueHandler.tick(); CreateClient.schematicSender.tick(); CreateClient.schematicAndQuillHandler.tick(); @@ -92,7 +96,8 @@ public class ClientEvents { CapabilityMinecartController.tick(world); CouplingPhysics.tick(world); - ScreenOpener.tick(); + PonderTooltipHandler.tick(); + //ScreenOpener.tick(); ServerSpeedProvider.clientTick(); BeltConnectorHandler.tick(); FilteringRenderer.tick(); @@ -121,14 +126,23 @@ public class ClientEvents { if (world.isRemote() && world instanceof ClientWorld) { CreateClient.invalidateRenderers(); AnimationTickHolder.reset(); - ((ClientWorld) world).loadedTileEntityList.forEach(CreateClient.kineticRenderer::add); + KineticRenderer renderer = CreateClient.kineticRenderer.get(world); + renderer.invalidate(); + ((ClientWorld) world).loadedTileEntityList.forEach(renderer::add); } + + /* + i was getting nullPointers when trying to call this during client setup, + so i assume minecraft's language manager isn't yet fully loaded at that time. + not sure where else to call this tho :S + */ + IHaveGoggleInformation.numberFormat.update(); } @SubscribeEvent public static void onUnloadWorld(WorldEvent.Unload event) { if (event.getWorld().isRemote()) { - CreateClient.invalidateRenderers(); + CreateClient.invalidateRenderers(event.getWorld()); AnimationTickHolder.reset(); } } @@ -136,6 +150,7 @@ public class ClientEvents { @SubscribeEvent public static void onRenderWorld(RenderWorldLastEvent event) { Vector3d cameraPos = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); + float pt = AnimationTickHolder.getPartialTicks(); MatrixStack ms = event.getMatrixStack(); ms.push(); @@ -146,9 +161,8 @@ public class ClientEvents { CreateClient.schematicHandler.render(ms, buffer); CreateClient.ghostBlocks.renderAll(ms, buffer); - CreateClient.outliner.renderOutlines(ms, buffer); + CreateClient.outliner.renderOutlines(ms, buffer, pt); // LightVolumeDebugger.render(ms, buffer); -// CollisionDebugger.render(ms, buffer); buffer.draw(); RenderSystem.enableCull(); @@ -172,6 +186,11 @@ public class ClientEvents { CreateClient.schematicHandler.renderOverlay(ms, buffer, light, overlay, partialTicks); } + @SubscribeEvent + public static void getItemTooltipColor(RenderTooltipEvent.Color event) { + PonderTooltipHandler.handleTooltipColor(event); + } + @SubscribeEvent public static void addToItemTooltip(ItemTooltipEvent event) { if (!AllConfigs.CLIENT.tooltips.get()) @@ -194,6 +213,7 @@ public class ClientEvents { itemTooltip.addAll(0, toolTip); } + PonderTooltipHandler.addToTooltip(event.getToolTip(), stack); } @SubscribeEvent @@ -201,7 +221,6 @@ public class ClientEvents { if (!isGameActive()) return; TurntableHandler.gameRenderTick(); - ContraptionRenderDispatcher.renderTick(); } protected static boolean isGameActive() { diff --git a/src/main/java/com/simibubi/create/events/CommonEvents.java b/src/main/java/com/simibubi/create/events/CommonEvents.java index 1c14bed9c..8b88e563d 100644 --- a/src/main/java/com/simibubi/create/events/CommonEvents.java +++ b/src/main/java/com/simibubi/create/events/CommonEvents.java @@ -17,7 +17,6 @@ import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.ServerSpeedProvider; import com.simibubi.create.foundation.utility.WorldAttached; import com.simibubi.create.foundation.utility.recipe.RecipeFinder; - import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; @@ -31,6 +30,7 @@ import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraftforge.event.AddReloadListenerEvent; import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.event.RegisterCommandsEvent; import net.minecraftforge.event.TickEvent.Phase; import net.minecraftforge.event.TickEvent.ServerTickEvent; import net.minecraftforge.event.TickEvent.WorldTickEvent; @@ -41,9 +41,9 @@ import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.world.BlockEvent.FluidPlaceBlockEvent; import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; -import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; @EventBusSubscriber @@ -118,9 +118,9 @@ public class CommonEvents { WrenchItem.wrenchInstaKillsMinecarts(event); } - @SubscribeEvent - public static void serverStarted(FMLServerStartingEvent event) { - AllCommands.register(event.getServer().getCommandManager().getDispatcher()); + @SubscribeEvent(priority = EventPriority.NORMAL) + public static void registerCommands(RegisterCommandsEvent event) { + AllCommands.register(event.getDispatcher()); } @SubscribeEvent diff --git a/src/main/java/com/simibubi/create/foundation/ResourceReloadHandler.java b/src/main/java/com/simibubi/create/foundation/ResourceReloadHandler.java index 6342594b9..0bb2d6f73 100644 --- a/src/main/java/com/simibubi/create/foundation/ResourceReloadHandler.java +++ b/src/main/java/com/simibubi/create/foundation/ResourceReloadHandler.java @@ -1,8 +1,8 @@ package com.simibubi.create.foundation; import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.foundation.block.render.SpriteShifter; - import net.minecraft.client.resources.ReloadListener; import net.minecraft.profiler.IProfiler; import net.minecraft.resources.IResourceManager; @@ -18,6 +18,7 @@ public class ResourceReloadHandler extends ReloadListener { protected void apply(Object $, IResourceManager resourceManagerIn, IProfiler profilerIn) { SpriteShifter.reloadUVs(); CreateClient.invalidateRenderers(); + IHaveGoggleInformation.numberFormat.update(); } } diff --git a/src/main/java/com/simibubi/create/foundation/advancement/AllTriggers.java b/src/main/java/com/simibubi/create/foundation/advancement/AllTriggers.java index a0dadaf81..b5da3bc49 100644 --- a/src/main/java/com/simibubi/create/foundation/advancement/AllTriggers.java +++ b/src/main/java/com/simibubi/create/foundation/advancement/AllTriggers.java @@ -1,9 +1,5 @@ package com.simibubi.create.foundation.advancement; -import java.util.LinkedList; -import java.util.List; -import java.util.function.Predicate; - import com.simibubi.create.content.logistics.InWorldProcessing; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.block.Block; @@ -15,13 +11,17 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IWorld; import net.minecraftforge.registries.ForgeRegistries; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Predicate; + public class AllTriggers { private static final List> triggers = new LinkedList<>(); - public static final RegistryTrigger INFINITE_FLUID = add(new RegistryTrigger<>("infinite_fluid", ForgeRegistries.FLUIDS)); - public static final RegistryTrigger BRACKET_APPLY_TRIGGER = add(new RegistryTrigger<>("bracket_apply", ForgeRegistries.BLOCKS)); - public static final EnumTrigger FAN_PROCESSING = add(new EnumTrigger<>("fan_processing", InWorldProcessing.Type.class)); + public static final StringSerializableTrigger INFINITE_FLUID = add(new RegistryTrigger<>("infinite_fluid", ForgeRegistries.FLUIDS)); + public static final StringSerializableTrigger BRACKET_APPLY_TRIGGER = add(new RegistryTrigger<>("bracket_apply", ForgeRegistries.BLOCKS)); + public static final StringSerializableTrigger FAN_PROCESSING = add(new EnumTrigger<>("fan_processing", InWorldProcessing.Type.class)); public static final SimpleTrigger ROTATION = simple("rotation"), diff --git a/src/main/java/com/simibubi/create/foundation/block/ItemUseOverrides.java b/src/main/java/com/simibubi/create/foundation/block/ItemUseOverrides.java new file mode 100644 index 000000000..8aa1000f9 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/block/ItemUseOverrides.java @@ -0,0 +1,44 @@ +package com.simibubi.create.foundation.block; + +import com.simibubi.create.AllItems; +import com.simibubi.create.foundation.utility.VecHelper; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.HashSet; +import java.util.Set; + +@Mod.EventBusSubscriber +public class ItemUseOverrides { + + private static final Set overrides = new HashSet<>(); + + public static void addBlock(Block block) { + overrides.add(block.getRegistryName()); + } + + @SubscribeEvent + public static void onBlockActivated(PlayerInteractEvent.RightClickBlock event) { + if (AllItems.WRENCH.isIn(event.getItemStack())) return; + + BlockState state = event.getWorld().getBlockState(event.getPos()); + ResourceLocation id = state.getBlock().getRegistryName(); + + if (!overrides.contains(id)) return; + + BlockRayTraceResult blockTrace = new BlockRayTraceResult(VecHelper.getCenterOf(event.getPos()), event.getFace(), event.getPos(), true); + ActionResultType result = state.onUse(event.getWorld(), event.getPlayer(), event.getHand(), blockTrace); + + if (!result.isAccepted()) return; + + event.setCanceled(true); + event.setCancellationResult(result); + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/block/connected/ConnectedTextureBehaviour.java b/src/main/java/com/simibubi/create/foundation/block/connected/ConnectedTextureBehaviour.java index 66c2646d3..411205def 100644 --- a/src/main/java/com/simibubi/create/foundation/block/connected/ConnectedTextureBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/block/connected/ConnectedTextureBehaviour.java @@ -1,7 +1,6 @@ package com.simibubi.create.foundation.block.connected; import com.simibubi.create.foundation.block.connected.CTSpriteShifter.CTType; - import net.minecraft.block.BlockState; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; @@ -55,10 +54,9 @@ public abstract class ConnectedTextureBehaviour { if (textureEntry == null) return context; - Axis axis = face.getAxis(); boolean positive = face.getAxisDirection() == AxisDirection.POSITIVE; - Direction h = axis == Axis.X ? Direction.SOUTH : Direction.WEST; - Direction v = axis.isHorizontal() ? Direction.UP : Direction.NORTH; + Direction h = getRightDirection(reader, pos, state, face); + Direction v = getUpDirection(reader, pos, state, face); h = positive ? h.getOpposite() : h; if (face == Direction.DOWN) { v = v.getOpposite(); @@ -95,6 +93,16 @@ public abstract class ConnectedTextureBehaviour { return context; } + protected Direction getUpDirection(IBlockDisplayReader reader, BlockPos pos, BlockState state, Direction face) { + Axis axis = face.getAxis(); + return axis.isHorizontal() ? Direction.UP : Direction.NORTH; + } + + protected Direction getRightDirection(IBlockDisplayReader reader, BlockPos pos, BlockState state, Direction face) { + Axis axis = face.getAxis(); + return axis == Axis.X ? Direction.SOUTH : Direction.WEST; + } + private boolean testConnection(IBlockDisplayReader reader, BlockPos pos, BlockState state, Direction face, final Direction horizontal, final Direction vertical, int sh, int sv) { BlockPos p = pos.offset(horizontal, sh) diff --git a/src/main/java/com/simibubi/create/foundation/collision/CollisionDebugger.java b/src/main/java/com/simibubi/create/foundation/collision/CollisionDebugger.java deleted file mode 100644 index 9624e84cb..000000000 --- a/src/main/java/com/simibubi/create/foundation/collision/CollisionDebugger.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.simibubi.create.foundation.collision; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.AllSpecialTextures; -import com.simibubi.create.CreateClient; -import com.simibubi.create.foundation.collision.ContinuousOBBCollider.ContinuousSeparationManifold; -import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; -import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.outliner.AABBOutline; - -import net.minecraft.client.Minecraft; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.RayTraceResult.Type; -import net.minecraft.util.math.vector.Vector3d; - -public class CollisionDebugger { - - public static AxisAlignedBB AABB = new AxisAlignedBB(BlockPos.ZERO.up(10)); - public static OrientedBB OBB = new OrientedBB(new AxisAlignedBB(BlockPos.ZERO)); - public static Vector3d motion = Vector3d.ZERO; - static ContinuousSeparationManifold seperation; - static double angle = 0; - static AABBOutline outline; - - public static void onScroll(double delta) { - angle += delta; - angle = (int) angle; - OBB.setRotation(new Matrix3d().asZRotation(AngleHelper.rad(angle))); - } - - public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { - ms.push(); - outline = new AABBOutline(OBB.getAsAxisAlignedBB()); - outline.getParams() - .withFaceTexture(seperation == null ? AllSpecialTextures.CHECKERED : null) - .colored(0xffffff); - if (seperation != null) - outline.getParams() - .lineWidth(1 / 64f) - .colored(0xff6544); - MatrixStacker.of(ms) - .translate(OBB.center); - ms.peek() - .getModel() - .multiply(OBB.rotation.getAsMatrix4f()); - MatrixStacker.of(ms) - .translateBack(OBB.center); - outline.render(ms, buffer); - ms.pop(); - -// ms.push(); -// if (motion.length() != 0 && (seperation == null || seperation.getTimeOfImpact() != 1)) { -// outline.getParams() -// .colored(0x6544ff) -// .lineWidth(1 / 32f); -// MatrixStacker.of(ms) -// .translate(seperation != null ? seperation.getAllowedMotion(motion) : motion) -// .translate(OBB.center); -// ms.peek() -// .getModel() -// .multiply(OBB.rotation.getAsMatrix4f()); -// MatrixStacker.of(ms) -// .translateBack(OBB.center); -// outline.render(ms, buffer); -// } -// ms.pop(); - - ms.push(); - if (seperation != null) { - Vector3d asSeparationVec = seperation.asSeparationVec(.5f); - if (asSeparationVec != null) { - outline.getParams() - .colored(0x65ff44) - .lineWidth(1 / 32f); - MatrixStacker.of(ms) - .translate(asSeparationVec) - .translate(OBB.center); - ms.peek() - .getModel() - .multiply(OBB.rotation.getAsMatrix4f()); - MatrixStacker.of(ms) - .translateBack(OBB.center); - outline.render(ms, buffer); - } - } - ms.pop(); - } - - public static void tick() { - AABB = new AxisAlignedBB(BlockPos.ZERO.up(60)).offset(.5, 0, .5); - motion = Vector3d.ZERO; - RayTraceResult mouse = Minecraft.getInstance().objectMouseOver; - if (mouse != null && mouse.getType() == Type.BLOCK) { - BlockRayTraceResult hit = (BlockRayTraceResult) mouse; - OBB.setCenter(hit.getHitVec()); - seperation = OBB.intersect(AABB, motion); - } - CreateClient.outliner.showAABB(AABB, AABB) - .withFaceTexture(seperation == null ? AllSpecialTextures.CHECKERED : null); - } - - static void showDebugLine(Vector3d relativeStart, Vector3d relativeEnd, int color, String id, int offset) { - Vector3d center = CollisionDebugger.AABB.getCenter() - .add(0, 1 + offset / 16f, 0); - CreateClient.outliner.showLine(id + OBBCollider.checkCount, center.add(relativeStart), center.add(relativeEnd)) - .colored(color) - .lineWidth(1 / 32f); - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/collision/OBBCollider.java b/src/main/java/com/simibubi/create/foundation/collision/OBBCollider.java index e636911a1..fad7b0426 100644 --- a/src/main/java/com/simibubi/create/foundation/collision/OBBCollider.java +++ b/src/main/java/com/simibubi/create/foundation/collision/OBBCollider.java @@ -1,11 +1,10 @@ package com.simibubi.create.foundation.collision; -import static com.simibubi.create.foundation.collision.CollisionDebugger.showDebugLine; +import net.minecraft.util.math.vector.Vector3d; + import static java.lang.Math.abs; import static java.lang.Math.signum; -import net.minecraft.util.math.vector.Vector3d; - public class OBBCollider { @@ -62,7 +61,6 @@ public class OBBCollider { if (diff > 0) return true; -// boolean isBestSeperation = distance != 0 && -(diff) <= abs(bestSeparation.getValue()); boolean isBestSeperation = checkCount == 2; // Debug specific separations if (isBestSeperation) { @@ -70,17 +68,6 @@ public class OBBCollider { double value = sTL * abs(diff); mf.axis = axis.normalize(); mf.separation = value; - - // Visualize values - if (CollisionDebugger.AABB != null) { - Vector3d normalizedAxis = axis.normalize(); - showDebugLine(Vector3d.ZERO, normalizedAxis.scale(TL), 0xbb00bb, "tl", 4); - showDebugLine(Vector3d.ZERO, normalizedAxis.scale(sTL * rA), 0xff4444, "ra", 3); - showDebugLine(normalizedAxis.scale(sTL * (distance - rB)), normalizedAxis.scale(TL), 0x4444ff, "rb", 2); - showDebugLine(normalizedAxis.scale(sTL * (distance - rB)), - normalizedAxis.scale(sTL * (distance - rB) + value), 0xff9966, "separation", 1); - System.out.println("TL:" + TL + ", rA: " + rA + ", rB: " + rB); - } } return false; 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 657535b79..37c759386 100644 --- a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java +++ b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java @@ -1,44 +1,89 @@ package com.simibubi.create.foundation.command; -import java.util.Collections; -import java.util.function.Predicate; - import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; - import net.minecraft.command.CommandSource; import net.minecraft.command.Commands; import net.minecraft.entity.player.PlayerEntity; +import java.util.Collections; +import java.util.function.Predicate; + public class AllCommands { public static Predicate sourceIsPlayer = (cs) -> cs.getEntity() instanceof PlayerEntity; public static void register(CommandDispatcher dispatcher) { - LiteralCommandNode createRoot = dispatcher.register(Commands.literal("create") - //general purpose - .then(ToggleDebugCommand.register()) - .then(OverlayConfigCommand.register()) - .then(FixLightingCommand.register()) - .then(ReplaceInCommandBlocksCommand.register()) - .then(HighlightCommand.register()) - .then(ToggleExperimentalRenderingCommand.register()) + LiteralCommandNode util = buildUtilityCommands(); - //dev-util - //Comment out for release - .then(ClearBufferCacheCommand.register()) - .then(ChunkUtilCommand.register()) - //.then(KillTPSCommand.register()) + LiteralCommandNode createRoot = dispatcher.register(Commands.literal("create") + .requires(cs -> cs.hasPermissionLevel(0)) + //general purpose + .then(new ToggleExperimentalRenderingCommand().register()) + .then(new ToggleDebugCommand().register()) + .then(OverlayConfigCommand.register()) + .then(FixLightingCommand.register()) + .then(HighlightCommand.register()) + .then(CouplingCommand.register()) + .then(CloneCommand.register()) + .then(PonderCommand.register()) + + //utility + .then(util) ); + createRoot.addChild(buildRedirect("u", util)); + CommandNode c = dispatcher.findNode(Collections.singleton("c")); if (c != null) return; - dispatcher.register(Commands.literal("c") - .redirect(createRoot) - ); + dispatcher.getRoot().addChild(buildRedirect("c", createRoot)); + + } + + + private static LiteralCommandNode buildUtilityCommands() { + + return Commands.literal("util") + .then(ReplaceInCommandBlocksCommand.register()) + .then(ClearBufferCacheCommand.register()) + .then(ChunkUtilCommand.register()) + .then(FlySpeedCommand.register()) + //.then(KillTPSCommand.register()) + .build(); + + } + + /** + * ***** + * https://github.com/VelocityPowered/Velocity/blob/8abc9c80a69158ebae0121fda78b55c865c0abad/proxy/src/main/java/com/velocitypowered/proxy/util/BrigadierUtils.java#L38 + * ***** + *

+ * Returns a literal node that redirects its execution to + * the given destination node. + * + * @param alias the command alias + * @param destination the destination node + * + * @return the built node + */ + public static LiteralCommandNode buildRedirect(final String alias, final LiteralCommandNode destination) { + // Redirects only work for nodes with children, but break the top argument-less command. + // Manually adding the root command after setting the redirect doesn't fix it. + // See https://github.com/Mojang/brigadier/issues/46). Manually clone the node instead. + LiteralArgumentBuilder builder = LiteralArgumentBuilder + .literal(alias) + .requires(destination.getRequirement()) + .forward( + destination.getRedirect(), destination.getRedirectModifier(), destination.isFork()) + .executes(destination.getCommand()); + for (CommandNode child : destination.getChildren()) { + builder.then(child); + } + return builder.build(); } } diff --git a/src/main/java/com/simibubi/create/foundation/command/CloneCommand.java b/src/main/java/com/simibubi/create/foundation/command/CloneCommand.java new file mode 100644 index 000000000..09a0193b3 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/CloneCommand.java @@ -0,0 +1,170 @@ +package com.simibubi.create.foundation.command; + +import com.google.common.collect.Lists; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; +import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; +import com.simibubi.create.foundation.utility.Pair; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.arguments.BlockPosArgument; +import net.minecraft.inventory.IClearable; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.CachedBlockInfo; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.gen.feature.template.Template; +import net.minecraft.world.server.ServerWorld; + +import java.util.List; + +public class CloneCommand { + + private static final Dynamic2CommandExceptionType CLONE_TOO_BIG_EXCEPTION = new Dynamic2CommandExceptionType((arg1, arg2) -> new TranslationTextComponent("commands.clone.toobig", arg1, arg2)); + + public static ArgumentBuilder register() { + return Commands.literal("clone") + .requires(cs -> cs.hasPermissionLevel(2)) + .then(Commands.argument("begin", BlockPosArgument.blockPos()) + .then(Commands.argument("end", BlockPosArgument.blockPos()) + .then(Commands.argument("destination", BlockPosArgument.blockPos()) + .then(Commands.literal("skipBlocks") + .executes(ctx -> doClone(ctx.getSource(), BlockPosArgument.getLoadedBlockPos(ctx, "begin"), BlockPosArgument.getLoadedBlockPos(ctx, "end"), BlockPosArgument.getLoadedBlockPos(ctx, "destination"), false)) + ) + .executes(ctx -> doClone(ctx.getSource(), BlockPosArgument.getLoadedBlockPos(ctx, "begin"), BlockPosArgument.getLoadedBlockPos(ctx, "end"), BlockPosArgument.getLoadedBlockPos(ctx, "destination"), true)) + ) + ) + ) + .executes(ctx -> { + ctx.getSource().sendFeedback(new StringTextComponent("Clones all blocks as well as super glue from the specified area to the target destination"), true); + + return Command.SINGLE_SUCCESS; + }); + + + } + + private static int doClone(CommandSource source, BlockPos begin, BlockPos end, BlockPos destination, boolean cloneBlocks) throws CommandSyntaxException { + MutableBoundingBox sourceArea = new MutableBoundingBox(begin, end); + BlockPos destinationEnd = destination.add(sourceArea.getLength()); + MutableBoundingBox destinationArea = new MutableBoundingBox(destination, destinationEnd); + + int i = sourceArea.getXSize() * sourceArea.getYSize() * sourceArea.getZSize(); + if (i > 32768) + throw CLONE_TOO_BIG_EXCEPTION.create(32768, i); + + ServerWorld world = source.getWorld(); + + if (!world.isAreaLoaded(begin, end) || !world.isAreaLoaded(destination, destinationEnd)) + throw BlockPosArgument.POS_UNLOADED.create(); + + BlockPos diffToTarget = new BlockPos(destinationArea.minX - sourceArea.minX, destinationArea.minY - sourceArea.minY, destinationArea.minZ - sourceArea.minZ); + + int blockPastes = cloneBlocks ? cloneBlocks(sourceArea, world, diffToTarget) : 0; + int gluePastes = cloneGlue(sourceArea, world, diffToTarget); + + if (cloneBlocks) + source.sendFeedback(new StringTextComponent("Successfully cloned " + blockPastes + " Blocks"), true); + + source.sendFeedback(new StringTextComponent("Successfully applied glue " + gluePastes + " times"), true); + return blockPastes + gluePastes; + + } + + private static int cloneGlue(MutableBoundingBox sourceArea, ServerWorld world, BlockPos diffToTarget) { + int gluePastes = 0; + + List glue = world.getEntitiesWithinAABB(SuperGlueEntity.class, AxisAlignedBB.func_216363_a(sourceArea)); + List> newGlue = Lists.newArrayList(); + + for (SuperGlueEntity g : glue) { + BlockPos pos = g.getHangingPosition(); + Direction direction = g.getFacingDirection(); + newGlue.add(Pair.of(pos.add(diffToTarget), direction)); + } + + for (Pair p : newGlue) { + SuperGlueEntity g = new SuperGlueEntity(world, p.getFirst(), p.getSecond()); + if (g.onValidSurface()){ + world.addEntity(g); + gluePastes++; + } + } + return gluePastes; + } + + private static int cloneBlocks(MutableBoundingBox sourceArea, ServerWorld world, BlockPos diffToTarget) { + int blockPastes = 0; + + List blocks = Lists.newArrayList(); + List tileBlocks = Lists.newArrayList(); + + for (int z = sourceArea.minZ; z <= sourceArea.maxZ; ++z) { + for (int y = sourceArea.minY; y <= sourceArea.maxY; ++y) { + for (int x = sourceArea.minX; x <= sourceArea.maxX; ++x) { + BlockPos currentPos = new BlockPos(x, y, z); + BlockPos newPos = currentPos.add(diffToTarget); + CachedBlockInfo cached = new CachedBlockInfo(world, currentPos, false); + BlockState state = cached.getBlockState(); + TileEntity te = world.getTileEntity(currentPos); + if (te != null) { + CompoundNBT nbt = te.write(new CompoundNBT()); + tileBlocks.add(new Template.BlockInfo(newPos, state, nbt)); + } else { + blocks.add(new Template.BlockInfo(newPos, state, null)); + } + } + } + } + + List allBlocks = Lists.newArrayList(); + allBlocks.addAll(blocks); + allBlocks.addAll(tileBlocks); + + List reverse = Lists.reverse(allBlocks); + + for (Template.BlockInfo info : reverse) { + TileEntity te = world.getTileEntity(info.pos); + IClearable.clearObj(te); + world.setBlockState(info.pos, Blocks.BARRIER.getDefaultState(), 2); + } + + for (Template.BlockInfo info : allBlocks) { + if (world.setBlockState(info.pos, info.state, 2)) + blockPastes++; + } + + for (Template.BlockInfo info : tileBlocks) { + TileEntity te = world.getTileEntity(info.pos); + if (te != null && info.nbt != null) { + info.nbt.putInt("x", info.pos.getX()); + info.nbt.putInt("y", info.pos.getY()); + info.nbt.putInt("z", info.pos.getZ()); + te.fromTag(info.state, info.nbt); + te.markDirty(); + } + + //idk why the state is set twice for a te, but its done like this in the original clone command + world.setBlockState(info.pos, info.state, 2); + } + + for (Template.BlockInfo info : reverse) { + world.updateNeighbors(info.pos, info.state.getBlock()); + } + + + world.getPendingBlockTicks().copyTicks(sourceArea, diffToTarget); + + return blockPastes; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigCommand.java b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigCommand.java new file mode 100644 index 000000000..7937764cb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigCommand.java @@ -0,0 +1,45 @@ +package com.simibubi.create.foundation.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.ArgumentBuilder; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.entity.player.ServerPlayerEntity; + +public abstract class ConfigureConfigCommand { + + protected final String commandLiteral; + + ConfigureConfigCommand(String commandLiteral) { + this.commandLiteral = commandLiteral; + } + + ArgumentBuilder register() { + return Commands.literal(this.commandLiteral) + .requires(cs -> cs.hasPermissionLevel(0)) + .then(Commands.literal("on") + .executes(ctx -> { + ServerPlayerEntity player = ctx.getSource().asPlayer(); + sendPacket(player, String.valueOf(true)); + + return Command.SINGLE_SUCCESS; + }) + ) + .then(Commands.literal("off") + .executes(ctx -> { + ServerPlayerEntity player = ctx.getSource().asPlayer(); + sendPacket(player, String.valueOf(false)); + + return Command.SINGLE_SUCCESS; + }) + ) + .executes(ctx -> { + ServerPlayerEntity player = ctx.getSource().asPlayer(); + sendPacket(player, "info"); + + return Command.SINGLE_SUCCESS; + }); + } + + protected abstract void sendPacket(ServerPlayerEntity player, String option); +} diff --git a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java index a8d174725..58c53e470 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java +++ b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java @@ -1,23 +1,32 @@ package com.simibubi.create.foundation.command; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; - +import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.goggles.GoggleConfigScreen; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.networking.SimplePacketBase; +import com.simibubi.create.foundation.ponder.PonderRegistry; +import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.ponder.content.PonderIndexScreen; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; - +import com.simibubi.create.foundation.render.backend.OptifineHandler; import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.IFormattableTextComponent; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.ForgeConfig; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.network.NetworkEvent; +import org.apache.logging.log4j.LogManager; + +import java.util.function.Consumer; +import java.util.function.Supplier; public class ConfigureConfigPacket extends SimplePacketBase { @@ -63,6 +72,7 @@ public class ConfigureConfigPacket extends SimplePacketBase { fixLighting(() -> Actions::experimentalLighting), overlayReset(() -> Actions::overlayReset), experimentalRendering(() -> Actions::experimentalRendering), + openPonder(() -> Actions::openPonder), ; @@ -79,23 +89,50 @@ public class ConfigureConfigPacket extends SimplePacketBase { @OnlyIn(Dist.CLIENT) private static void rainbowDebug(String value) { + ClientPlayerEntity player = Minecraft.getInstance().player; + if (player == null || "".equals(value)) return; + + if (value.equals("info")) { + ITextComponent text = new StringTextComponent("Rainbow Debug Utility is currently: ").append(boolToText(AllConfigs.CLIENT.rainbowDebug.get())); + player.sendStatusMessage(text, false); + return; + } + AllConfigs.CLIENT.rainbowDebug.set(Boolean.parseBoolean(value)); + ITextComponent text = boolToText(AllConfigs.CLIENT.rainbowDebug.get()).append(new StringTextComponent(" Rainbow Debug Utility").formatted(TextFormatting.WHITE)); + player.sendStatusMessage(text, false); } @OnlyIn(Dist.CLIENT) private static void experimentalRendering(String value) { - if (!"".equals(value)) { - AllConfigs.CLIENT.experimentalRendering.set(Boolean.parseBoolean(value)); + ClientPlayerEntity player = Minecraft.getInstance().player; + if (player == null || "".equals(value)) return; + + if (value.equals("info")) { + ITextComponent text = new StringTextComponent("Experimental Rendering is currently: ").append(boolToText(AllConfigs.CLIENT.experimentalRendering.get())); + player.sendStatusMessage(text, false); + return; } + + boolean parsedBoolean = Boolean.parseBoolean(value); + boolean cannotUseER = OptifineHandler.usingShaders() && parsedBoolean; + + AllConfigs.CLIENT.experimentalRendering.set(parsedBoolean); + + ITextComponent text = boolToText(AllConfigs.CLIENT.experimentalRendering.get()) + .append(new StringTextComponent(" Experimental Rendering").formatted(TextFormatting.WHITE)); + ITextComponent error = new StringTextComponent("Experimental Rendering does not support Optifine Shaders").formatted(TextFormatting.RED); + + player.sendStatusMessage(cannotUseER ? error : text, false); FastRenderDispatcher.refresh(); } - + @OnlyIn(Dist.CLIENT) private static void overlayReset(String value) { AllConfigs.CLIENT.overlayOffsetX.set(0); AllConfigs.CLIENT.overlayOffsetY.set(0); } - + @OnlyIn(Dist.CLIENT) private static void overlayScreen(String value) { ScreenOpener.open(new GoggleConfigScreen()); @@ -106,5 +143,28 @@ public class ConfigureConfigPacket extends SimplePacketBase { ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.set(true); Minecraft.getInstance().worldRenderer.loadRenderers(); } + + @OnlyIn(Dist.CLIENT) + private static void openPonder(String value) { + if (value.equals("index")) { + ScreenOpener.transitionTo(new PonderIndexScreen()); + return; + } + + ResourceLocation id = new ResourceLocation(value); + if (!PonderRegistry.all.containsKey(id)) { + Create.logger.error("Could not find ponder scenes for item: " + id); + return; + } + + ScreenOpener.transitionTo(PonderUI.of(id)); + + } + + private static IFormattableTextComponent boolToText(boolean b) { + return b + ? new StringTextComponent("enabled").formatted(TextFormatting.DARK_GREEN) + : new StringTextComponent("disabled").formatted(TextFormatting.RED); + } } } diff --git a/src/main/java/com/simibubi/create/foundation/command/CouplingCommand.java b/src/main/java/com/simibubi/create/foundation/command/CouplingCommand.java new file mode 100644 index 000000000..62cb360f1 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/CouplingCommand.java @@ -0,0 +1,166 @@ +package com.simibubi.create.foundation.command; + +import com.google.common.collect.Lists; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler; +import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; +import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; +import com.simibubi.create.foundation.utility.Iterate; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.arguments.EntityArgument; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.text.StringTextComponent; +import net.minecraftforge.common.util.LazyOptional; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.UUID; + +public class CouplingCommand { + + public static final SimpleCommandExceptionType ONLY_MINECARTS_ALLOWED = new SimpleCommandExceptionType(new StringTextComponent("Only Minecarts can be coupled")); + public static final SimpleCommandExceptionType SAME_DIMENSION = new SimpleCommandExceptionType(new StringTextComponent("Minecarts have to be in the same Dimension")); + public static final DynamicCommandExceptionType TWO_CARTS = new DynamicCommandExceptionType(a -> new StringTextComponent("Your selector targeted " + a + " entities. You can only couple 2 Minecarts at a time.")); + + public static ArgumentBuilder register() { + + return Commands.literal("coupling") + .requires(cs -> cs.hasPermissionLevel(2)) + .then(Commands.literal("add") + .then(Commands.argument("cart1", EntityArgument.entity()) + .then(Commands.argument("cart2", EntityArgument.entity()) + .executes(ctx -> { + Entity cart1 = EntityArgument.getEntity(ctx, "cart1"); + if (!(cart1 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + Entity cart2 = EntityArgument.getEntity(ctx, "cart2"); + if (!(cart2 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + if (!cart1.getEntityWorld().equals(cart2.getEntityWorld())) + throw SAME_DIMENSION.create(); + + Entity source = ctx.getSource().getEntity(); + + CouplingHandler.tryToCoupleCarts(source instanceof PlayerEntity ? (PlayerEntity) source : null, cart1.getEntityWorld(), cart1.getEntityId(), cart2.getEntityId()); + + return Command.SINGLE_SUCCESS; + }) + ) + ) + .then(Commands.argument("carts", EntityArgument.entities()) + .executes(ctx -> { + Collection entities = EntityArgument.getEntities(ctx, "carts"); + if (entities.size() != 2) + throw TWO_CARTS.create(entities.size()); + + ArrayList eList = Lists.newArrayList(entities); + Entity cart1 = eList.get(0); + if (!(cart1 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + Entity cart2 = eList.get(1); + if (!(cart2 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + if (!cart1.getEntityWorld().equals(cart2.getEntityWorld())) + throw SAME_DIMENSION.create(); + + Entity source = ctx.getSource().getEntity(); + + CouplingHandler.tryToCoupleCarts(source instanceof PlayerEntity ? (PlayerEntity) source : null, cart1.getEntityWorld(), cart1.getEntityId(), cart2.getEntityId()); + + return Command.SINGLE_SUCCESS; + }) + ) + ) + .then(Commands.literal("remove") + .then(Commands.argument("cart1", EntityArgument.entity()) + .then(Commands.argument("cart2", EntityArgument.entity()) + .executes(ctx -> { + Entity cart1 = EntityArgument.getEntity(ctx, "cart1"); + if (!(cart1 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + Entity cart2 = EntityArgument.getEntity(ctx, "cart2"); + if (!(cart2 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + LazyOptional cart1Capability = cart1.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY); + if (!cart1Capability.isPresent()) { + ctx.getSource().sendFeedback(new StringTextComponent("Minecart has no Couplings Attached"), true); + return 0; + } + + MinecartController cart1Controller = cart1Capability.orElse(null); + + int cart1Couplings = (cart1Controller.isConnectedToCoupling() ? 1 : 0) + (cart1Controller.isLeadingCoupling() ? 1 : 0); + if (cart1Couplings == 0) { + ctx.getSource().sendFeedback(new StringTextComponent("Minecart has no Couplings Attached"), true); + return 0; + } + + for (boolean bool : Iterate.trueAndFalse) { + UUID coupledCart = cart1Controller.getCoupledCart(bool); + if (coupledCart == null) + continue; + + if (coupledCart != cart2.getUniqueID()) + continue; + + MinecartController cart2Controller = CapabilityMinecartController.getIfPresent(cart1.getEntityWorld(), coupledCart); + if (cart2Controller == null) + return 0; + + cart1Controller.removeConnection(bool); + cart2Controller.removeConnection(!bool); + return Command.SINGLE_SUCCESS; + } + + ctx.getSource().sendFeedback(new StringTextComponent("The specified Carts are not coupled"), true); + + return 0; + }) + ) + ) + ) + .then(Commands.literal("removeAll") + .then(Commands.argument("cart", EntityArgument.entity()) + .executes(ctx -> { + Entity cart = EntityArgument.getEntity(ctx, "cart"); + if (!(cart instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + LazyOptional capability = cart.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY); + if (!capability.isPresent()) { + ctx.getSource().sendFeedback(new StringTextComponent("Minecart has no Couplings Attached"), true); + return 0; + } + + MinecartController controller = capability.orElse(null); + + int couplings = (controller.isConnectedToCoupling() ? 1 : 0) + (controller.isLeadingCoupling() ? 1 : 0); + if (couplings == 0) { + ctx.getSource().sendFeedback(new StringTextComponent("Minecart has no Couplings Attached"), true); + return 0; + } + + controller.decouple(); + + ctx.getSource().sendFeedback(new StringTextComponent("Removed " + couplings + " couplings from the Minecart"), true); + + return couplings; + }) + ) + ); + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/command/FlySpeedCommand.java b/src/main/java/com/simibubi/create/foundation/command/FlySpeedCommand.java new file mode 100644 index 000000000..2ac61f5f6 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/FlySpeedCommand.java @@ -0,0 +1,64 @@ +package com.simibubi.create.foundation.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.FloatArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.arguments.EntityArgument; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.play.server.SPlayerAbilitiesPacket; +import net.minecraft.util.text.StringTextComponent; + +public class FlySpeedCommand { + + public static ArgumentBuilder register() { + return Commands.literal("flySpeed") + .requires(cs -> cs.hasPermissionLevel(2)) + .then(Commands.argument("speed", FloatArgumentType.floatArg(0)) + .then(Commands.argument("target", EntityArgument.player()) + .executes(ctx -> sendFlySpeedUpdate( + ctx, + EntityArgument.getPlayer(ctx, "target"), + FloatArgumentType.getFloat(ctx, "speed") + ) + ) + ) + .executes(ctx -> sendFlySpeedUpdate( + ctx, + ctx.getSource().asPlayer(), + FloatArgumentType.getFloat(ctx, "speed") + ) + ) + ) + .then(Commands.literal("reset") + .then(Commands.argument("target", EntityArgument.player()) + .executes(ctx -> sendFlySpeedUpdate( + ctx, + EntityArgument.getPlayer(ctx, "target"), + 0.05f + ) + ) + ) + .executes(ctx -> sendFlySpeedUpdate( + ctx, + ctx.getSource().asPlayer(), + 0.05f + ) + ) + + ); + } + + private static int sendFlySpeedUpdate(CommandContext ctx, ServerPlayerEntity player, float speed) { + SPlayerAbilitiesPacket packet = new SPlayerAbilitiesPacket(player.abilities); + //packet.setFlySpeed(speed);TODO 1.16 + player.connection.sendPacket(packet); + + ctx.getSource().sendFeedback(new StringTextComponent("Temporarily set " + player.getName().getString() + "'s Flying Speed to: " + speed), true); + + return Command.SINGLE_SUCCESS; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/command/PonderCommand.java b/src/main/java/com/simibubi/create/foundation/command/PonderCommand.java new file mode 100644 index 000000000..f4e2cfb90 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/PonderCommand.java @@ -0,0 +1,55 @@ +package com.simibubi.create.foundation.command; + +import com.google.common.collect.ImmutableList; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.ponder.PonderRegistry; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.ISuggestionProvider; +import net.minecraft.command.arguments.EntityArgument; +import net.minecraft.command.arguments.ResourceLocationArgument; +import net.minecraft.command.arguments.SuggestionProviders; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.fml.network.PacketDistributor; + +import java.util.Collection; + +public class PonderCommand { + public static final SuggestionProvider ITEM_PONDERS = SuggestionProviders.register(new ResourceLocation("all_ponders"), (iSuggestionProviderCommandContext, builder) -> ISuggestionProvider.func_212476_a(PonderRegistry.all.keySet().stream(), builder)); + + static ArgumentBuilder register() { + return Commands.literal("ponder") + .requires(cs -> cs.hasPermissionLevel(0)) + .executes(ctx -> openScene("index", ctx.getSource().asPlayer())) + .then(Commands.argument("scene", ResourceLocationArgument.resourceLocation()) + .suggests(ITEM_PONDERS) + .executes(ctx -> openScene(ResourceLocationArgument.getResourceLocation(ctx, "scene").toString(), ctx.getSource().asPlayer())) + .then(Commands.argument("targets", EntityArgument.players()) + .requires(cs -> cs.hasPermissionLevel(2)) + .executes(ctx -> openScene(ResourceLocationArgument.getResourceLocation(ctx, "scene").toString(), EntityArgument.getPlayers(ctx, "targets"))) + ) + ); + + } + + private static int openScene(String sceneId, ServerPlayerEntity player) { + return openScene(sceneId, ImmutableList.of(player)); + } + + private static int openScene(String sceneId, Collection players) { + for (ServerPlayerEntity player : players) { + if (player instanceof FakePlayer) + continue; + + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new ConfigureConfigPacket(ConfigureConfigPacket.Actions.openPonder.name(), sceneId)); + } + return Command.SINGLE_SUCCESS; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java b/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java index 918d3dc7c..d8953c8f1 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java @@ -1,38 +1,20 @@ package com.simibubi.create.foundation.command; -import com.mojang.brigadier.Command; -import com.mojang.brigadier.arguments.BoolArgumentType; -import com.mojang.brigadier.builder.ArgumentBuilder; import com.simibubi.create.foundation.networking.AllPackets; - -import net.minecraft.command.CommandSource; -import net.minecraft.command.Commands; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.util.text.StringTextComponent; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.network.PacketDistributor; -public class ToggleDebugCommand { +public class ToggleDebugCommand extends ConfigureConfigCommand { - static ArgumentBuilder register() { - return Commands.literal("toggleDebug") - .requires(cs -> cs.hasPermissionLevel(0)) - .then(Commands.argument("value", BoolArgumentType.bool()) - .executes(ctx -> { - boolean value = BoolArgumentType.getBool(ctx, "value"); - //DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> AllConfigs.CLIENT.rainbowDebug.set(value)); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ConfigureConfigPacket.Actions.rainbowDebug.performAction(String.valueOf(value))); + public ToggleDebugCommand() { + super("rainbowDebug"); + } - DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () -> - AllPackets.channel.send( - PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.rainbowDebug.name(), String.valueOf(value)))); - - ctx.getSource().sendFeedback(new StringTextComponent((value ? "enabled" : "disabled") + " rainbow debug"), true); - - return Command.SINGLE_SUCCESS; - }) - ); + @Override + protected void sendPacket(ServerPlayerEntity player, String option) { + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new ConfigureConfigPacket(ConfigureConfigPacket.Actions.rainbowDebug.name(), option) + ); } } diff --git a/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java b/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java index 25970ac7a..e80862f33 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java @@ -1,36 +1,20 @@ package com.simibubi.create.foundation.command; -import com.mojang.brigadier.arguments.BoolArgumentType; -import com.mojang.brigadier.builder.ArgumentBuilder; import com.simibubi.create.foundation.networking.AllPackets; - -import net.minecraft.command.CommandSource; -import net.minecraft.command.Commands; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.util.text.StringTextComponent; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.network.PacketDistributor; -public class ToggleExperimentalRenderingCommand { +public class ToggleExperimentalRenderingCommand extends ConfigureConfigCommand { - static ArgumentBuilder register() { - return Commands.literal("experimentalRendering") - .requires(cs -> cs.hasPermissionLevel(0)) - .then(Commands.argument("value", BoolArgumentType.bool()) - .executes(ctx -> { - boolean value = BoolArgumentType.getBool(ctx, "value"); - //DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> AllConfigs.CLIENT.rainbowDebug.set(value)); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ConfigureConfigPacket.Actions.experimentalRendering.performAction(String.valueOf(value))); + public ToggleExperimentalRenderingCommand() { + super("experimentalRendering"); + } - DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () -> - AllPackets.channel.send( - PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.experimentalRendering.name(), String.valueOf(value)))); - - ctx.getSource().sendFeedback(new StringTextComponent((value ? "enabled" : "disabled") + " experimental rendering"), true); - - return 1; - })); + @Override + protected void sendPacket(ServerPlayerEntity player, String option) { + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new ConfigureConfigPacket(ConfigureConfigPacket.Actions.experimentalRendering.name(), option) + ); } } diff --git a/src/main/java/com/simibubi/create/foundation/config/CCuriosities.java b/src/main/java/com/simibubi/create/foundation/config/CCuriosities.java index 21f79c1ee..6bc63467d 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CCuriosities.java +++ b/src/main/java/com/simibubi/create/foundation/config/CCuriosities.java @@ -3,6 +3,7 @@ package com.simibubi.create.foundation.config; public class CCuriosities extends ConfigBase { public ConfigInt maxSymmetryWandRange = i(50, 10, "maxSymmetryWandRange", Comments.symmetryRange); + public ConfigInt placementAssistRange = i(12, 3, "placementAssistRange", Comments.placementRange); // public ConfigInt zapperUndoLogLength = i(10, 0, "zapperUndoLogLength", Comments.zapperUndoLogLength); NYI @Override @@ -12,6 +13,7 @@ public class CCuriosities extends ConfigBase { private static class Comments { static String symmetryRange = "The Maximum Distance to an active mirror for the symmetry wand to trigger."; + static String placementRange = "The Maximum Distance a Block placed by Create's placement assist will have to its interaction point."; // static String zapperUndoLogLength = "The maximum amount of operations, a blockzapper can remember for undoing. (0 to disable undo)"; } diff --git a/src/main/java/com/simibubi/create/foundation/config/CKinetics.java b/src/main/java/com/simibubi/create/foundation/config/CKinetics.java index c218f4006..a38e7945c 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CKinetics.java +++ b/src/main/java/com/simibubi/create/foundation/config/CKinetics.java @@ -14,6 +14,7 @@ public class CKinetics extends ConfigBase { e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks); public ConfigInt kineticValidationFrequency = i(60, 5, "kineticValidationFrequency", Comments.kineticValidationFrequency); public ConfigFloat crankHungerMultiplier = f(.01f, 0, 1, "crankHungerMultiplier", Comments.crankHungerMultiplier); + public ConfigInt minimumWindmillSails = i(8, 0, "minimumWindmillSails", Comments.minimumWindmillSails); public ConfigGroup fan = group(1, "encasedFan", "Encased Fan"); public ConfigInt fanPushDistance = i(20, 5, "fanPushDistance", Comments.fanPushDistance); @@ -79,6 +80,7 @@ public class CKinetics extends ConfigBase { static String furnaceEngineSpeed = "Base rotation speed for the furnace engine generator"; static String disableStress = "Disable the Stress mechanic altogether."; static String kineticValidationFrequency = "Game ticks between Kinetic Blocks checking whether their source is still valid."; + static String minimumWindmillSails = "Amount of sail-type blocks required for a windmill to assemble successfully."; } public static enum DeployerAggroSetting { diff --git a/src/main/java/com/simibubi/create/foundation/data/AllLangPartials.java b/src/main/java/com/simibubi/create/foundation/data/AllLangPartials.java index 34dcfeb86..6c71f4d97 100644 --- a/src/main/java/com/simibubi/create/foundation/data/AllLangPartials.java +++ b/src/main/java/com/simibubi/create/foundation/data/AllLangPartials.java @@ -1,21 +1,49 @@ package com.simibubi.create.foundation.data; +import com.google.common.base.Supplier; +import com.google.gson.JsonElement; +import com.simibubi.create.Create; +import com.simibubi.create.foundation.ponder.PonderRegistry; +import com.simibubi.create.foundation.utility.FilesHelper; +import com.simibubi.create.foundation.utility.Lang; + public enum AllLangPartials { - + ADVANCEMENTS("Advancements"), MESSAGES("UI & Messages"), TOOLTIPS("Item Descriptions"), - + PONDER("Ponder Content", PonderRegistry::provideLangEntries), + ; - + private String display; + private Supplier provider; private AllLangPartials(String display) { this.display = display; + this.provider = this::fromResource; + } + + private AllLangPartials(String display, Supplier customProvider) { + this.display = display; + this.provider = customProvider; } public String getDisplay() { return display; } + public JsonElement provide() { + return provider.get(); + } + + private JsonElement fromResource() { + String fileName = Lang.asId(name()); + String filepath = "assets/" + Create.ID + "/lang/default/" + fileName + ".json"; + JsonElement element = FilesHelper.loadJsonResource(filepath); + if (element == null) + throw new IllegalStateException(String.format("Could not find default lang file: %s", filepath)); + return element; + } + } 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 e73eda7be..c021f90c1 100644 --- a/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java +++ b/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java @@ -1,15 +1,5 @@ package com.simibubi.create.foundation.data; -import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock; -import static com.simibubi.create.foundation.data.CreateRegistrate.casingConnectivity; -import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -import javax.annotation.Nullable; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllItemTags; @@ -22,17 +12,14 @@ import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock 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.block.funnel.FunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.FunnelItem; import com.simibubi.create.content.logistics.block.inventories.CrateBlock; +import com.simibubi.create.foundation.block.ItemUseOverrides; import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; import com.simibubi.create.foundation.config.StressConfigDefaults; import com.simibubi.create.foundation.item.TooltipHelper; import com.tterrag.registrate.builders.BlockBuilder; import com.tterrag.registrate.util.nullness.NonNullUnaryOperator; - import net.minecraft.block.Block; -import net.minecraft.block.BlockState; import net.minecraft.client.renderer.RenderType; import net.minecraft.item.DyeColor; import net.minecraft.item.Item; @@ -43,6 +30,14 @@ import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.model.generators.ConfiguredModel; import net.minecraftforge.client.model.generators.ModelFile; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock; +import static com.simibubi.create.foundation.data.CreateRegistrate.casingConnectivity; +import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures; + public class BuilderTransformers { public static NonNullUnaryOperator> cuckooClock() { @@ -85,6 +80,7 @@ public class BuilderTransformers { TooltipHelper.referTo(v, AllBlocks.COPPER_VALVE_HANDLE); }) .tag(AllBlockTags.BRITTLE.tag, AllBlockTags.VALVE_HANDLES.tag) + .onRegister(ItemUseOverrides::addBlock) .item() .tag(AllItemTags.VALVE_HANDLES.tag) .build(); @@ -99,41 +95,6 @@ public class BuilderTransformers { .simpleItem(); } - public static NonNullUnaryOperator> funnel(String type, - ResourceLocation particleTexture) { - return b -> { - return b.blockstate((c, p) -> { - Function model = s -> { - String powered = s.get(FunnelBlock.POWERED) ? "_powered" : ""; - String extracting = s.get(FunnelBlock.EXTRACTING) ? "_push" : "_pull"; - String face = s.get(FunnelBlock.FACE) - .getString(); - return p.models() - .withExistingParent("block/" + type + "_funnel_" + face + extracting + powered, - p.modLoc("block/funnel/block_" + face)) - .texture("particle", particleTexture) - .texture("7", p.modLoc("block/" + type + "_funnel_plating")) - .texture("6", p.modLoc("block/" + type + "_funnel" + powered)) - .texture("5", p.modLoc("block/" + type + "_funnel_tall" + powered)) - .texture("2_2", p.modLoc("block/" + type + "_funnel" + extracting)) - .texture("3", p.modLoc("block/" + type + "_funnel_back")); - }; - p.horizontalFaceBlock(c.get(), model); - }) - .item(FunnelItem::new) - .model((c, p) -> { - p.withExistingParent("item/" + type + "_funnel", p.modLoc("block/funnel/item")) - .texture("particle", particleTexture) - .texture("7", p.modLoc("block/" + type + "_funnel_plating")) - .texture("2", p.modLoc("block/" + type + "_funnel_neutral")) - .texture("6", p.modLoc("block/" + type + "_funnel")) - .texture("5", p.modLoc("block/" + type + "_funnel_tall")) - .texture("3", p.modLoc("block/" + type + "_funnel_back")); - }) - .build(); - }; - } - public static NonNullUnaryOperator> beltTunnel( String type, ResourceLocation particleTexture) { return b -> b.initialProperties(SharedProperties::stone) 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 59dd0ee71..5e70123ba 100644 --- a/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java +++ b/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java @@ -1,14 +1,5 @@ package com.simibubi.create.foundation.data; -import java.util.Collection; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Supplier; -import java.util.stream.Collectors; - import com.simibubi.create.Create; import com.simibubi.create.CreateClient; import com.simibubi.create.content.AllSections; @@ -25,12 +16,7 @@ import com.tterrag.registrate.builders.FluidBuilder; import com.tterrag.registrate.builders.ItemBuilder; import com.tterrag.registrate.util.NonNullLazyValue; import com.tterrag.registrate.util.entry.RegistryEntry; -import com.tterrag.registrate.util.nullness.NonNullBiFunction; -import com.tterrag.registrate.util.nullness.NonNullConsumer; -import com.tterrag.registrate.util.nullness.NonNullFunction; -import com.tterrag.registrate.util.nullness.NonNullSupplier; -import com.tterrag.registrate.util.nullness.NonNullUnaryOperator; - +import com.tterrag.registrate.util.nullness.*; import net.minecraft.block.AbstractBlock.Properties; import net.minecraft.block.Block; import net.minecraft.client.renderer.color.IBlockColor; @@ -38,6 +24,8 @@ import net.minecraft.client.renderer.color.IItemColor; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.fluid.Fluid; import net.minecraft.item.Item; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.IItemProvider; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -48,6 +36,15 @@ import net.minecraftforge.fml.RegistryObject; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.IForgeRegistryEntry; +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Supplier; +import java.util.stream.Collectors; + public class CreateRegistrate extends AbstractRegistrate { protected CreateRegistrate(String modid) { @@ -109,6 +106,17 @@ public class CreateRegistrate extends AbstractRegistrate { .collect(Collectors.toList()); } + public CreateTileEntityBuilder tileEntity(String name, NonNullFunction, ? extends T> factory) { + return this.tileEntity(this.self(), name, (NonNullFunction)factory); + } + + @Override + public CreateTileEntityBuilder tileEntity(P parent, String name, NonNullFunction, ? extends T> factory) { + return (CreateTileEntityBuilder) this.entry(name, (callback) -> { + return CreateTileEntityBuilder.create(this, parent, name, callback, factory); + }); + } + /* Palettes */ public BlockBuilder baseBlock(String name, diff --git a/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java b/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java new file mode 100644 index 000000000..4b4637576 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java @@ -0,0 +1,51 @@ +package com.simibubi.create.foundation.data; + +import com.simibubi.create.foundation.render.backend.instancing.IRendererFactory; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import com.tterrag.registrate.AbstractRegistrate; +import com.tterrag.registrate.builders.BuilderCallback; +import com.tterrag.registrate.builders.TileEntityBuilder; +import com.tterrag.registrate.util.OneTimeEventReceiver; +import com.tterrag.registrate.util.nullness.NonNullFunction; +import com.tterrag.registrate.util.nullness.NonNullSupplier; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; + +import javax.annotation.Nullable; + +public class CreateTileEntityBuilder extends TileEntityBuilder { + + @Nullable + private NonNullSupplier> instanceFactory; + + public static TileEntityBuilder create(AbstractRegistrate owner, P parent, String name, BuilderCallback callback, NonNullFunction, ? extends T> factory) { + return new CreateTileEntityBuilder<>(owner, parent, name, callback, factory); + } + + protected CreateTileEntityBuilder(AbstractRegistrate owner, P parent, String name, BuilderCallback callback, NonNullFunction, ? extends T> factory) { + super(owner, parent, name, callback, factory); + } + + public CreateTileEntityBuilder instance(NonNullSupplier> instanceFactory) { + if (this.instanceFactory == null) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> this::registerInstance); + } + + this.instanceFactory = instanceFactory; + + return this; + } + + protected void registerInstance() { + OneTimeEventReceiver.addModListener(FMLClientSetupEvent.class, ($) -> { + NonNullSupplier> instanceFactory = this.instanceFactory; + if (instanceFactory != null) { + InstancedTileRenderRegistry.instance.register(getEntry(), instanceFactory.get()); + } + + }); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/data/LangMerger.java b/src/main/java/com/simibubi/create/foundation/data/LangMerger.java index d51631052..a4426a706 100644 --- a/src/main/java/com/simibubi/create/foundation/data/LangMerger.java +++ b/src/main/java/com/simibubi/create/foundation/data/LangMerger.java @@ -23,8 +23,8 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.simibubi.create.Create; +import com.simibubi.create.foundation.ponder.PonderScene; import com.simibubi.create.foundation.utility.FilesHelper; -import com.simibubi.create.foundation.utility.Lang; import net.minecraft.data.DataGenerator; import net.minecraft.data.DirectoryCache; @@ -45,12 +45,28 @@ public class LangMerger implements IDataProvider { private Map> allLocalizedEntries; private Map missingTranslationTally; + private List langIgnore; + public LangMerger(DataGenerator gen) { this.gen = gen; this.mergedLangData = new ArrayList<>(); + this.langIgnore = new ArrayList<>(); this.allLocalizedEntries = new HashMap<>(); this.populatedLangData = new HashMap<>(); this.missingTranslationTally = new HashMap<>(); + populateLangIgnore(); + } + + private void populateLangIgnore() { + // Key prefixes added here will NOT be transferred to lang templates + langIgnore.add("create.ponder.debug_"); // Ponder debug scene text + } + + private boolean shouldIgnore(String key) { + for (String string : langIgnore) + if (key.startsWith(string)) + return true; + return false; } @Override @@ -128,6 +144,8 @@ public class LangMerger implements IDataProvider { .stream() .forEachOrdered(entry -> { String key = entry.getKey(); + if (shouldIgnore(key)) + return; String value = entry.getValue() .getAsString(); if (!previousKey.getValue() @@ -158,9 +176,11 @@ public class LangMerger implements IDataProvider { } protected boolean shouldAddLineBreak(String key, String previousKey) { - // Always put tooltips in their own paragraphs + // Always put tooltips and ponder scenes in their own paragraphs if (key.endsWith(".tooltip")) return true; + if (key.startsWith("create.ponder") && key.endsWith(PonderScene.TITLE_KEY)) + return true; key = key.replaceFirst("\\.", ""); previousKey = previousKey.replaceFirst("\\.", ""); @@ -201,14 +221,9 @@ public class LangMerger implements IDataProvider { } private void collectEntries() { - for (AllLangPartials partial : AllLangPartials.values()) { - String fileName = Lang.asId(partial.name()); - String filepath = "assets/" + Create.ID + "/lang/default/" + fileName + ".json"; - JsonElement element = FilesHelper.loadJsonResource(filepath); - if (element == null) - throw new IllegalStateException(String.format("Could not find default lang file: %s", filepath)); - addAll(partial.getDisplay(), element.getAsJsonObject()); - } + for (AllLangPartials partial : AllLangPartials.values()) + addAll(partial.getDisplay(), partial.provide() + .getAsJsonObject()); } private void save(DirectoryCache cache, List dataIn, int missingKeys, Path target, String message) diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/FillingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/FillingRecipeGen.java index 3a39b6fc3..60faad0fa 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/FillingRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/FillingRecipeGen.java @@ -5,7 +5,6 @@ import com.simibubi.create.AllItems; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllTags; import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler; - import net.minecraft.data.DataGenerator; import net.minecraft.fluid.Fluids; import net.minecraft.item.Items; @@ -26,6 +25,18 @@ public class FillingRecipeGen extends ProcessingRecipeGen { BLAZE_CAKE = create("blaze_cake", b -> b.require(Fluids.LAVA, 250) .require(AllItems.BLAZE_CAKE_BASE.get()) .output(AllItems.BLAZE_CAKE.get())), + + HONEYED_APPLE = create("honeyed_apple", b -> b.require(AllTags.forgeFluidTag("honey"), 250) + .require(Items.APPLE) + .output(AllItems.HONEYED_APPLE.get())), + + SWEET_ROLL = create("sweet_roll", b -> b.require(AllTags.forgeFluidTag("milk"), 250) + .require(Items.BREAD) + .output(AllItems.SWEET_ROLL.get())), + + CHOCOLATE_BERRIES = create("chocolate_glazed_berries", b -> b.require(AllFluids.CHOCOLATE.get(), 250) + .require(Items.SWEET_BERRIES) + .output(AllItems.CHOCOLATE_BERRIES.get())), GRASS_BLOCK = create("grass_block", b -> b.require(Fluids.WATER, 500) .require(Items.DIRT) diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java index 11ce58934..90b9da293 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java @@ -1,17 +1,5 @@ package com.simibubi.create.foundation.data.recipe; -import static com.simibubi.create.foundation.data.recipe.Mods.EID; -import static com.simibubi.create.foundation.data.recipe.Mods.IE; -import static com.simibubi.create.foundation.data.recipe.Mods.INF; -import static com.simibubi.create.foundation.data.recipe.Mods.MEK; -import static com.simibubi.create.foundation.data.recipe.Mods.MW; -import static com.simibubi.create.foundation.data.recipe.Mods.SM; -import static com.simibubi.create.foundation.data.recipe.Mods.TH; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.UnaryOperator; - import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.gson.JsonArray; @@ -27,15 +15,10 @@ import com.simibubi.create.foundation.utility.Lang; import com.tterrag.registrate.util.entry.BlockEntry; import com.tterrag.registrate.util.entry.ItemEntry; import com.tterrag.registrate.util.entry.ItemProviderEntry; - import net.minecraft.advancements.criterion.ItemPredicate; import net.minecraft.block.Block; import net.minecraft.block.Blocks; -import net.minecraft.data.CookingRecipeBuilder; -import net.minecraft.data.DataGenerator; -import net.minecraft.data.IFinishedRecipe; -import net.minecraft.data.ShapedRecipeBuilder; -import net.minecraft.data.ShapelessRecipeBuilder; +import net.minecraft.data.*; import net.minecraft.item.Item; import net.minecraft.item.Items; import net.minecraft.item.crafting.CookingRecipeSerializer; @@ -51,6 +34,12 @@ import net.minecraftforge.common.crafting.conditions.ICondition; import net.minecraftforge.common.crafting.conditions.ModLoadedCondition; import net.minecraftforge.common.crafting.conditions.NotCondition; +import java.util.ArrayList; +import java.util.List; +import java.util.function.UnaryOperator; + +import static com.simibubi.create.foundation.data.recipe.Mods.*; + @SuppressWarnings("unused") public class StandardRecipeGen extends CreateRecipeProvider { @@ -319,7 +308,7 @@ public class StandardRecipeGen extends CreateRecipeProvider { .patternLine("A") .patternLine("P")), - GANTRY_PINION = create(AllBlocks.GANTRY_PINION).unlockedBy(I::andesiteCasing) + GANTRY_PINION = create(AllBlocks.GANTRY_CARRIAGE).unlockedBy(I::andesiteCasing) .viaShaped(b -> b.key('B', ItemTags.PLANKS) .key('S', I.cog()) .key('C', I.andesiteCasing()) @@ -670,6 +659,15 @@ public class StandardRecipeGen extends CreateRecipeProvider { LINEAR_CHASSIS_CYCLE = conversionCycle(ImmutableList.of(AllBlocks.LINEAR_CHASSIS, AllBlocks.SECONDARY_LINEAR_CHASSIS)), + STICKER = create(AllBlocks.STICKER).returns(1) + .unlockedBy(I::andesite) + .viaShaped(b -> b.key('I', I.andesite()) + .key('C', Tags.Items.COBBLESTONE) + .key('R', I.redstone()) + .key('S', Tags.Items.SLIMEBALLS) + .patternLine("ISI") + .patternLine("CRC")), + MINECART = create(() -> Items.MINECART).withSuffix("_from_contraption_cart") .unlockedBy(AllBlocks.CART_ASSEMBLER::get) .viaShapeless(b -> b.addIngredient(AllItems.MINECART_CONTRAPTION.get())), diff --git a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java index 34c8a0ef8..726dbb8c3 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java @@ -11,7 +11,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget; -import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.gui.widget.Widget; @@ -29,7 +29,6 @@ import net.minecraftforge.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) @ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault public abstract class AbstractSimiContainerScreen extends ContainerScreen { protected List widgets; @@ -44,12 +43,9 @@ public abstract class AbstractSimiContainerScreen extends C this.ySize = height; } - @Override - protected void drawForeground(MatrixStack p_230451_1_, int p_230451_2_, int p_230451_3_) { - } - @Override public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { + partialTicks = Minecraft.getInstance().getRenderPartialTicks(); renderBackground(matrixStack); renderWindow(matrixStack, mouseX, mouseY, partialTicks); diff --git a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiScreen.java b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiScreen.java index 2b229a5a6..8430c5cb6 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiScreen.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiScreen.java @@ -4,8 +4,10 @@ import java.util.ArrayList; import java.util.List; import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.Widget; import net.minecraft.util.text.StringTextComponent; @@ -33,31 +35,41 @@ public abstract class AbstractSimiScreen extends Screen { @Override public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { - renderBackground(ms); + partialTicks = partialTicks == 10 ? 0 + : Minecraft.getInstance() + .getRenderPartialTicks(); + + RenderSystem.pushMatrix(); + + renderWindowBackground(ms, mouseX, mouseY, partialTicks); renderWindow(ms, mouseX, mouseY, partialTicks); for (Widget widget : widgets) widget.render(ms, mouseX, mouseY, partialTicks); renderWindowForeground(ms, mouseX, mouseY, partialTicks); for (Widget widget : widgets) widget.renderToolTip(ms, mouseX, mouseY); + + RenderSystem.popMatrix(); + } + + protected void renderWindowBackground(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + renderBackground(ms); } @Override public boolean mouseClicked(double x, double y, int button) { boolean result = false; - for (Widget widget : widgets) { + for (Widget widget : widgets) if (widget.mouseClicked(x, y, button)) result = true; - } return result; } @Override public boolean keyPressed(int code, int p_keyPressed_2_, int p_keyPressed_3_) { - for (Widget widget : widgets) { + for (Widget widget : widgets) if (widget.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_)) return true; - } return super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_); } @@ -80,7 +92,7 @@ public abstract class AbstractSimiScreen extends Screen { } return super.mouseScrolled(mouseX, mouseY, delta); } - + @Override public boolean mouseReleased(double x, double y, int button) { boolean result = false; @@ -107,7 +119,7 @@ public abstract class AbstractSimiScreen extends Screen { for (Widget widget : widgets) { if (!widget.isHovered()) continue; - + if (widget instanceof AbstractSimiWidget && !((AbstractSimiWidget) widget).getToolTip().isEmpty()) { renderTooltip(ms, ((AbstractSimiWidget) widget).getToolTip(), mouseX, mouseY); } diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java index 669334f99..0048dae4f 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java @@ -2,15 +2,13 @@ package com.simibubi.create.foundation.gui; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.Create; - import net.minecraft.client.Minecraft; import net.minecraft.client.gui.AbstractGui; -import net.minecraft.client.gui.screen.Screen; import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public enum AllGuiTextures { +public enum AllGuiTextures implements IScreenRenderable { // Inventories PLAYER_INVENTORY("player_inventory.png", 176, 108), @@ -81,6 +79,9 @@ public enum AllGuiTextures { INDICATOR_YELLOW("widgets.png", 54, 18, 18, 6), INDICATOR_RED("widgets.png", 72, 18, 18, 6), + SPEECH_TOOLTIP("widgets.png", 0, 24, 8, 8), + SPEECH_TOOLTIP_HIGHLIGHT("widgets.png", 8, 24, 8, 8), + // PlacementIndicator PLACEMENT_INDICATOR_SHEET("placement_indicator.png", 0, 0, 16, 256); @@ -115,16 +116,10 @@ public enum AllGuiTextures { .bindTexture(location); } + @Override @OnlyIn(Dist.CLIENT) - public void draw(MatrixStack matrixStack, AbstractGui screen, int x, int y) { + public void draw(MatrixStack ms, AbstractGui screen, int x, int y) { bind(); - screen.drawTexture(matrixStack, x, y, startX, startY, width, height); + screen.drawTexture(ms, x, y, startX, startY, width, height); } - - @OnlyIn(Dist.CLIENT) - public void draw(MatrixStack matrixStack, int x, int y) { - draw(matrixStack, new Screen(null) { - }, x, y); - } - } diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java index 4f071fd09..c73832576 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java @@ -5,10 +5,8 @@ import com.mojang.blaze3d.matrix.MatrixStack.Entry; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.Create; import com.simibubi.create.foundation.utility.ColorHelper; - import net.minecraft.client.Minecraft; import net.minecraft.client.gui.AbstractGui; -import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.util.ResourceLocation; @@ -16,7 +14,7 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public class AllIcons { +public class AllIcons implements IScreenRenderable { public static final ResourceLocation ICON_ATLAS = Create.asResource("textures/gui/icons.png"); private static int x = 0, y = -1; @@ -70,7 +68,10 @@ public class AllIcons { I_REPLACE = next(), I_CLEAR = next(), I_OVERLAY = next(), - I_FLATTEN = next(); + I_FLATTEN = next(), + I_LMB = next(), + I_SCROLL = next(), + I_RMB = next(); public static final AllIcons I_TOOL_DEPLOY = newRow(), @@ -115,7 +116,14 @@ public class AllIcons { I_FOLLOW_DIAGONAL = next(), I_FOLLOW_MATERIAL = next(), - I_SCHEMATIC = newRow(); + I_SCHEMATIC = newRow(), + + I_MTD_LEFT = newRow(), + I_MTD_CLOSE = next(), + I_MTD_RIGHT = next(), + I_MTD_SCAN = next(), + I_MTD_REPLAY = next(), + I_MTD_USER_MODE = next(); public AllIcons(int x, int y) { iconX = x * 16; @@ -137,18 +145,13 @@ public class AllIcons { .bindTexture(ICON_ATLAS); } + @Override @OnlyIn(Dist.CLIENT) public void draw(MatrixStack matrixStack, AbstractGui screen, int x, int y) { bind(); screen.drawTexture(matrixStack, x, y, iconX, iconY, 16, 16); } - @OnlyIn(Dist.CLIENT) - public void draw(MatrixStack matrixStack, int x, int y) { - draw(matrixStack, new Screen(null) { - }, x, y); - } - @OnlyIn(Dist.CLIENT) public void draw(MatrixStack ms, IRenderTypeBuffer buffer, int color) { IVertexBuilder builder = buffer.getBuffer(RenderType.getTextSeeThrough(ICON_ATLAS)); diff --git a/src/main/java/com/simibubi/create/foundation/gui/IScreenRenderable.java b/src/main/java/com/simibubi/create/foundation/gui/IScreenRenderable.java new file mode 100644 index 000000000..c17fcad75 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/IScreenRenderable.java @@ -0,0 +1,19 @@ +package com.simibubi.create.foundation.gui; + +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.client.gui.AbstractGui; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.util.text.StringTextComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public interface IScreenRenderable { + + @OnlyIn(Dist.CLIENT) + void draw(MatrixStack ms, AbstractGui screen, int x, int y); + + @OnlyIn(Dist.CLIENT) + default void draw(MatrixStack ms, int x, int y) { + draw(ms, new Screen(new StringTextComponent("")) {}, x, y); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/ScreenOpener.java b/src/main/java/com/simibubi/create/foundation/gui/ScreenOpener.java index bef5042de..2d7c65352 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/ScreenOpener.java +++ b/src/main/java/com/simibubi/create/foundation/gui/ScreenOpener.java @@ -1,29 +1,96 @@ package com.simibubi.create.foundation.gui; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.Optional; + +import javax.annotation.Nullable; + +import com.simibubi.create.foundation.ponder.NavigatableSimiScreen; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; + import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; public class ScreenOpener { - @OnlyIn(Dist.CLIENT) - private static Screen openedGuiNextTick; + private static final Deque backStack = new ArrayDeque<>(); + private static Screen backSteppedFrom = null; - public static void tick() { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { - if (openedGuiNextTick != null) { - Minecraft.getInstance().displayGuiScreen(openedGuiNextTick); - openedGuiNextTick = null; - } - }); + public static void open(Screen screen) { + open(Minecraft.getInstance().currentScreen, screen); } - public static void open(Screen gui) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { - openedGuiNextTick = gui; - }); + public static void open(@Nullable Screen current, Screen toOpen) { + backSteppedFrom = null; + if (current != null) { + if (backStack.size() >= 15) // don't go deeper than 15 steps + backStack.pollLast(); + + backStack.push(current); + } else + backStack.clear(); + + openScreen(toOpen); + } + + public static void openPreviousScreen(Screen current, Optional screenWithContext) { + if (backStack.isEmpty()) + return; + backSteppedFrom = current; + Screen previousScreen = backStack.pop(); + if (previousScreen instanceof NavigatableSimiScreen) { + NavigatableSimiScreen previousAbstractSimiScreen = (NavigatableSimiScreen) previousScreen; + screenWithContext.ifPresent(s -> s.shareContextWith(previousAbstractSimiScreen)); + previousAbstractSimiScreen.transition.startWithValue(-0.1) + .chase(-1, .4f, LerpedFloat.Chaser.EXP); + } + openScreen(previousScreen); + } + + // transitions are only supported in simiScreens atm. they take care of all the + // rendering for it + public static void transitionTo(NavigatableSimiScreen screen) { + if (tryBackTracking(screen)) + return; + screen.transition.startWithValue(0.1) + .chase(1, .4f, LerpedFloat.Chaser.EXP); + open(screen); + } + + private static boolean tryBackTracking(NavigatableSimiScreen screen) { + List screenHistory = getScreenHistory(); + if (screenHistory.isEmpty()) + return false; + Screen previouslyRenderedScreen = screenHistory.get(0); + if (!(previouslyRenderedScreen instanceof AbstractSimiScreen)) + return false; + if (!screen.isEquivalentTo((NavigatableSimiScreen) previouslyRenderedScreen)) + return false; + + openPreviousScreen(Minecraft.getInstance().currentScreen, Optional.of(screen)); + return true; + } + + public static void clearStack() { + backStack.clear(); + } + + public static List getScreenHistory() { + return new ArrayList<>(backStack); + } + + @Nullable + public static Screen getPreviouslyRenderedScreen() { + return backSteppedFrom != null ? backSteppedFrom : backStack.peek(); + } + + private static void openScreen(Screen screen) { + Minecraft.getInstance() + .enqueue(() -> Minecraft.getInstance() + .displayGuiScreen(screen)); } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java b/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java new file mode 100644 index 000000000..af9a8c3be --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java @@ -0,0 +1,182 @@ +package com.simibubi.create.foundation.gui; + +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.util.math.vector.Matrix4f; +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.utility.ColorHelper; + +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.shader.Framebuffer; +import net.minecraftforge.fml.client.gui.GuiUtils; + +public class UIRenderHelper { + + public static Framebuffer framebuffer; + + public static void init() { + RenderSystem.recordRenderCall(() -> { + MainWindow mainWindow = Minecraft.getInstance().getWindow(); + framebuffer = new Framebuffer(mainWindow.getFramebufferWidth(), mainWindow.getFramebufferHeight(), true, Minecraft.IS_RUNNING_ON_MAC); + framebuffer.setFramebufferColor(0, 0, 0, 0); +// framebuffer.deleteFramebuffer(); + }); + } + + public static void prepFramebufferSize() { + MainWindow window = Minecraft.getInstance().getWindow(); + if (framebuffer.framebufferWidth != window.getFramebufferWidth() || framebuffer.framebufferHeight != window.getFramebufferHeight()) { + framebuffer.func_216491_a(window.getFramebufferWidth(), window.getFramebufferHeight(), Minecraft.IS_RUNNING_ON_MAC); + } + } + + public static void drawFramebuffer(float alpha) { + MainWindow window = Minecraft.getInstance() + .getWindow(); + + float vx = (float) window.getScaledWidth(); + float vy = (float) window.getScaledHeight(); + float tx = (float) framebuffer.framebufferWidth / (float) framebuffer.framebufferTextureWidth; + float ty = (float) framebuffer.framebufferHeight / (float) framebuffer.framebufferTextureHeight; + + RenderSystem.enableTexture(); + RenderSystem.enableBlend(); + RenderSystem.disableLighting(); + RenderSystem.disableAlphaTest(); + RenderSystem.defaultBlendFunc(); + RenderSystem.enableDepthTest(); + + framebuffer.bindFramebufferTexture(); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + bufferbuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEXTURE); + + bufferbuilder.vertex(0, vy, 0).color(1, 1, 1, alpha).texture(0,0).endVertex(); + bufferbuilder.vertex(vx, vy, 0).color(1, 1, 1, alpha).texture(tx,0).endVertex(); + bufferbuilder.vertex(vx, 0, 0).color(1, 1, 1, alpha).texture(tx, ty).endVertex(); + bufferbuilder.vertex(0, 0, 0).color(1, 1, 1, alpha).texture(0, ty).endVertex(); + + tessellator.draw(); + framebuffer.unbindFramebufferTexture(); + RenderSystem.disableBlend(); + RenderSystem.enableAlphaTest(); + } + + //angle in degrees; 0° -> fading to the right + //x and y specify the middle point of the starting edge + //width is the total width of the streak + public static void streak(MatrixStack ms, float angle, int x, int y, int width, int length, int color) { + int a1 = 0xa0 << 24; + int a2 = 0x80 << 24; + int a3 = 0x10 << 24; + int a4 = 0x00 << 24; + + color = color & 0x00FFFFFF; + int c1 = a1 | color; + int c2 = a2 | color; + int c3 = a3 | color; + int c4 = a4 | color; + + RenderSystem.pushMatrix(); + RenderSystem.translated(x, y, 0); + RenderSystem.rotatef(angle - 90, 0, 0, 1); + + streak(ms, width/2, length, c1, c2, c3, c4); + + RenderSystem.popMatrix(); + } + + private static void streak(MatrixStack ms, int width, int height, int c1, int c2, int c3, int c4) { + double split1 = .5; + double split2 = .75; + Matrix4f model = ms.peek().getModel(); + GuiUtils.drawGradientRect(model, 0, -width, 0, width, (int) (split1 * height), c1, c2); + GuiUtils.drawGradientRect(model, 0, -width, (int) (split1 * height), width, (int) (split2 * height), c2, c3); + GuiUtils.drawGradientRect(model, 0, -width, (int) (split2 * height), width, height, c3, c4); + } + + //draws a wide chevron-style breadcrumb arrow pointing left + public static void breadcrumbArrow(int x, int y, int width, int height, int indent, int startColor, int endColor) { + RenderSystem.pushMatrix(); + RenderSystem.translated(x - indent, y, 0); + + breadcrumbArrow(width, height, indent, startColor, endColor); + + RenderSystem.popMatrix(); + } + + private static void breadcrumbArrow(int width, int height, int indent, int c1, int c2) { + + /* + * 0,0 x1,y1 ********************* x4,y4 ***** x7,y7 + * **** **** + * **** **** + * x0,y0 x2,y2 x5,y5 + * **** **** + * **** **** + * x3,y3 ********************* x6,y6 ***** x8,y8 + * + * */ + + double x0 = 0, y0 = height / 2d; + double x1 = indent, y1 = 0; + double x2 = indent, y2 = height / 2d; + double x3 = indent, y3 = height; + double x4 = width, y4 = 0; + double x5 = width, y5 = height / 2d; + double x6 = width, y6 = height; + double x7 = indent + width, y7 = 0; + double x8 = indent + width, y8 = height; + + int fc1 = ColorHelper.mixAlphaColors(c1, c2, 0); + int fc2 = ColorHelper.mixAlphaColors(c1, c2, (indent)/(width + 2f * indent)); + int fc3 = ColorHelper.mixAlphaColors(c1, c2, (indent + width)/(width + 2f * indent)); + int fc4 = ColorHelper.mixAlphaColors(c1, c2, 1); + + RenderSystem.disableTexture(); + RenderSystem.enableBlend(); + RenderSystem.disableAlphaTest(); + RenderSystem.defaultBlendFunc(); + RenderSystem.shadeModel(GL11.GL_SMOOTH); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + bufferbuilder.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_COLOR); + + bufferbuilder.vertex(x0, y0, 0).color(fc1 >> 16 & 0xFF, fc1 >> 8 & 0xFF, fc1 & 0xFF, fc1 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x1, y1, 0).color(fc2 >> 16 & 0xFF, fc2 >> 8 & 0xFF, fc2 & 0xFF, fc2 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x2, y2, 0).color(fc2 >> 16 & 0xFF, fc2 >> 8 & 0xFF, fc2 & 0xFF, fc2 >> 24 & 0xFF).endVertex(); + + bufferbuilder.vertex(x0, y0, 0).color(fc1 >> 16 & 0xFF, fc1 >> 8 & 0xFF, fc1 & 0xFF, fc1 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x2, y2, 0).color(fc2 >> 16 & 0xFF, fc2 >> 8 & 0xFF, fc2 & 0xFF, fc2 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x3, y3, 0).color(fc2 >> 16 & 0xFF, fc2 >> 8 & 0xFF, fc2 & 0xFF, fc2 >> 24 & 0xFF).endVertex(); + + bufferbuilder.vertex(x3, y3, 0).color(fc2 >> 16 & 0xFF, fc2 >> 8 & 0xFF, fc2 & 0xFF, fc2 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x1, y1, 0).color(fc2 >> 16 & 0xFF, fc2 >> 8 & 0xFF, fc2 & 0xFF, fc2 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x4, y4, 0).color(fc3 >> 16 & 0xFF, fc3 >> 8 & 0xFF, fc3 & 0xFF, fc3 >> 24 & 0xFF).endVertex(); + + bufferbuilder.vertex(x3, y3, 0).color(fc2 >> 16 & 0xFF, fc2 >> 8 & 0xFF, fc2 & 0xFF, fc2 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x4, y4, 0).color(fc3 >> 16 & 0xFF, fc3 >> 8 & 0xFF, fc3 & 0xFF, fc3 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x6, y6, 0).color(fc3 >> 16 & 0xFF, fc3 >> 8 & 0xFF, fc3 & 0xFF, fc3 >> 24 & 0xFF).endVertex(); + + bufferbuilder.vertex(x5, y5, 0).color(fc3 >> 16 & 0xFF, fc3 >> 8 & 0xFF, fc3 & 0xFF, fc3 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x4, y4, 0).color(fc3 >> 16 & 0xFF, fc3 >> 8 & 0xFF, fc3 & 0xFF, fc3 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x7, y7, 0).color(fc4 >> 16 & 0xFF, fc4 >> 8 & 0xFF, fc4 & 0xFF, fc4 >> 24 & 0xFF).endVertex(); + + bufferbuilder.vertex(x6, y6, 0).color(fc3 >> 16 & 0xFF, fc3 >> 8 & 0xFF, fc3 & 0xFF, fc3 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x5, y5, 0).color(fc3 >> 16 & 0xFF, fc3 >> 8 & 0xFF, fc3 & 0xFF, fc3 >> 24 & 0xFF).endVertex(); + bufferbuilder.vertex(x8, y8, 0).color(fc4 >> 16 & 0xFF, fc4 >> 8 & 0xFF, fc4 & 0xFF, fc4 >> 24 & 0xFF).endVertex(); + + tessellator.draw(); + RenderSystem.shadeModel(GL11.GL_FLAT); + RenderSystem.disableBlend(); + RenderSystem.enableAlphaTest(); + RenderSystem.enableTexture(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedValue.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedValue.java index 6739f39af..ebc1e712f 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedValue.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedValue.java @@ -16,5 +16,9 @@ public class InterpolatedValue { public float get(float partialTicks) { return MathHelper.lerp(partialTicks, lastValue, value); } + + public boolean settled() { + return Math.abs(value - lastValue) < 1e-3; + } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/SelectionScrollInput.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/SelectionScrollInput.java index e118400b1..c056984fe 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/SelectionScrollInput.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/SelectionScrollInput.java @@ -41,13 +41,26 @@ public class SelectionScrollInput extends ScrollInput { protected void updateTooltip() { toolTip.clear(); toolTip.add(title.copy().formatted(TextFormatting.BLUE)); + int min = Math.min(this.max - 16, state - 7); + int max = Math.max(this.min + 16, state + 8); + min = Math.max(min, this.min); + max = Math.min(max, this.max); + if (this.min + 1 == min) + min--; + if (min > this.min) + toolTip.add(new StringTextComponent("> ...").formatted(TextFormatting.GRAY)); + if (this.max - 1 == max) + max++; for (int i = min; i < max; i++) { if (i == state) toolTip.add(StringTextComponent.EMPTY.copy().append("-> ").append(options.get(i)).formatted(TextFormatting.WHITE)); else toolTip.add(StringTextComponent.EMPTY.copy().append("> ").append(options.get(i)).formatted(TextFormatting.GRAY)); } - toolTip.add( StringTextComponent.EMPTY.copy().append(scrollToSelect).formatted(TextFormatting.ITALIC, TextFormatting.DARK_GRAY)); + if (max < this.max) + toolTip.add(new StringTextComponent("> ...").formatted(TextFormatting.GRAY)); + + toolTip.add(scrollToSelect.copy().formatted(TextFormatting.DARK_GRAY, TextFormatting.ITALIC)); } } diff --git a/src/main/java/com/simibubi/create/foundation/item/TooltipHelper.java b/src/main/java/com/simibubi/create/foundation/item/TooltipHelper.java index 988981e0c..639bbaa8d 100644 --- a/src/main/java/com/simibubi/create/foundation/item/TooltipHelper.java +++ b/src/main/java/com/simibubi/create/foundation/item/TooltipHelper.java @@ -22,6 +22,7 @@ import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.content.curiosities.tools.AllToolTiers; import com.simibubi.create.foundation.item.ItemDescription.Palette; import com.simibubi.create.foundation.utility.Couple; +import com.simibubi.create.foundation.utility.FontHelper; import com.simibubi.create.foundation.utility.Lang; import net.minecraft.client.Minecraft; @@ -95,30 +96,8 @@ public class TooltipHelper { words.add(word); } - // Apply hard wrap FontRenderer font = Minecraft.getInstance().fontRenderer; - List lines = new LinkedList<>(); - StringBuilder currentLine = new StringBuilder(); - int width = 0; - for (String word : words) { - int newWidth = font.getStringWidth(word); - if (width + newWidth > maxWidthPerLine) { - if (width > 0) { - String line = currentLine.toString(); - lines.add(line); - currentLine = new StringBuilder(); - width = 0; - } else { - lines.add(word); - continue; - } - } - currentLine.append(word); - width += newWidth; - } - if (width > 0) { - lines.add(currentLine.toString()); - } + List lines = FontHelper.cutString(font, markedUp, maxWidthPerLine); // Format String lineStart = Strings.repeat(" ", indent); @@ -150,7 +129,7 @@ public class TooltipHelper { public static List cutTextComponent(ITextComponent c, TextFormatting defaultColor, TextFormatting highlightColor, int indent) { String s = getUnformattedDeepText(c); - + // Apply markup String markedUp = s;//.replaceAll("_([^_]+)_", highlightColor + "$1" + defaultColor); @@ -203,15 +182,15 @@ public class TooltipHelper { currentComponent.append(new StringTextComponent(part).formatted(f.get(currentlyHighlighted))); currentlyHighlighted = !currentlyHighlighted; } - + formattedLines.add(currentComponent); currentlyHighlighted = !currentlyHighlighted; } - - + + return formattedLines; } - + // public static List cutTextComponentOld(ITextComponent c, TextFormatting defaultColor, // TextFormatting highlightColor, int indent) { // IFormattableTextComponent lineStart = StringTextComponent.EMPTY.copy(); diff --git a/src/main/java/com/simibubi/create/foundation/mixin/OnRemoveTileMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/AddRemoveTileMixin.java similarity index 53% rename from src/main/java/com/simibubi/create/foundation/mixin/OnRemoveTileMixin.java rename to src/main/java/com/simibubi/create/foundation/mixin/AddRemoveTileMixin.java index 355f9426a..24321c5ad 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/OnRemoveTileMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/AddRemoveTileMixin.java @@ -1,11 +1,13 @@ package com.simibubi.create.foundation.mixin; +import com.simibubi.create.foundation.render.KineticRenderer; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import com.simibubi.create.CreateClient; @@ -16,12 +18,16 @@ import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import java.util.Set; + @OnlyIn(Dist.CLIENT) @Mixin(World.class) -public class OnRemoveTileMixin { +public class AddRemoveTileMixin { @Shadow @Final public boolean isRemote; + @Shadow @Final protected Set tileEntitiesToBeRemoved; + /** * JUSTIFICATION: This method is called whenever a tile entity is removed due * to a change in block state, even on the client. By hooking into this method, @@ -29,6 +35,28 @@ public class OnRemoveTileMixin { */ @Inject(at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/World;getTileEntity(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/tileentity/TileEntity;"), method = "removeTileEntity", locals = LocalCapture.CAPTURE_FAILHARD) private void onRemoveTile(BlockPos pos, CallbackInfo ci, TileEntity te) { - if (isRemote) CreateClient.kineticRenderer.remove(te); + if (isRemote) { + World thi = (World)(Object) this; + CreateClient.kineticRenderer.get(thi).remove(te); + } + } + + @Inject(at = @At("TAIL"), method = "addTileEntity") + private void onAddTile(TileEntity te, CallbackInfoReturnable cir) { + if (isRemote) { + World thi = (World)(Object) this; + CreateClient.kineticRenderer.get(thi).queueAdd(te); + } + } + + @Inject(at = @At(value = "INVOKE", target = "Ljava/util/Set;clear()V", ordinal = 0), method = "tickBlockEntities") + private void onChunkUnload(CallbackInfo ci) { + if (isRemote) { + World thi = (World)(Object) this; + KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(thi); + for (TileEntity tile : tileEntitiesToBeRemoved) { + kineticRenderer.remove(tile); + } + } } } diff --git a/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java index 6a7118cdd..2609b4bf9 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java @@ -2,6 +2,8 @@ package com.simibubi.create.foundation.mixin; import java.util.Map; +import com.simibubi.create.CreateClient; +import net.minecraft.client.world.ClientWorld; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -32,6 +34,7 @@ public abstract class LightUpdateMixin extends AbstractChunkProvider { @Inject(at = @At("HEAD"), method = "markLightChanged") private void onLightUpdate(LightType type, SectionPos pos, CallbackInfo ci) { ClientChunkProvider thi = ((ClientChunkProvider) (Object) this); + ClientWorld world = (ClientWorld) thi.getWorld(); Chunk chunk = thi.getChunk(pos.getSectionX(), pos.getSectionZ(), false); @@ -43,9 +46,12 @@ public abstract class LightUpdateMixin extends AbstractChunkProvider { .stream() .filter(entry -> SectionPos.toChunk(entry.getKey().getY()) == sectionY) .map(Map.Entry::getValue) - .filter(tile -> tile instanceof ILightListener) - .map(tile -> (ILightListener) tile) - .forEach(ILightListener::onChunkLightUpdate); + .forEach(tile -> { + CreateClient.kineticRenderer.get(world).onLightUpdate(tile); + + if (tile instanceof ILightListener) + ((ILightListener) tile).onChunkLightUpdate(); + }); } ContraptionRenderDispatcher.notifyLightUpdate((IBlockDisplayReader) thi.getWorld(), type, pos); diff --git a/src/main/java/com/simibubi/create/foundation/mixin/NetworkLightUpdateMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/NetworkLightUpdateMixin.java new file mode 100644 index 000000000..a40c2c088 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/NetworkLightUpdateMixin.java @@ -0,0 +1,43 @@ +package com.simibubi.create.foundation.mixin; + +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.render.backend.RenderWork; +import com.simibubi.create.foundation.render.backend.light.ILightListener; +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.play.ClientPlayNetHandler; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.network.play.server.SUpdateLightPacket; +import net.minecraft.world.chunk.Chunk; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ClientPlayNetHandler.class) +public class NetworkLightUpdateMixin { + + @Inject(at = @At("TAIL"), method = "handleUpdateLight") + private void onLightPacket(SUpdateLightPacket packet, CallbackInfo ci) { + RenderWork.enqueue(() -> { + ClientWorld world = Minecraft.getInstance().world; + + if (world == null) return; + + int chunkX = packet.getChunkX(); + int chunkZ = packet.getChunkZ(); + + Chunk chunk = world.getChunkProvider().getChunk(chunkX, chunkZ, false); + + if (chunk != null) { + chunk.getTileEntityMap() + .values() + .stream() + .filter(tile -> tile instanceof ILightListener) + .map(tile -> (ILightListener) tile) + .forEach(ILightListener::onChunkLightUpdate); + } + + ContraptionRenderDispatcher.notifyLightPacket(world, chunkX, chunkZ); + }); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java index 2bf3bdde3..163f6e6a7 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java @@ -1,5 +1,8 @@ package com.simibubi.create.foundation.mixin; +import com.simibubi.create.foundation.render.KineticRenderer; +import net.minecraft.client.renderer.*; +import net.minecraft.util.math.vector.Vector3d; import org.lwjgl.opengl.GL20; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -32,7 +35,7 @@ public class RenderHooksMixin { * layer-correct custom rendering. RenderWorldLast is not refined enough for rendering world objects. * This should probably be a forge event. */ - @Inject(at = @At(value = "TAIL"), method = "renderLayer") + @Inject(at = @At("TAIL"), method = "renderLayer") private void renderLayer(RenderType type, MatrixStack stack, double camX, double camY, double camZ, CallbackInfo ci) { if (!Backend.available()) return; @@ -46,13 +49,27 @@ public class RenderHooksMixin { GL20.glUseProgram(0); } - @Inject(at = @At(value = "TAIL"), method = "loadRenderers") + @Inject(at = @At(value = "INVOKE", target = "net.minecraft.client.renderer.WorldRenderer.updateChunks(J)V"), method = "render") + private void setupFrame(MatrixStack p_228426_1_, float p_228426_2_, long p_228426_3_, boolean p_228426_5_, ActiveRenderInfo info, GameRenderer p_228426_7_, LightTexture p_228426_8_, Matrix4f p_228426_9_, CallbackInfo ci) { + Vector3d cameraPos = info.getProjectedView(); + double camX = cameraPos.getX(); + double camY = cameraPos.getY(); + double camZ = cameraPos.getZ(); + + CreateClient.kineticRenderer.get(world).beginFrame(camX, camY, camZ); + ContraptionRenderDispatcher.beginFrame(camX, camY, camZ); + } + + @Inject(at = @At("TAIL"), method = "loadRenderers") private void refresh(CallbackInfo ci) { - CreateClient.kineticRenderer.invalidate(); ContraptionRenderDispatcher.invalidateAll(); OptifineHandler.refresh(); Backend.refresh(); - if (Backend.canUseInstancing() && world != null) world.loadedTileEntityList.forEach(CreateClient.kineticRenderer::add); + if (Backend.canUseInstancing() && world != null) { + KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world); + kineticRenderer.invalidate(); + world.loadedTileEntityList.forEach(kineticRenderer::add); + } } } diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index 40329dc3e..d259b9d2a 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -1,22 +1,11 @@ package com.simibubi.create.foundation.networking; -import static net.minecraftforge.fml.network.NetworkDirection.PLAY_TO_CLIENT; -import static net.minecraftforge.fml.network.NetworkDirection.PLAY_TO_SERVER; - -import java.util.function.BiConsumer; -import java.util.function.Function; -import java.util.function.Supplier; - import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionDisassemblyPacket; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionStallPacket; import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraptionUpdatePacket; import com.simibubi.create.content.contraptions.components.structureMovement.glue.GlueEffectPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionFluidPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.LimbSwingUpdatePacket; +import com.simibubi.create.content.contraptions.components.structureMovement.sync.*; import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingCreationPacket; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartControllerUpdatePacket; import com.simibubi.create.content.contraptions.fluids.actors.FluidSplashPacket; @@ -28,17 +17,14 @@ import com.simibubi.create.content.logistics.block.mechanicalArm.ArmPlacementPac import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket; import com.simibubi.create.content.logistics.packet.ConfigureFlexcratePacket; import com.simibubi.create.content.logistics.packet.ConfigureStockswitchPacket; -import com.simibubi.create.content.schematics.packet.ConfigureSchematicannonPacket; -import com.simibubi.create.content.schematics.packet.InstantSchematicPacket; -import com.simibubi.create.content.schematics.packet.SchematicPlacePacket; -import com.simibubi.create.content.schematics.packet.SchematicSyncPacket; -import com.simibubi.create.content.schematics.packet.SchematicUploadPacket; +import com.simibubi.create.content.logistics.packet.FunnelFlapPacket; +import com.simibubi.create.content.logistics.packet.TunnelFlapPacket; +import com.simibubi.create.content.schematics.packet.*; import com.simibubi.create.foundation.command.ConfigureConfigPacket; import com.simibubi.create.foundation.command.HighlightPacket; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringCountUpdatePacket; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueUpdatePacket; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; @@ -50,6 +36,13 @@ import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.fml.network.PacketDistributor.TargetPoint; import net.minecraftforge.fml.network.simple.SimpleChannel; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import static net.minecraftforge.fml.network.NetworkDirection.PLAY_TO_CLIENT; +import static net.minecraftforge.fml.network.NetworkDirection.PLAY_TO_SERVER; + public enum AllPackets { // Client to Server @@ -86,7 +79,9 @@ public enum AllPackets { FLUID_SPLASH(FluidSplashPacket.class, FluidSplashPacket::new, PLAY_TO_CLIENT), CONTRAPTION_FLUID(ContraptionFluidPacket.class, ContraptionFluidPacket::new, PLAY_TO_CLIENT), GANTRY_UPDATE(GantryContraptionUpdatePacket.class, GantryContraptionUpdatePacket::new, PLAY_TO_CLIENT), - BLOCK_HIGHLIGHT(HighlightPacket.class, HighlightPacket::new, PLAY_TO_CLIENT) + BLOCK_HIGHLIGHT(HighlightPacket.class, HighlightPacket::new, PLAY_TO_CLIENT), + TUNNEL_FLAP(TunnelFlapPacket.class, TunnelFlapPacket::new, PLAY_TO_CLIENT), + FUNNEL_FLAP(FunnelFlapPacket.class, FunnelFlapPacket::new, PLAY_TO_CLIENT), ; diff --git a/src/main/java/com/simibubi/create/foundation/networking/TileEntityDataPacket.java b/src/main/java/com/simibubi/create/foundation/networking/TileEntityDataPacket.java new file mode 100644 index 000000000..2acdffb6d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/networking/TileEntityDataPacket.java @@ -0,0 +1,56 @@ +package com.simibubi.create.foundation.networking; + +import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity; +import com.simibubi.create.foundation.tileEntity.SyncedTileEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +/** + * A server to client version of {@link TileEntityConfigurationPacket} + * @param + */ +public abstract class TileEntityDataPacket extends SimplePacketBase { + + protected BlockPos tilePos; + + public TileEntityDataPacket(PacketBuffer buffer) { + tilePos = buffer.readBlockPos(); + } + + public TileEntityDataPacket(BlockPos pos) { + this.tilePos = pos; + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeBlockPos(tilePos); + writeData(buffer); + } + + @Override + public void handle(Supplier context) { + NetworkEvent.Context ctx = context.get(); + ctx.enqueueWork(() -> { + ClientWorld world = Minecraft.getInstance().world; + + if (world == null) return; + + TileEntity tile = world.getTileEntity(tilePos); + + if (tile instanceof SyncedTileEntity) { + handlePacket((TE) tile); + } + }); + ctx.setPacketHandled(true); + } + + protected abstract void writeData(PacketBuffer buffer); + + protected abstract void handlePacket(TE tile); +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/ElementLink.java b/src/main/java/com/simibubi/create/foundation/ponder/ElementLink.java new file mode 100644 index 000000000..cc336981c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/ElementLink.java @@ -0,0 +1,27 @@ +package com.simibubi.create.foundation.ponder; + +import java.util.UUID; + +public class ElementLink { + + private Class elementClass; + private UUID id; + + public ElementLink(Class elementClass) { + this(elementClass, UUID.randomUUID()); + } + + public ElementLink(Class elementClass, UUID id) { + this.elementClass = elementClass; + this.id = id; + } + + public UUID getId() { + return id; + } + + public T cast(PonderElement e) { + return elementClass.cast(e); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/NavigatableSimiScreen.java b/src/main/java/com/simibubi/create/foundation/ponder/NavigatableSimiScreen.java new file mode 100644 index 000000000..9e8e99361 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/NavigatableSimiScreen.java @@ -0,0 +1,246 @@ +package com.simibubi.create.foundation.ponder; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.gui.AbstractSimiScreen; +import com.simibubi.create.foundation.gui.IScreenRenderable; +import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import com.simibubi.create.foundation.ponder.content.PonderTagScreen; +import com.simibubi.create.foundation.ponder.ui.PonderButton; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; +import org.apache.commons.lang3.mutable.MutableBoolean; +import org.apache.commons.lang3.mutable.MutableInt; +import org.lwjgl.glfw.GLFW; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public abstract class NavigatableSimiScreen extends AbstractSimiScreen { + + public static final String THINK_BACK = PonderLocalization.LANG_PREFIX + "think_back"; + + protected int depthPointX, depthPointY; + public final LerpedFloat transition = LerpedFloat.linear() + .startWithValue(0) + .chase(0, .1f, LerpedFloat.Chaser.LINEAR); + protected final LerpedFloat arrowAnimation = LerpedFloat.linear() + .startWithValue(0) + .chase(0, 0.075f, LerpedFloat.Chaser.LINEAR); + protected PonderButton backTrack; + + public NavigatableSimiScreen() { + MainWindow window = Minecraft.getInstance() + .getWindow(); + depthPointX = window.getScaledWidth() / 2; + depthPointY = window.getScaledHeight() / 2; + } + + @Override + public void onClose() { + ScreenOpener.clearStack(); + super.onClose(); + } + + @Override + public void tick() { + super.tick(); + transition.tickChaser(); + arrowAnimation.tickChaser(); + } + + @Override + protected void init() { + super.init(); + List screenHistory = ScreenOpener.getScreenHistory(); + if (screenHistory.isEmpty()) + return; + if (!(screenHistory.get(0) instanceof NavigatableSimiScreen)) + return; + + Screen screen = screenHistory.get(0); + IScreenRenderable icon = null; + ItemStack altIcon = null; + + if (screen instanceof PonderUI) + altIcon = ((PonderUI) screen).stack; + if (screen instanceof PonderTagScreen) + icon = ((PonderTagScreen) screen).getTag(); + + widgets.add(backTrack = new PonderButton(31, height - 31 - PonderButton.SIZE, () -> { + ScreenOpener.openPreviousScreen(this, Optional.empty()); + }).fade(0, -1)); + backTrack.fade(1); + + if (icon != null) + backTrack.showing(icon); + if (altIcon != null) + backTrack.showing(altIcon); + } + + @Override + public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + super.render(ms, mouseX, mouseY, partialTicks); +// renderZeloBreadcrumbs(ms, mouseX, mouseY, partialTicks); + if (backTrack == null) + return; + + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, 500); + if (backTrack.isHovered()) { + textRenderer.draw(ms, Lang.translate(THINK_BACK), 15, height - 16, 0xffa3a3a3); + if (MathHelper.epsilonEquals(arrowAnimation.getValue(), arrowAnimation.getChaseTarget())) { + arrowAnimation.setValue(1); + arrowAnimation.setValue(1);//called twice to also set the previous value to 1 + } + } + RenderSystem.popMatrix(); + } + + @Override + protected void renderWindowBackground(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + if (transition.getChaseTarget() == 0) { + renderBackground(ms); + return; + } + + renderBackground(ms); + + Screen lastScreen = ScreenOpener.getPreviouslyRenderedScreen(); + float transitionValue = transition.getValue(partialTicks); + double scale = 1 + 0.5 * transitionValue; + + // draw last screen into buffer + if (lastScreen != null && lastScreen != this) { + RenderSystem.pushMatrix();// 1 + UIRenderHelper.framebuffer.framebufferClear(Minecraft.IS_RUNNING_ON_MAC); + UIRenderHelper.prepFramebufferSize(); + RenderSystem.pushMatrix();// 2 + RenderSystem.translated(0, 0, -1000); + UIRenderHelper.framebuffer.bindFramebuffer(true); + lastScreen.render(ms, mouseX, mouseY, 10); + RenderSystem.popMatrix();// 2 + + // use the buffer texture + Minecraft.getInstance() + .getFramebuffer() + .bindFramebuffer(true); + + MainWindow window = Minecraft.getInstance() + .getWindow(); + int dpx = window.getScaledWidth() / 2; + int dpy = window.getScaledHeight() / 2; + if (lastScreen instanceof AbstractSimiScreen) { + dpx = ((NavigatableSimiScreen) lastScreen).depthPointX; + dpy = ((NavigatableSimiScreen) lastScreen).depthPointY; + } + + // transitionV is 1/-1 when the older screen is hidden + // transitionV is 0 when the older screen is still fully visible + RenderSystem.translated(dpx, dpy, 0); + RenderSystem.scaled(scale, scale, 1); + RenderSystem.translated(-dpx, -dpy, 0); + UIRenderHelper.drawFramebuffer(1f - Math.abs(transitionValue)); + RenderSystem.popMatrix();// 1 + } + + // modify current screen as well + scale = transitionValue > 0 ? 1 - 0.5 * (1 - transitionValue) : 1 + .5 * (1 + transitionValue); + RenderSystem.translated(depthPointX, depthPointY, 0); + RenderSystem.scaled(scale, scale, 1); + RenderSystem.translated(-depthPointX, -depthPointY, 0); + + if (backTrack != null) { + int x = (int) MathHelper.lerp(arrowAnimation.getValue(partialTicks), -9, 21); + int maxX = backTrack.x + backTrack.getWidth(); + + if (x + 30 < backTrack.x) + UIRenderHelper.breadcrumbArrow(x + 30, height - 51, maxX - (x + 30), 20, 5, 0x40aa9999, 0x10aa9999); + + UIRenderHelper.breadcrumbArrow(x, height - 51, 30, 20, 5, 0x40aa9999, 0x10aa9999); + UIRenderHelper.breadcrumbArrow(x - 30, height - 51, 30, 20, 5, 0x40aa9999, 0x10aa9999); + } + } + + @Override + public boolean keyPressed(int code, int p_keyPressed_2_, int p_keyPressed_3_) { + if (code == GLFW.GLFW_KEY_BACKSPACE) { + ScreenOpener.openPreviousScreen(this, Optional.empty()); + return true; + } + return super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_); + } + + public void centerScalingOn(int x, int y) { + depthPointX = x; + depthPointY = y; + } + + public void centerScalingOnMouse() { + MainWindow w = client.getWindow(); + double mouseX = client.mouseHelper.getMouseX() * w.getScaledWidth() / w.getWidth(); + double mouseY = client.mouseHelper.getMouseY() * w.getScaledHeight() / w.getHeight(); + centerScalingOn((int) mouseX, (int) mouseY); + } + + public boolean isEquivalentTo(NavigatableSimiScreen other) { + return false; + } + + public void shareContextWith(NavigatableSimiScreen other) {} + + protected void renderZeloBreadcrumbs(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + List history = ScreenOpener.getScreenHistory(); + if (history.isEmpty()) + return; + + history.add(0, Minecraft.getInstance().currentScreen); + int spacing = 20; + + List names = history.stream() + .map(NavigatableSimiScreen::screenTitle) + .collect(Collectors.toList()); + + int bWidth = names.stream() + .mapToInt(s -> textRenderer.getStringWidth(s) + spacing) + .sum(); + + MutableInt x = new MutableInt(width - bWidth); + MutableInt y = new MutableInt(height - 18); + MutableBoolean first = new MutableBoolean(true); + + if (x.getValue() < 25) + x.setValue(25); + + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, 600); + names.forEach(s -> { + int sWidth = textRenderer.getStringWidth(s); + UIRenderHelper.breadcrumbArrow(x.getValue(), y.getValue(), sWidth + spacing, 14, spacing / 2, 0xdd101010, + 0x44101010); + textRenderer.draw(ms, s, x.getValue() + 5, y.getValue() + 3, first.getValue() ? 0xffeeffee : 0xffddeeff); + first.setFalse(); + + x.add(sWidth + spacing); + }); + RenderSystem.popMatrix(); + } + + private static String screenTitle(Screen screen) { + if (screen instanceof NavigatableSimiScreen) + return ((NavigatableSimiScreen) screen).getBreadcrumbTitle(); + return "<"; + } + + protected String getBreadcrumbTitle() { + return this.getClass() + .getSimpleName(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderElement.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderElement.java new file mode 100644 index 000000000..7d1c61f71 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderElement.java @@ -0,0 +1,21 @@ +package com.simibubi.create.foundation.ponder; + +public class PonderElement { + + boolean visible = true; + + public void whileSkipping(PonderScene scene) {} + + public void tick(PonderScene scene) {} + + public void reset(PonderScene scene) {} + + public boolean isVisible() { + return visible; + } + + public void setVisible(boolean visible) { + this.visible = visible; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderInstruction.java new file mode 100644 index 000000000..1cee38f86 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderInstruction.java @@ -0,0 +1,43 @@ +package com.simibubi.create.foundation.ponder; + +import java.util.function.Consumer; + +public abstract class PonderInstruction { + + public boolean isBlocking() { + return false; + } + + public void reset(PonderScene scene) {} + + public abstract boolean isComplete(); + + public void onScheduled(PonderScene scene) {} + + public abstract void tick(PonderScene scene); + + public static PonderInstruction simple(Consumer callback) { + return new Simple(callback); + } + + private static class Simple extends PonderInstruction { + + private Consumer callback; + + public Simple(Consumer callback) { + this.callback = callback; + } + + @Override + public boolean isComplete() { + return true; + } + + @Override + public void tick(PonderScene scene) { + callback.accept(scene); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderLocalization.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderLocalization.java new file mode 100644 index 000000000..3dfae3db0 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderLocalization.java @@ -0,0 +1,124 @@ +package com.simibubi.create.foundation.ponder; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.simibubi.create.Create; +import com.simibubi.create.foundation.ponder.content.PonderIndex; +import com.simibubi.create.foundation.ponder.content.PonderTagScreen; +import com.simibubi.create.foundation.utility.Couple; +import com.simibubi.create.foundation.utility.Lang; + +public class PonderLocalization { + + static Map shared = new HashMap<>(); + static Map> tag = new HashMap<>(); + static Map> specific = new HashMap<>(); + + // + + public static void registerTag(String key, String enUS, String description) { + tag.put(key, Couple.create(enUS, description)); + } + + public static void registerShared(String key, String enUS) { + shared.put(key, enUS); + } + + public static void registerSpecific(String sceneId, String key, String enUS) { + specific.computeIfAbsent(sceneId, $ -> new HashMap<>()) + .put(key, enUS); + } + + // + + public static String getShared(String key) { + if (PonderIndex.EDITOR_MODE) + return shared.containsKey(key) ? shared.get(key) : ("unregistered shared entry:" + key); + return Lang.translate(langKeyForShared(key)).getString(); + } + + public static String getSpecific(String sceneId, String k) { + if (PonderIndex.EDITOR_MODE) + return specific.get(sceneId) + .get(k); + return Lang.translate(langKeyForSpecific(sceneId, k)).getString(); + } + + public static String getTag(String key) { + if (PonderIndex.EDITOR_MODE) + return tag.containsKey(key) ? tag.get(key) + .getFirst() : ("unregistered tag entry:" + key); + return Lang.translate(langKeyForTag(key)).getString(); + } + + public static String getTagDescription(String key) { + if (PonderIndex.EDITOR_MODE) + return tag.containsKey(key) ? tag.get(key) + .getSecond() : ("unregistered tag entry:" + key); + return Lang.translate(langKeyForTagDescription(key)).getString(); + } + + // + + public static final String LANG_PREFIX = "ponder."; + + public static JsonElement record() { + JsonObject object = new JsonObject(); + + addGeneral(object, PonderTooltipHandler.HOLD_TO_PONDER, "Hold [%1$s] to Ponder"); + addGeneral(object, PonderTooltipHandler.SUBJECT, "Subject of this scene"); + addGeneral(object, PonderUI.PONDERING, "Pondering about..."); + addGeneral(object, PonderUI.IDENTIFY_MODE, "Identify mode active.\nUnpause with [%1$s]"); + addGeneral(object, PonderTagScreen.ASSOCIATED, "Associated Entries"); + + addGeneral(object, PonderUI.CLOSE, "Close"); + addGeneral(object, PonderUI.IDENTIFY, "Identify"); + addGeneral(object, PonderUI.NEXT, "Next Scene"); + addGeneral(object, PonderUI.PREVIOUS, "Previous Scene"); + addGeneral(object, PonderUI.REPLAY, "Replay"); + addGeneral(object, PonderUI.THINK_BACK, "Think Back"); + + shared.forEach((k, v) -> object.addProperty(Create.ID + "." + langKeyForShared(k), v)); + tag.forEach((k, v) -> { + object.addProperty(Create.ID + "." + langKeyForTag(k), v.getFirst()); + object.addProperty(Create.ID + "." + langKeyForTagDescription(k), v.getSecond()); + }); + + specific.entrySet() + .stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(entry -> { + entry.getValue() + .entrySet() + .stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(subEntry -> object.addProperty(Create.ID + "." + langKeyForSpecific(entry.getKey(), subEntry.getKey()), + subEntry.getValue())); + }); + return object; + } + + private static void addGeneral(JsonObject json, String key, String enUS) { + json.addProperty(Create.ID + "." + key, enUS); + } + + protected static String langKeyForSpecific(String sceneId, String k) { + return LANG_PREFIX + sceneId + "." + k; + } + + protected static String langKeyForShared(String k) { + return LANG_PREFIX + "shared." + k; + } + + protected static String langKeyForTag(String k) { + return LANG_PREFIX + "tag." + k; + } + + protected static String langKeyForTagDescription(String k) { + return LANG_PREFIX + "tag." + k + ".description"; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderProgressBar.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderProgressBar.java new file mode 100644 index 000000000..bfb4004be --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderProgressBar.java @@ -0,0 +1,196 @@ +package com.simibubi.create.foundation.ponder; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.SoundHandler; +import net.minecraft.client.gui.FontRenderer; +import net.minecraftforge.fml.client.gui.GuiUtils; +import org.antlr.v4.runtime.misc.IntegerList; + +public class PonderProgressBar extends AbstractSimiWidget { + + LerpedFloat progress; + LerpedFloat flash; + + PonderUI ponder; + + public PonderProgressBar(PonderUI ponder, int xIn, int yIn, int widthIn, int heightIn) { + super(xIn, yIn, widthIn, heightIn); + + this.ponder = ponder; + progress = LerpedFloat.linear() + .startWithValue(0); + flash = LerpedFloat.linear() + .startWithValue(0); + } + + public void tick() { + progress.chase(ponder.getActiveScene() + .getSceneProgress(), .5f, LerpedFloat.Chaser.EXP); + progress.tickChaser(); + + if (hovered) + flash(); + } + + public void flash() { + float value = flash.getValue(); + flash.setValue(value + (1 - value) * .2f); + } + + public void dim() { + float value = flash.getValue(); + flash.setValue(value * .5f); + } + + @Override + protected boolean clicked(double mouseX, double mouseY) { + return this.active && this.visible && !ponder.getActiveScene().keyframeTimes.isEmpty() + && mouseX >= (double) this.x && mouseX < (double) (this.x + this.width + 4) && mouseY >= (double) this.y - 3 + && mouseY < (double) (this.y + this.height + 20); + } + + @Override + public void onClick(double mouseX, double mouseY) { + PonderScene activeScene = ponder.getActiveScene(); + IntegerList keyframeTimes = activeScene.keyframeTimes; + + int keyframeIndex = getHoveredKeyframeIndex(activeScene, mouseX); + + if (keyframeIndex == -1) + ponder.seekToTime(0); + else if (keyframeIndex == keyframeTimes.size()) + ponder.seekToTime(activeScene.totalTime); + else + ponder.seekToTime(keyframeTimes.get(keyframeIndex)); + } + + public int getHoveredKeyframeIndex(PonderScene activeScene, double mouseX) { + IntegerList keyframeTimes = activeScene.keyframeTimes; + + int totalTime = activeScene.totalTime; + int clickedAtTime = (int) ((mouseX - x) / ((double) width + 4) * totalTime); + + { + int lastKeyframeTime = keyframeTimes.get(keyframeTimes.size() - 1); + + int diffToEnd = totalTime - clickedAtTime; + int diffToLast = clickedAtTime - lastKeyframeTime; + + if (diffToEnd > 0 && diffToEnd < diffToLast / 2) { + return keyframeTimes.size(); + } + } + + int index = -1; + + for (int i = 0; i < keyframeTimes.size(); i++) { + int keyframeTime = keyframeTimes.get(i); + + if (keyframeTime > clickedAtTime) + break; + + index = i; + } + + return index; + } + + @Override + public void renderButton(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + + hovered = clicked(mouseX, mouseY); + + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, 400); + PonderUI.renderBox(ms, x, y, width, height, false); + RenderSystem.popMatrix(); + + RenderSystem.pushMatrix(); + RenderSystem.translated(x - 2, y - 2, 0); + + RenderSystem.pushMatrix(); + RenderSystem.scaled((width + 4) * progress.getValue(partialTicks), 1, 1); + GuiUtils.drawGradientRect(ms.peek().getModel(), 500, 0, 3, 1, 4, 0x80ffeedd, 0x80ffeedd); + GuiUtils.drawGradientRect(ms.peek().getModel(), 500, 0, 4, 1, 5, 0x50ffeedd, 0x50ffeedd); + RenderSystem.popMatrix(); + + renderKeyframes(ms, mouseX, partialTicks); + + RenderSystem.popMatrix(); + } + + private void renderKeyframes(MatrixStack ms, int mouseX, float partialTicks) { + PonderScene activeScene = ponder.getActiveScene(); + + int hoverStartColor; + int hoverEndColor; + int hoverIndex; + + if (hovered) { + hoverIndex = getHoveredKeyframeIndex(activeScene, mouseX); + float flashValue = flash.getValue(partialTicks) * 3 + + (float) Math.sin((AnimationTickHolder.getTicks() + partialTicks) / 6); + + hoverEndColor = ColorHelper.applyAlpha(0x70ffffff, flashValue); + hoverStartColor = ColorHelper.applyAlpha(0x30ffffff, flashValue); + } else { + hoverIndex = -2; + hoverEndColor = 0; + hoverStartColor = 0; + } + IntegerList keyframeTimes = activeScene.keyframeTimes; + + if (hoverIndex == -1) + drawKeyframe(ms, activeScene, true, 0, 0, hoverStartColor, hoverEndColor, 8); + else if (hoverIndex == keyframeTimes.size()) + drawKeyframe(ms, activeScene, true, activeScene.totalTime, width + 4, hoverStartColor, hoverEndColor, 8); + + for (int i = 0; i < keyframeTimes.size(); i++) { + int keyframeTime = keyframeTimes.get(i); + int keyframePos = (int) (((float) keyframeTime) / ((float) activeScene.totalTime) * (width + 4)); + + boolean selected = i == hoverIndex; + int startColor = selected ? hoverStartColor : 0x30ffeedd; + int endColor = selected ? hoverEndColor : 0x60ffeedd; + int height = selected ? 8 : 4; + + drawKeyframe(ms, activeScene, selected, keyframeTime, keyframePos, startColor, endColor, height); + + } + } + + private void drawKeyframe(MatrixStack ms, PonderScene activeScene, boolean selected, int keyframeTime, int keyframePos, int startColor, int endColor, int height) { + if (selected) { + FontRenderer font = Minecraft.getInstance().fontRenderer; + GuiUtils.drawGradientRect(ms.peek().getModel(), 500, keyframePos, 10, keyframePos + 1, 10 + height, endColor, startColor); + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, 400); + String text; + int offset; + if (activeScene.currentTime < keyframeTime) { + text = ">"; + offset = -1 - font.getStringWidth(text); + } + else { + text = "<"; + offset = 3; + } + font.draw(ms, text, keyframePos + offset, 10, endColor); + RenderSystem.popMatrix(); + } + + GuiUtils.drawGradientRect(ms.peek().getModel(), 500, keyframePos, -1, keyframePos + 1, 2 + height, startColor, endColor); + } + + @Override + public void playDownSound(SoundHandler handler) { + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderRegistry.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderRegistry.java new file mode 100644 index 000000000..cccb299e7 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderRegistry.java @@ -0,0 +1,194 @@ +package com.simibubi.create.foundation.ponder; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.zip.GZIPInputStream; + +import com.google.gson.JsonElement; +import com.simibubi.create.Create; +import com.simibubi.create.foundation.ponder.PonderStoryBoardEntry.PonderStoryBoard; +import com.simibubi.create.foundation.ponder.content.PonderChapter; +import com.simibubi.create.foundation.ponder.content.PonderChapterRegistry; +import com.simibubi.create.foundation.ponder.content.PonderIndex; +import com.simibubi.create.foundation.ponder.content.PonderTag; +import com.simibubi.create.foundation.ponder.content.PonderTagRegistry; +import com.simibubi.create.foundation.ponder.content.SharedText; +import com.tterrag.registrate.util.entry.ItemProviderEntry; + +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTSizeTracker; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.gen.feature.template.PlacementSettings; +import net.minecraft.world.gen.feature.template.Template; + +public class PonderRegistry { + + public static final PonderTagRegistry tags = new PonderTagRegistry(); + public static final PonderChapterRegistry chapters = new PonderChapterRegistry(); + public static Map> all = new HashMap<>(); + + public static PonderSceneBuilder addStoryBoard(ItemProviderEntry component, String schematic, + PonderStoryBoard storyBoard, PonderTag... tags) { + ResourceLocation id = component.getId(); + PonderStoryBoardEntry entry = new PonderStoryBoardEntry(storyBoard, schematic, id); + PonderSceneBuilder builder = new PonderSceneBuilder(entry); + if (tags.length > 0) + builder.highlightTags(tags); + all.computeIfAbsent(id, _$ -> new ArrayList<>()) + .add(entry); + return builder; + } + + public static PonderSceneBuilder addStoryBoard(PonderChapter chapter, ResourceLocation component, String schematic, + PonderStoryBoard storyBoard) { + if (component == null) + component = new ResourceLocation("minecraft", "stick"); + + PonderStoryBoardEntry entry = new PonderStoryBoardEntry(storyBoard, schematic, component); + PonderSceneBuilder builder = new PonderSceneBuilder(entry); + chapters.addStoriesToChapter(chapter, entry); + return builder; + } + + public static MultiSceneBuilder forComponents(ItemProviderEntry... components) { + return new MultiSceneBuilder(Arrays.asList(components)); + } + + public static List compile(ResourceLocation id) { + return compile(all.get(id)); + } + + public static List compile(PonderChapter chapter) { + return compile(chapters.getStories(chapter)); + } + + public static List compile(List entries) { + if (PonderIndex.EDITOR_MODE) { + PonderLocalization.shared.clear(); + SharedText.gatherText(); + } + + List scenes = new ArrayList<>(); + + for (int i = 0; i < entries.size(); i++) { + PonderStoryBoardEntry sb = entries.get(i); + Template activeTemplate = loadSchematic(sb.getSchematicName()); + PonderWorld world = new PonderWorld(BlockPos.ZERO, Minecraft.getInstance().world); + activeTemplate.placeAndNotifyListeners(world, BlockPos.ZERO, new PlacementSettings(), world.rand);//TODO 1.16 crashing + world.createBackup(); + PonderScene scene = compileScene(i, sb, world); + scene.begin(); + scenes.add(scene); + } + + return scenes; + } + + public static PonderScene compileScene(int i, PonderStoryBoardEntry sb, PonderWorld world) { + PonderScene scene = new PonderScene(world, sb.getComponent(), sb.getTags()); + SceneBuilder builder = scene.builder(); + sb.getBoard() + .program(builder, scene.getSceneBuildingUtil()); + return scene; + } + + public static Template loadSchematic(String path) { + Template t = new Template(); + String filepath = "ponder/" + path + ".nbt"; + InputStream resourceAsStream = Create.class.getClassLoader() + .getResourceAsStream(filepath); + if (resourceAsStream == null) { + Create.logger.error("Ponder schematic missing: " + path); + return t; + } + try (DataInputStream stream = + new DataInputStream(new BufferedInputStream(new GZIPInputStream(resourceAsStream)))) { + CompoundNBT nbt = CompressedStreamTools.read(stream, new NBTSizeTracker(0x20000000L)); + t.read(nbt); + } catch (IOException e) { + Create.logger.warn("Failed to read ponder schematic", e); + } + return t; + } + + public static JsonElement provideLangEntries() { + PonderIndex.register(); + PonderTag.register(); + SharedText.gatherText(); + all.forEach((id, list) -> { + for (int i = 0; i < list.size(); i++) + compileScene(i, list.get(i), null); + }); + return PonderLocalization.record(); + } + + public static class MultiSceneBuilder { + + private final Collection> components; + + MultiSceneBuilder(Collection> components) { + this.components = components; + } + + public MultiSceneBuilder addStoryBoard(String schematicPath, PonderStoryBoard storyBoard) { + return addStoryBoard(schematicPath, storyBoard, $ -> { + }); + } + + public MultiSceneBuilder addStoryBoard(String schematicPath, PonderStoryBoard storyBoard, PonderTag... tags) { + return addStoryBoard(schematicPath, storyBoard, sb -> sb.highlightTags(tags)); + } + + public MultiSceneBuilder addStoryBoard(String schematicPath, PonderStoryBoard storyBoard, + Consumer extras) { + components.forEach(c -> extras.accept(PonderRegistry.addStoryBoard(c, schematicPath, storyBoard))); + return this; + } + + } + + public static class PonderSceneBuilder { + + private final PonderStoryBoardEntry entry; + + PonderSceneBuilder(PonderStoryBoardEntry entry) { + this.entry = entry; + } + + public PonderSceneBuilder highlightAllTags() { + entry.getTags() + .add(PonderTag.Highlight.ALL); + return this; + } + + public PonderSceneBuilder highlightTags(PonderTag... tags) { + entry.getTags() + .addAll(Arrays.asList(tags)); + return this; + } + + public PonderSceneBuilder chapter(PonderChapter chapter) { + PonderRegistry.chapters.addStoriesToChapter(chapter, entry); + return this; + } + + public PonderSceneBuilder chapters(PonderChapter... chapters) { + for (PonderChapter c : chapters) + chapter(c); + return this; + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderScene.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderScene.java new file mode 100644 index 000000000..c1bf33394 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderScene.java @@ -0,0 +1,520 @@ +package com.simibubi.create.foundation.ponder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import net.minecraft.util.math.vector.*; +import org.antlr.v4.runtime.misc.IntegerList; +import org.apache.commons.lang3.mutable.MutableDouble; +import org.apache.commons.lang3.mutable.MutableObject; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.ponder.content.PonderIndex; +import com.simibubi.create.foundation.ponder.content.PonderTag; +import com.simibubi.create.foundation.ponder.elements.PonderOverlayElement; +import com.simibubi.create.foundation.ponder.elements.PonderSceneElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.ponder.instructions.HideAllInstruction; +import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import com.simibubi.create.foundation.utility.Pair; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.foundation.utility.outliner.Outliner; + +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ArmorStandEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.math.vector.Vector3d; + +public class PonderScene { + + public static final String TITLE_KEY = "header"; + + boolean finished; + int sceneIndex; + int textIndex; + String sceneId; + + IntegerList keyframeTimes; + + List schedule, activeSchedule; + Map linkedElements; + Set elements; + List tags; + + PonderWorld world; + ResourceLocation component; + SceneTransform transform; + SceneRenderInfo info; + Outliner outliner; + String defaultTitle; + + Vector3d pointOfInterest; + Vector3d chasingPointOfInterest; + WorldSectionElement baseWorldSection; + Entity renderViewEntity; + + int basePlateOffsetX; + int basePlateOffsetZ; + int basePlateSize; + float scaleFactor; + float yOffset; + + boolean stoppedCounting; + int totalTime; + int currentTime; + + public PonderScene(PonderWorld world, ResourceLocation component, Collection tags) { + if (world != null) + world.scene = this; + + pointOfInterest = Vector3d.ZERO; + textIndex = 1; + + this.world = world; + this.component = component; + + outliner = new Outliner(); + elements = new HashSet<>(); + linkedElements = new HashMap<>(); + this.tags = new ArrayList<>(tags); + schedule = new ArrayList<>(); + activeSchedule = new ArrayList<>(); + transform = new SceneTransform(); + basePlateSize = getBounds().getXSize(); + info = new SceneRenderInfo(); + baseWorldSection = new WorldSectionElement(); + renderViewEntity = new ArmorStandEntity(world, 0, 0, 0); + keyframeTimes = new IntegerList(4); + scaleFactor = 1; + yOffset = 0; + + setPointOfInterest(new Vector3d(0, 4, 0)); + } + + public void deselect() { + forEach(WorldSectionElement.class, WorldSectionElement::resetSelectedBlock); + } + + public Pair rayTraceScene(Vector3d from, Vector3d to) { + MutableObject> nearestHit = new MutableObject<>(); + MutableDouble bestDistance = new MutableDouble(0); + + forEach(WorldSectionElement.class, wse -> { + wse.resetSelectedBlock(); + if (!wse.isVisible()) + return; + Pair rayTrace = wse.rayTrace(world, from, to); + if (rayTrace == null) + return; + double distanceTo = rayTrace.getFirst() + .distanceTo(from); + if (nearestHit.getValue() != null && distanceTo >= bestDistance.getValue()) + return; + + nearestHit.setValue(Pair.of(wse, rayTrace.getSecond())); + bestDistance.setValue(distanceTo); + }); + + if (nearestHit.getValue() == null) + return Pair.of(ItemStack.EMPTY, null); + + BlockPos selectedPos = nearestHit.getValue() + .getSecond(); + + BlockPos origin = new BlockPos(basePlateOffsetX, 0, basePlateOffsetZ); + if (!world.getBounds() + .isVecInside(selectedPos)) + return Pair.of(ItemStack.EMPTY, null); + if (new MutableBoundingBox(origin, origin.add(new Vector3i(basePlateSize - 1, 0, basePlateSize - 1))) + .isVecInside(selectedPos)) { + if (PonderIndex.EDITOR_MODE) + nearestHit.getValue() + .getFirst() + .selectBlock(selectedPos); + return Pair.of(ItemStack.EMPTY, selectedPos); + } + + nearestHit.getValue() + .getFirst() + .selectBlock(selectedPos); + BlockState blockState = world.getBlockState(selectedPos); + ItemStack pickBlock = blockState.getPickBlock( + new BlockRayTraceResult(VecHelper.getCenterOf(selectedPos), Direction.UP, selectedPos, true), world, + selectedPos, Minecraft.getInstance().player); + + return Pair.of(pickBlock, selectedPos); + } + + public String getTitle() { + return getString(TITLE_KEY); + } + + public String getString(String key) { + return PonderLocalization.getSpecific(sceneId, key); + } + + public void reset() { + currentTime = 0; + activeSchedule.clear(); + schedule.forEach(mdi -> mdi.reset(this)); + } + + public void begin() { + reset(); + forEach(pe -> pe.reset(this)); + + world.restore(); + elements.clear(); + linkedElements.clear(); + keyframeTimes.clear(); + + transform = new SceneTransform(); + finished = false; + setPointOfInterest(new Vector3d(0, 4, 0)); + + baseWorldSection.setEmpty(); + baseWorldSection.forceApplyFade(1); + elements.add(baseWorldSection); + + totalTime = 0; + stoppedCounting = false; + activeSchedule.addAll(schedule); + activeSchedule.forEach(i -> i.onScheduled(this)); + } + + public WorldSectionElement getBaseWorldSection() { + return baseWorldSection; + } + + public float getSceneProgress() { + return totalTime == 0 ? 0 : currentTime / (float) totalTime; + } + + public void fadeOut() { + reset(); + activeSchedule.add(new HideAllInstruction(10, null)); + } + + public void renderScene(SuperRenderTypeBuffer buffer, MatrixStack ms, float pt) { + ms.push(); + Minecraft mc = Minecraft.getInstance(); + Entity prevRVE = mc.renderViewEntity; + + mc.renderViewEntity = this.renderViewEntity; + forEachVisible(PonderSceneElement.class, e -> e.renderFirst(world, buffer, ms, pt)); + mc.renderViewEntity = prevRVE; + + for (RenderType type : RenderType.getBlockLayers()) + forEachVisible(PonderSceneElement.class, e -> e.renderLayer(world, buffer, type, ms, pt)); + forEachVisible(PonderSceneElement.class, e -> e.renderLast(world, buffer, ms, pt)); + info.set(transform.xRotation.getValue(pt), transform.yRotation.getValue(pt)); + world.renderEntities(ms, buffer, info, pt); + world.renderParticles(ms, buffer, info, pt); + outliner.renderOutlines(ms, buffer, pt); + + ms.pop(); + } + + public void renderOverlay(PonderUI screen, MatrixStack ms, float partialTicks) { + ms.push(); + forEachVisible(PonderOverlayElement.class, e -> e.render(this, screen, ms, partialTicks)); + ms.pop(); + } + + public void setPointOfInterest(Vector3d poi) { + if (chasingPointOfInterest == null) + pointOfInterest = poi; + chasingPointOfInterest = poi; + } + + public Vector3d getPointOfInterest() { + return pointOfInterest; + } + + public void tick() { + if (chasingPointOfInterest != null) + pointOfInterest = VecHelper.lerp(.25f, pointOfInterest, chasingPointOfInterest); + + outliner.tickOutlines(); + world.tick(); + transform.tick(); + forEach(e -> e.tick(this)); + + if (currentTime < totalTime) + currentTime++; + + for (Iterator iterator = activeSchedule.iterator(); iterator.hasNext();) { + PonderInstruction instruction = iterator.next(); + instruction.tick(this); + if (instruction.isComplete()) { + iterator.remove(); + if (instruction.isBlocking()) + break; + continue; + } + if (instruction.isBlocking()) + break; + } + + if (activeSchedule.isEmpty()) + finished = true; + } + + public void seekToTime(int time) { + if (time < currentTime) + throw new IllegalStateException("Cannot seek backwards. Rewind first."); + + while (currentTime < time && !finished) { + forEach(e -> e.whileSkipping(this)); + tick(); + } + + forEach(WorldSectionElement.class, WorldSectionElement::queueRedraw); + } + + public void addToSceneTime(int time) { + if (!stoppedCounting) + totalTime += time; + } + + public void stopCounting() { + stoppedCounting = true; + } + + public void markKeyframe(int offset) { + if (!stoppedCounting) + keyframeTimes.add(totalTime + offset); + } + + public void addElement(PonderElement e) { + elements.add(e); + } + + public void linkElement(E e, ElementLink link) { + linkedElements.put(link.getId(), e); + } + + public E resolve(ElementLink link) { + return link.cast(linkedElements.get(link.getId())); + } + + public void runWith(ElementLink link, Consumer callback) { + callback.accept(resolve(link)); + } + + public F applyTo(ElementLink link, Function function) { + return function.apply(resolve(link)); + } + + public PonderWorld getWorld() { + return world; + } + + public Set getElements() { + return elements; + } + + public void forEach(Consumer function) { + for (PonderElement elemtent : elements) + function.accept(elemtent); + } + + public void forEachWorldEntity(Class type, Consumer function) { + world.getEntities() + .filter(type::isInstance) + .map(type::cast) + .forEach(function); + /*for (Entity element : world.getEntities()) { + if (type.isInstance(element)) + function.accept(type.cast(element)); + }*/ + } + + public void forEach(Class type, Consumer function) { + for (PonderElement element : elements) + if (type.isInstance(element)) + function.accept(type.cast(element)); + } + + public void forEachVisible(Class type, Consumer function) { + for (PonderElement element : elements) + if (type.isInstance(element) && element.isVisible()) + function.accept(type.cast(element)); + } + + public MutableBoundingBox getBounds() { + return world == null ? new MutableBoundingBox() : world.getBounds(); + } + + public Supplier registerText(String defaultText) { + final String key = "text_" + textIndex; + PonderLocalization.registerSpecific(sceneId, key, defaultText); + Supplier supplier = () -> PonderLocalization.getSpecific(sceneId, key); + textIndex++; + return supplier; + } + + public SceneBuilder builder() { + return new SceneBuilder(this); + } + + public SceneBuildingUtil getSceneBuildingUtil() { + return new SceneBuildingUtil(getBounds()); + } + + public SceneTransform getTransform() { + return transform; + } + + public class SceneTransform { + + public LerpedFloat xRotation, yRotation; + + // Screen params + int width, height; + double offset; + Matrix4f cachedMat; + + public SceneTransform() { + xRotation = LerpedFloat.angular() + .startWithValue(-35); + yRotation = LerpedFloat.angular() + .startWithValue(55 + 90); + } + + public void tick() { + xRotation.tickChaser(); + yRotation.tickChaser(); + } + + public void updateScreenParams(int width, int height, double offset) { + this.width = width; + this.height = height; + this.offset = offset; + cachedMat = null; + } + + public MatrixStack apply(MatrixStack ms) { + return apply(ms, AnimationTickHolder.getPartialTicks(world), false); + } + + public MatrixStack apply(MatrixStack ms, float pt, boolean overlayCompatible) { + ms.translate(width / 2, height / 2, 200 + offset); + + MatrixStacker.of(ms) + .rotateX(-35) + .rotateY(55); + ms.translate(offset, 0, 0); + MatrixStacker.of(ms) + .rotateY(-55) + .rotateX(35); + MatrixStacker.of(ms) + .rotateX(xRotation.getValue(pt)) + .rotateY(yRotation.getValue(pt)); + + float f = 30 * scaleFactor; + + if (!overlayCompatible) { + ms.scale(f, -f, f); + ms.translate((basePlateSize + basePlateOffsetX) / -2f, -1f + yOffset, + (basePlateSize + basePlateOffsetZ) / -2f); + } else { + // For block breaking overlay; Don't ask + ms.scale(f, f, f); + ms.translate((basePlateSize + basePlateOffsetX) / -2f, -yOffset, + (basePlateSize + basePlateOffsetZ) / -2f); + float y = (float) (0.5065 * Math.pow(2.2975, Math.log(1 / scaleFactor) / Math.log(2))) / 30; + ms.scale(y, -y, -y); + } + + return ms; + } + + public void updateSceneRVE() { + Vector3d v = screenToScene(width / 2, height / 2, 500); + renderViewEntity.setPosition(v.x, v.y, v.z); + } + + public Vector3d screenToScene(double x, double y, int depth) { + refreshMatrix(); + float pt = AnimationTickHolder.getPartialTicks(); + Vector3d vec = new Vector3d(x, y, depth); + + vec = vec.subtract(width / 2, height / 2, 200 + offset); + vec = VecHelper.rotate(vec, 35, Axis.X); + vec = VecHelper.rotate(vec, -55, Axis.Y); + vec = vec.subtract(offset, 0, 0); + vec = VecHelper.rotate(vec, 55, Axis.Y); + vec = VecHelper.rotate(vec, -35, Axis.X); + vec = VecHelper.rotate(vec, -xRotation.getValue(pt), Axis.X); + vec = VecHelper.rotate(vec, -yRotation.getValue(pt), Axis.Y); + + float f = 1f / (30 * scaleFactor); + + vec = vec.mul(f, -f, f); + vec = vec.subtract((basePlateSize + basePlateOffsetX) / -2f, -1f + yOffset, + (basePlateSize + basePlateOffsetZ) / -2f); + + return vec; + } + + public Vector2f sceneToScreen(Vector3d vec) { + refreshMatrix(); + Vector4f vec4 = new Vector4f((float) vec.x, (float) vec.y, (float) vec.z, 1); + vec4.transform(cachedMat); + return new Vector2f(vec4.getX(), vec4.getY()); + } + + protected void refreshMatrix() { + if (cachedMat != null) + return; + cachedMat = apply(new MatrixStack()).peek() + .getModel(); + } + + } + + public class SceneRenderInfo extends ActiveRenderInfo { + + public void set(float xRotation, float yRotation) { + setDirection(yRotation, xRotation); + } + + } + + public Outliner getOutliner() { + return outliner; + } + + public boolean isFinished() { + return finished; + } + + public void setFinished(boolean finished) { + this.finished = finished; + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderStoryBoardEntry.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderStoryBoardEntry.java new file mode 100644 index 000000000..7de4ccf5e --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderStoryBoardEntry.java @@ -0,0 +1,43 @@ +package com.simibubi.create.foundation.ponder; + +import com.simibubi.create.foundation.ponder.content.PonderTag; +import net.minecraft.util.ResourceLocation; + +import java.util.ArrayList; +import java.util.List; + +public class PonderStoryBoardEntry { + + private final String schematicName; + private final PonderStoryBoard board; + private final List tags; + private final ResourceLocation component; + + public PonderStoryBoardEntry(PonderStoryBoard board, String schematicName, ResourceLocation component) { + this.board = board; + this.schematicName = schematicName; + this.tags = new ArrayList<>(); + this.component = component; + } + + public interface PonderStoryBoard { + void program(SceneBuilder scene, SceneBuildingUtil util); + } + + public String getSchematicName() { + return schematicName; + } + + public PonderStoryBoard getBoard() { + return board; + } + + public List getTags() { + return tags; + } + + public ResourceLocation getComponent() { + return component; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderTooltipHandler.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderTooltipHandler.java new file mode 100644 index 000000000..ee91d6309 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderTooltipHandler.java @@ -0,0 +1,161 @@ +package com.simibubi.create.foundation.ponder; + +import java.util.List; + +import com.google.common.base.Strings; +import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.ponder.content.PonderIndexScreen; +import com.simibubi.create.foundation.ponder.content.PonderTagScreen; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.client.util.InputMappings; +import net.minecraft.inventory.container.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.IFormattableTextComponent; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.client.event.RenderTooltipEvent; + +public class PonderTooltipHandler { + + static LerpedFloat holdWProgress = LerpedFloat.linear() + .startWithValue(0); + static ItemStack lastHoveredStack = ItemStack.EMPTY; + static boolean subject = false; + + public static final String HOLD_TO_PONDER = PonderLocalization.LANG_PREFIX + "hold_to_ponder"; + public static final String SUBJECT = PonderLocalization.LANG_PREFIX + "subject"; + + public static void tick() { + Minecraft instance = Minecraft.getInstance(); + Screen currentScreen = instance.currentScreen; + ItemStack stack = ItemStack.EMPTY; + ItemStack prevStack = lastHoveredStack; + lastHoveredStack = ItemStack.EMPTY; + subject = false; + + if (currentScreen instanceof ContainerScreen) { + ContainerScreen cs = (ContainerScreen) currentScreen; + Slot slotUnderMouse = cs.getSlotUnderMouse(); + if (slotUnderMouse == null || !slotUnderMouse.getHasStack()) + return; + stack = slotUnderMouse.getStack(); + } else if (currentScreen instanceof PonderUI) { + PonderUI ponderUI = (PonderUI) currentScreen; + stack = ponderUI.getHoveredTooltipItem(); + if (stack.isItemEqual(ponderUI.getSubject())) + subject = true; + } else if (currentScreen instanceof PonderTagScreen) { + PonderTagScreen tagScreen = (PonderTagScreen) currentScreen; + stack = tagScreen.getHoveredTooltipItem(); + } else if (currentScreen instanceof PonderIndexScreen) { + PonderIndexScreen indexScreen = (PonderIndexScreen) currentScreen; + stack = indexScreen.getHoveredTooltipItem(); + } else + return; + + if (stack.isEmpty()) + return; + if (!PonderRegistry.all.containsKey(stack.getItem() + .getRegistryName())) + return; + + if (prevStack.isEmpty() || !prevStack.isItemEqual(stack)) + holdWProgress.startWithValue(0); + + float value = holdWProgress.getValue(); + int keyCode = ponderKeybind().getKey() + .getKeyCode(); + long window = instance.getWindow() + .getHandle(); + + if (!subject && InputMappings.isKeyDown(window, keyCode)) { + if (value >= 1) { + if (currentScreen instanceof NavigatableSimiScreen) + ((NavigatableSimiScreen) currentScreen).centerScalingOnMouse(); + ScreenOpener.transitionTo(PonderUI.of(stack)); + holdWProgress.startWithValue(0); + return; + } + holdWProgress.setValue(Math.min(1, value + Math.max(.25f, value) * .25f)); + } else + holdWProgress.setValue(Math.max(0, value - .05f)); + + lastHoveredStack = stack; + } + + public static void addToTooltip(List toolTip, ItemStack stack) { + float renderPartialTicks = Minecraft.getInstance() + .getRenderPartialTicks(); + if (lastHoveredStack != stack) + return; + ITextComponent component = subject ? Lang.createTranslationTextComponent(SUBJECT).formatted(TextFormatting.GREEN) + : makeProgressBar(Math.min(1, holdWProgress.getValue(renderPartialTicks) * 8 / 7f)); + if (toolTip.size() < 2) + toolTip.add(component); + else + toolTip.set(1, component); + } + + public static void handleTooltipColor(RenderTooltipEvent.Color event) { + if (lastHoveredStack != event.getStack()) + return; + if (holdWProgress.getValue() == 0) + return; + float renderPartialTicks = Minecraft.getInstance() + .getRenderPartialTicks(); + int start = event.getOriginalBorderStart(); + int end = event.getOriginalBorderEnd(); + float progress = Math.min(1, holdWProgress.getValue(renderPartialTicks) * 8 / 7f); + + start = getSmoothColorForProgress(progress); + end = getSmoothColorForProgress((progress)); + + event.setBorderStart(start | 0xa0000000); + event.setBorderEnd(end | 0xa0000000); + } + + private static int getSmoothColorForProgress(float progress) { + if (progress < .5f) + return ColorHelper.mixColors(0x5000FF, 5592575, progress * 2); + return ColorHelper.mixColors(5592575, 0xffffff, (progress - .5f) * 2); + } + + private static ITextComponent makeProgressBar(float progress) { + IFormattableTextComponent holdW = Lang.translate( + HOLD_TO_PONDER, + ((IFormattableTextComponent) ponderKeybind().getBoundKeyLocalizedText()).formatted(TextFormatting.WHITE) + ).formatted(TextFormatting.GRAY); + + + FontRenderer fontRenderer = Minecraft.getInstance().fontRenderer; + float charWidth = fontRenderer.getStringWidth("|"); + float tipWidth = fontRenderer.getWidth(holdW); + + int total = (int) (tipWidth / charWidth); + int current = (int) (progress * total); + + if (progress > 0) { + String bars = ""; + bars += TextFormatting.WHITE + Strings.repeat("|", current); + if (progress < 1) + bars += TextFormatting.GRAY + Strings.repeat("|", total - current); + return new StringTextComponent(bars); + } + + return holdW; + } + + protected static KeyBinding ponderKeybind() { + return Minecraft.getInstance().gameSettings.keyBindForward; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderUI.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderUI.java new file mode 100644 index 000000000..8f1f98f0a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderUI.java @@ -0,0 +1,931 @@ +package com.simibubi.create.foundation.ponder; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.gui.*; +import com.simibubi.create.foundation.ponder.PonderScene.SceneTransform; +import com.simibubi.create.foundation.ponder.content.*; +import com.simibubi.create.foundation.ponder.ui.PonderButton; +import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.*; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; +import net.minecraft.client.ClipboardHelper; +import net.minecraft.client.GameSettings; +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.IFormattableTextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.gen.feature.template.PlacementSettings; +import net.minecraft.world.gen.feature.template.Template; +import net.minecraftforge.fml.client.gui.GuiUtils; +import net.minecraftforge.registries.ForgeRegistries; +import org.apache.commons.lang3.mutable.MutableBoolean; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.stream.IntStream; + +public class PonderUI extends NavigatableSimiScreen { + + public static int ponderTicks; + public static float ponderPartialTicksPaused; + + public static final String PONDERING = PonderLocalization.LANG_PREFIX + "pondering"; + public static final String IDENTIFY_MODE = PonderLocalization.LANG_PREFIX + "identify_mode"; + public static final String IN_CHAPTER = PonderLocalization.LANG_PREFIX + "in_chapter"; + public static final String IDENTIFY = PonderLocalization.LANG_PREFIX + "identify"; + public static final String PREVIOUS = PonderLocalization.LANG_PREFIX + "previous"; + public static final String CLOSE = PonderLocalization.LANG_PREFIX + "close"; + public static final String NEXT = PonderLocalization.LANG_PREFIX + "next"; + public static final String REPLAY = PonderLocalization.LANG_PREFIX + "replay"; + + private List scenes; + private List tags; + private List tagButtons; + private List tagFades; + private LerpedFloat fadeIn; + ItemStack stack; + PonderChapter chapter = null; + + private boolean userViewMode; + private boolean identifyMode; + private ItemStack hoveredTooltipItem; + private BlockPos hoveredBlockPos; + + private ClipboardHelper clipboardHelper; + private BlockPos copiedBlockPos; + + private LerpedFloat finishingFlash; + private int finishingFlashWarmup = 0; + + private LerpedFloat lazyIndex; + private int index = 0; + private PonderTag referredToByTag; + + private PonderButton left, right, scan, chap, userMode, close, replay; + private PonderProgressBar progressBar; + private int skipCooling = 0; + + public static PonderUI of(ResourceLocation id) { + return new PonderUI(PonderRegistry.compile(id)); + } + + public static PonderUI of(ItemStack item) { + return new PonderUI(PonderRegistry.compile(item.getItem() + .getRegistryName())); + } + + public static PonderUI of(ItemStack item, PonderTag tag) { + PonderUI ponderUI = new PonderUI(PonderRegistry.compile(item.getItem() + .getRegistryName())); + ponderUI.referredToByTag = tag; + return ponderUI; + } + + public static PonderUI of(PonderChapter chapter) { + PonderUI ui = new PonderUI(PonderRegistry.compile(chapter)); + ui.chapter = chapter; + return ui; + } + + PonderUI(List scenes) { + ResourceLocation component = scenes.get(0).component; + if (ForgeRegistries.ITEMS.containsKey(component)) + stack = new ItemStack(ForgeRegistries.ITEMS.getValue(component)); + else + stack = new ItemStack(ForgeRegistries.BLOCKS.getValue(component)); + + tags = new ArrayList<>(PonderRegistry.tags.getTags(component)); + this.scenes = scenes; + if (scenes.isEmpty()) { + List l = Collections.singletonList(new PonderStoryBoardEntry(DebugScenes::empty, + "debug/scene_1", new ResourceLocation("minecraft", "stick"))); + scenes.addAll(PonderRegistry.compile(l)); + } + lazyIndex = LerpedFloat.linear() + .startWithValue(index); + fadeIn = LerpedFloat.linear() + .startWithValue(0) + .chase(1, .1f, Chaser.EXP); + clipboardHelper = new ClipboardHelper(); + finishingFlash = LerpedFloat.linear() + .startWithValue(0) + .chase(0, .1f, Chaser.EXP); + } + + @Override + protected void init() { + widgets.clear(); + super.init(); + + tagButtons = new ArrayList<>(); + tagFades = new ArrayList<>(); + + tags.forEach(t -> { + int i = tagButtons.size(); + int x = 31; + int y = 81 + i * 30; + PonderButton b = new PonderButton(x, y, (mouseX, mouseY) -> { + centerScalingOn(mouseX, mouseY); + ScreenOpener.transitionTo(new PonderTagScreen(t)); + }).showing(t); + + widgets.add(b); + tagButtons.add(b); + + LerpedFloat chase = LerpedFloat.linear() + .startWithValue(0) + .chase(0, .05f, Chaser.exp(.1)); + tagFades.add(chase); + + }); + + if (chapter != null) { + widgets.add(chap = new PonderButton(width - 31 - 24, 31, () -> { + }).showing(chapter)); + } + + GameSettings bindings = client.gameSettings; + int spacing = 8; + int bX = (width - 20) / 2 - (70 + 2 * spacing); + int bY = height - 20 - 31; + + { + int pX = (width / 2) - 110; + int pY = bY + PonderButton.SIZE + 4; + int pW = width - 2 * pX; + widgets.add(progressBar = new PonderProgressBar(this, pX, pY, pW, 1)); + } + + widgets.add(scan = new PonderButton(bX, bY, () -> { + identifyMode = !identifyMode; + if (!identifyMode) + scenes.get(index) + .deselect(); + else + ponderPartialTicksPaused = client.getRenderPartialTicks(); + }).showing(AllIcons.I_MTD_SCAN) + .shortcut(bindings.keyBindDrop) + .fade(0, -1)); + + if (PonderIndex.EDITOR_MODE) { + widgets.add(userMode = new PonderButton(width - 20 - 31, bY, () -> { + userViewMode = !userViewMode; + }).showing(AllIcons.I_MTD_USER_MODE) + .fade(0, -1)); + } + + bX += 50 + spacing; + widgets.add(left = new PonderButton(bX, bY, () -> this.scroll(false)).showing(AllIcons.I_MTD_LEFT) + .shortcut(bindings.keyBindLeft) + .fade(0, -1)); + + bX += 20 + spacing; + widgets.add(close = new PonderButton(bX, bY, this::onClose).showing(AllIcons.I_MTD_CLOSE) + .shortcut(bindings.keyBindInventory) + .fade(0, -1)); + + bX += 20 + spacing; + widgets.add(right = new PonderButton(bX, bY, () -> this.scroll(true)).showing(AllIcons.I_MTD_RIGHT) + .shortcut(bindings.keyBindRight) + .fade(0, -1)); + + bX += 50 + spacing; + widgets.add(replay = new PonderButton(bX, bY, this::replay).showing(AllIcons.I_MTD_REPLAY) + .shortcut(bindings.keyBindBack) + .fade(0, -1)); + } + + @Override + public void tick() { + super.tick(); + + if (skipCooling > 0) + skipCooling--; + + if (referredToByTag != null) { + for (int i = 0; i < scenes.size(); i++) { + PonderScene ponderScene = scenes.get(i); + if (!ponderScene.tags.contains(referredToByTag)) + continue; + if (i == index) + break; + scenes.get(index) + .fadeOut(); + index = i; + scenes.get(index) + .begin(); + lazyIndex.chase(index, 1 / 4f, Chaser.EXP); + identifyMode = false; + break; + } + referredToByTag = null; + } + + PonderScene activeScene = scenes.get(index); + if (!identifyMode) { + ponderTicks++; + if (skipCooling == 0) + activeScene.tick(); + } + + lazyIndex.tickChaser(); + fadeIn.tickChaser(); + finishingFlash.tickChaser(); + progressBar.tick(); + + if (activeScene.currentTime == activeScene.totalTime - 1) + finishingFlashWarmup = 30; + if (finishingFlashWarmup > 0) { + finishingFlashWarmup--; + if (finishingFlashWarmup == 0) { + finishingFlash.setValue(1); + finishingFlash.setValue(1); + } + } + + if (!identifyMode) { + float lazyIndexValue = lazyIndex.getValue(); + if (Math.abs(lazyIndexValue - index) > 1 / 512f) + scenes.get(lazyIndexValue < index ? index - 1 : index + 1) + .tick(); + } + + updateIdentifiedItem(activeScene); + } + + public PonderScene getActiveScene() { + return scenes.get(index); + } + + public void seekToTime(int time) { + if (getActiveScene().currentTime > time) + replay(); + + getActiveScene().seekToTime(time); + if (time != 0) + coolDownAfterSkip(); + } + + public void updateIdentifiedItem(PonderScene activeScene) { + hoveredTooltipItem = ItemStack.EMPTY; + hoveredBlockPos = null; + if (!identifyMode) + return; + + MainWindow w = client.getWindow(); + double mouseX = client.mouseHelper.getMouseX() * w.getScaledWidth() / w.getWidth(); + double mouseY = client.mouseHelper.getMouseY() * w.getScaledHeight() / w.getHeight(); + SceneTransform t = activeScene.getTransform(); + Vector3d vec1 = t.screenToScene(mouseX, mouseY, 1000); + Vector3d vec2 = t.screenToScene(mouseX, mouseY, -100); + Pair pair = activeScene.rayTraceScene(vec1, vec2); + hoveredTooltipItem = pair.getFirst(); + hoveredBlockPos = pair.getSecond(); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double delta) { + if (scroll(delta > 0)) + return true; + return super.mouseScrolled(mouseX, mouseY, delta); + } + + protected void replay() { + identifyMode = false; + PonderScene scene = scenes.get(index); + + if (hasShiftDown()) { + List list = PonderRegistry.all.get(scene.component); + PonderStoryBoardEntry sb = list.get(index); + Template activeTemplate = PonderRegistry.loadSchematic(sb.getSchematicName()); + PonderWorld world = new PonderWorld(BlockPos.ZERO, Minecraft.getInstance().world); + activeTemplate.placeAndNotifyListeners(world, BlockPos.ZERO, new PlacementSettings(), new Random()); + world.createBackup(); + scene = PonderRegistry.compileScene(index, sb, world); + scene.begin(); + scenes.set(index, scene); + } + + scene.begin(); + } + + protected boolean scroll(boolean forward) { + int prevIndex = index; + index = forward ? index + 1 : index - 1; + index = MathHelper.clamp(index, 0, scenes.size() - 1); + if (prevIndex != index) {// && Math.abs(index - lazyIndex.getValue()) < 1.5f) { + scenes.get(prevIndex) + .fadeOut(); + scenes.get(index) + .begin(); + lazyIndex.chase(index, 1 / 4f, Chaser.EXP); + identifyMode = false; + return true; + } else + index = prevIndex; + return false; + } + + @Override + protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + RenderSystem.enableBlend(); + renderVisibleScenes(ms, mouseX, mouseY, + skipCooling > 0 ? 0 : identifyMode ? ponderPartialTicksPaused : partialTicks); + renderWidgets(ms, mouseX, mouseY, identifyMode ? ponderPartialTicksPaused : partialTicks); + } + + @Override + public void renderBackground(MatrixStack ms) { + super.renderBackground(ms); + } + + protected void renderVisibleScenes(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + SuperRenderTypeBuffer.vertexSortingOrigin = new BlockPos(0, 0, 800); + renderScene(ms, mouseX, mouseY, index, partialTicks); + float lazyIndexValue = lazyIndex.getValue(partialTicks); + if (Math.abs(lazyIndexValue - index) > 1 / 512f) + renderScene(ms, mouseX, mouseY, lazyIndexValue < index ? index - 1 : index + 1, partialTicks); + } + + protected void renderScene(MatrixStack ms, int mouseX, int mouseY, int i, float partialTicks) { + SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance(); + PonderScene story = scenes.get(i); + double value = lazyIndex.getValue(client.getRenderPartialTicks()); + double diff = i - value; + double slide = MathHelper.lerp(diff * diff, 200, 600) * diff; + + RenderSystem.enableAlphaTest(); + RenderSystem.enableBlend(); + RenderSystem.enableDepthTest(); + + ms.push(); + story.transform.updateScreenParams(width, height, slide); + story.transform.apply(ms, partialTicks, false); + story.transform.updateSceneRVE(); + story.renderScene(buffer, ms, partialTicks); + buffer.draw(); + + MutableBoundingBox bounds = story.getBounds(); + RenderSystem.pushMatrix(); + RenderSystem.multMatrix(ms.peek() + .getModel()); + + // kool shadow fx + { + RenderSystem.enableCull(); + RenderSystem.enableDepthTest(); + RenderSystem.pushMatrix(); + RenderSystem.translated(story.basePlateOffsetX, 0, story.basePlateOffsetZ); + RenderSystem.scaled(1, -1, 1); + + float flash = finishingFlash.getValue(partialTicks) * .9f; + float alpha = flash; + flash *= flash; + flash = ((flash * 2) - 1); + flash *= flash; + flash = 1 - flash; + + for (int f = 0; f < 4; f++) { + RenderSystem.translated(story.basePlateSize, 0, 0); + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, -1 / 1024f); + if (flash > 0) { + RenderSystem.pushMatrix(); + RenderSystem.scaled(1, .5 + flash * .75, 1); + GuiUtils.drawGradientRect(ms.peek().getModel(),0, 0, -1, -story.basePlateSize, 0, 0x00_c6ffc9, + ColorHelper.applyAlpha(0xaa_c6ffc9, alpha)); + RenderSystem.popMatrix(); + } + RenderSystem.translated(0, 0, 2 / 1024f); + GuiUtils.drawGradientRect(ms.peek().getModel(), 0, 0, 0, -story.basePlateSize, 4, 0x66_000000, 0x00_000000); + RenderSystem.popMatrix(); + RenderSystem.rotatef(-90, 0, 1, 0); + } + RenderSystem.popMatrix(); + RenderSystem.disableCull(); + RenderSystem.disableDepthTest(); + } + + // coords for debug + if (PonderIndex.EDITOR_MODE && !userViewMode) { + + RenderSystem.scaled(-1, -1, 1); + RenderSystem.scaled(1 / 16d, 1 / 16d, 1 / 16d); + RenderSystem.translated(1, -8, -1 / 64f); + + // X AXIS + RenderSystem.pushMatrix(); + RenderSystem.translated(4, -3, 0); + for (int x = 0; x <= bounds.getXSize(); x++) { + RenderSystem.translated(-16, 0, 0); + textRenderer.draw(ms, x == bounds.getXSize() ? "x" : "" + x, 0, 0, 0xFFFFFFFF); + } + RenderSystem.popMatrix(); + + // Z AXIS + RenderSystem.pushMatrix(); + RenderSystem.scaled(-1, 1, 1); + RenderSystem.translated(0, -3, -4); + RenderSystem.rotatef(-90, 0, 1, 0); + RenderSystem.translated(-8, -2, 2 / 64f); + for (int z = 0; z <= bounds.getZSize(); z++) { + RenderSystem.translated(16, 0, 0); + textRenderer.draw(ms, z == bounds.getZSize() ? "z" : "" + z, 0, 0, 0xFFFFFFFF); + } + RenderSystem.popMatrix(); + + // DIRECTIONS + RenderSystem.pushMatrix(); + RenderSystem.translated(bounds.getXSize() * -8, 0, bounds.getZSize() * 8); + RenderSystem.rotatef(-90, 0, 1, 0); + for (Direction d : Iterate.horizontalDirections) { + RenderSystem.rotatef(90, 0, 1, 0); + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, bounds.getZSize() * 16); + RenderSystem.rotatef(-90, 1, 0, 0); + textRenderer.draw(ms, d.name().substring(0, 1), 0, 0, 0x66FFFFFF); + textRenderer.draw(ms, "|", 2, 10, 0x44FFFFFF); + textRenderer.draw(ms, ".", 2, 14, 0x22FFFFFF); + RenderSystem.popMatrix(); + } + RenderSystem.popMatrix(); + buffer.draw(); + } + + RenderSystem.popMatrix(); + + ms.pop(); + } + + protected void renderWidgets(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + float fade = fadeIn.getValue(partialTicks); + float lazyIndexValue = lazyIndex.getValue(partialTicks); + float indexDiff = Math.abs(lazyIndexValue - index); + PonderScene activeScene = scenes.get(index); + int textColor = 0xeeeeee; + + boolean noWidgetsHovered = true; + for (Widget widget : widgets) + noWidgetsHovered &= !widget.isMouseOver(mouseX, mouseY); + + int tooltipColor = 0xffa3a3a3; + { + // Chapter title + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, 800); + int x = 31 + 20 + 8; + int y = 31; + + String title = activeScene.getTitle(); + int wordWrappedHeight = textRenderer.getWordWrappedHeight(title, left.x - 51); + + int streakHeight = 35 - 9 + wordWrappedHeight; + UIRenderHelper.streak(ms, 0, x - 4, y - 12 + streakHeight / 2, streakHeight, (int) (150 * fade), 0x101010); + UIRenderHelper.streak(ms, 180, x - 4, y - 12 + streakHeight / 2, streakHeight, (int) (30 * fade), 0x101010); + renderBox(ms, 21, 21, 30, 30, false); + + GuiGameElement.of(stack) + .at(x - 39, y - 11) + .scale(2) + .render(ms); + + textRenderer.draw(ms, Lang.translate(PONDERING), x, y - 6, tooltipColor); + y += 8; + x += 0; + // RenderSystem.translated(0, 3 * (indexDiff), 0); + RenderSystem.translated(x, y, 0); + RenderSystem.rotatef(indexDiff * -75, 1, 0, 0); + RenderSystem.translated(0, 0, 5); + FontHelper.drawSplitString(textRenderer, title, 0, 0, left.x - 51, + ColorHelper.applyAlpha(textColor, 1 - indexDiff)); + RenderSystem.popMatrix(); + + if (chapter != null) { + RenderSystem.pushMatrix(); + + RenderSystem.translated(chap.x - 4 - 4, chap.y, 0); + UIRenderHelper.streak(ms, 180, 4, 10, 26, (int) (150 * fade), 0x101010); + + drawRightAlignedString(textRenderer, ms, Lang.translate(IN_CHAPTER).getString(), 0, 0, tooltipColor); + drawRightAlignedString(textRenderer, ms, Lang.translate(PonderLocalization.LANG_PREFIX + "chapter." + chapter.getId()).getString(), 0, 12, 0xffeeeeee); + + RenderSystem.popMatrix(); + } + + UIRenderHelper.breadcrumbArrow(width / 2 - 20, height - 51, 20, 20, 5, 0x40aa9999, 0x20aa9999); + UIRenderHelper.breadcrumbArrow(width / 2 + 20, height - 51, -20, 20, -5, 0x40aa9999, 0x20aa9999); + UIRenderHelper.breadcrumbArrow(width / 2 - 90, height - 51, 70, 20, 5, 0x40aa9999, 0x10aa9999); + UIRenderHelper.breadcrumbArrow(width / 2 + 90, height - 51, -70, 20, -5, 0x40aa9999, 0x10aa9999); + } + + if (identifyMode) { + if (noWidgetsHovered && mouseY < height - 80) { + RenderSystem.pushMatrix(); + RenderSystem.translated(mouseX, mouseY, 100); + if (hoveredTooltipItem.isEmpty()) { + IFormattableTextComponent text = Lang.translate( + IDENTIFY_MODE, + ((IFormattableTextComponent) client.gameSettings.keyBindDrop.getBoundKeyLocalizedText()).formatted(TextFormatting.WHITE) + ).formatted(TextFormatting.GRAY); + + //renderOrderedTooltip(ms, textRenderer.wrapLines(text, width / 3), 0, 0); + renderWrappedToolTip(ms, textRenderer.getTextHandler().wrapLines(text, width / 3, Style.EMPTY), 0, 0, textRenderer); + /*String tooltip = Lang + .createTranslationTextComponent(IDENTIFY_MODE, client.gameSettings.keyBindDrop.getBoundKeyLocalizedText().applyTextStyle(TextFormatting.WHITE)) + .applyTextStyle(TextFormatting.GRAY) + .getFormattedText(); + renderTooltip(font.listFormattedStringToWidth(tooltip, width / 3), 0, 0);*/ + } else + renderTooltip(ms, hoveredTooltipItem, 0, 0); + if (hoveredBlockPos != null && PonderIndex.EDITOR_MODE && !userViewMode) { + RenderSystem.translated(0, -15, 0); + boolean copied = copiedBlockPos != null && hoveredBlockPos.equals(copiedBlockPos); + IFormattableTextComponent coords = new StringTextComponent(hoveredBlockPos.getX() + ", " + hoveredBlockPos.getY() + ", " + hoveredBlockPos.getZ()) + .formatted(copied ? TextFormatting.GREEN : TextFormatting.GOLD); + renderTooltip(ms, coords, 0, 0); + } + RenderSystem.popMatrix(); + } + scan.flash(); + } else { + scan.dim(); + } + + if (PonderIndex.EDITOR_MODE) { + if (userViewMode) + userMode.flash(); + else + userMode.dim(); + } + + { + // Scene overlay + float scenePT = skipCooling > 0 ? 0 : partialTicks; + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, 100); + renderOverlay(index, scenePT); + if (indexDiff > 1 / 512f) + renderOverlay(lazyIndexValue < index ? index - 1 : index + 1, scenePT); + RenderSystem.popMatrix(); + } + + // Widgets + widgets.forEach(w -> { + if (w instanceof PonderButton) { + PonderButton mtdButton = (PonderButton) w; + mtdButton.fade(fade); + } + }); + + if (index == 0 || index == 1 && lazyIndexValue < index) + left.fade(lazyIndexValue); + if (index == scenes.size() - 1 || index == scenes.size() - 2 && lazyIndexValue > index) + right.fade(scenes.size() - lazyIndexValue - 1); + + boolean finished = activeScene.isFinished(); + if (finished) + right.flash(); + else + right.dim(); + + // Tags + List sceneTags = activeScene.tags; + boolean highlightAll = sceneTags.contains(PonderTag.Highlight.ALL); + double s = Minecraft.getInstance() + .getWindow() + .getGuiScaleFactor(); + IntStream.range(0, tagButtons.size()) + .forEach(i -> { + RenderSystem.pushMatrix(); + LerpedFloat chase = tagFades.get(i); + PonderButton button = tagButtons.get(i); + if (button.isMouseOver(mouseX, mouseY)) { + chase.updateChaseTarget(1); + } else + chase.updateChaseTarget(0); + + chase.tickChaser(); + + if (highlightAll || sceneTags.contains(this.tags.get(i))) + button.flash(); + else + button.dim(); + + int x = button.x + button.getWidth() + 4; + int y = button.y - 2; + RenderSystem.translated(x, y + 5 * (1 - fade), 800); + + float fadedWidth = 200 * chase.getValue(partialTicks); + UIRenderHelper.streak(ms, 0, 0, 12, 26, (int) fadedWidth, 0x101010); + + GL11.glScissor((int) (x * s), 0, (int) (fadedWidth * s), (int) (height * s)); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + + String tagName = this.tags.get(i) + .getTitle(); + textRenderer.draw(ms, tagName, 3, 8, 0xffeedd); + + GL11.glDisable(GL11.GL_SCISSOR_TEST); + + RenderSystem.popMatrix(); + }); + + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, 500); + int tooltipY = height - 16; + if (scan.isHovered()) + drawCenteredText(ms, textRenderer, Lang.translate(IDENTIFY), scan.x + 10, tooltipY, tooltipColor); + if (index != 0 && left.isHovered()) + drawCenteredText(ms, textRenderer, Lang.translate(PREVIOUS), left.x + 10, tooltipY, tooltipColor); + if (close.isHovered()) + drawCenteredText(ms, textRenderer, Lang.translate(CLOSE), close.x + 10, tooltipY, tooltipColor); + if (index != scenes.size() - 1 && right.isHovered()) + drawCenteredText(ms, textRenderer, Lang.translate(NEXT), right.x + 10, tooltipY, tooltipColor); + if (replay.isHovered()) + drawCenteredText(ms, textRenderer, Lang.translate(REPLAY), replay.x + 10, tooltipY, tooltipColor); + RenderSystem.popMatrix(); + } + + protected void lowerButtonGroup(MatrixStack ms, int index, int mouseX, int mouseY, float fade, AllIcons icon, KeyBinding key) { + int bWidth = 20; + int bHeight = 20; + int bX = (width - bWidth) / 2 + (index - 1) * (bWidth + 8); + int bY = height - bHeight - 31; + + RenderSystem.pushMatrix(); + if (fade < fadeIn.getChaseTarget()) + RenderSystem.translated(0, (1 - fade) * 5, 0); + boolean hovered = isMouseOver(mouseX, mouseY, bX, bY, bWidth, bHeight); + renderBox(ms, bX, bY, bWidth, bHeight, hovered); + icon.draw(ms, bX + 2, bY + 2); + drawCenteredText(ms, textRenderer, key.getBoundKeyLocalizedText(), bX + bWidth / 2 + 8, bY + bHeight - 6, 0xff606060); + RenderSystem.popMatrix(); + } + + private void renderOverlay(int i, float partialTicks) { + if (identifyMode) + return; + RenderSystem.pushMatrix(); + PonderScene story = scenes.get(i); + MatrixStack ms = new MatrixStack(); + story.renderOverlay(this, ms, partialTicks); + RenderSystem.popMatrix(); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + MutableBoolean handled = new MutableBoolean(false); + widgets.forEach(w -> { + if (handled.booleanValue()) + return; + if (!w.isMouseOver(x, y)) + return; + if (w instanceof PonderButton) { + PonderButton mtdButton = (PonderButton) w; + mtdButton.runCallback(x, y); + handled.setTrue(); + return; + } + }); + + if (handled.booleanValue()) + return true; + + if (identifyMode && hoveredBlockPos != null && PonderIndex.EDITOR_MODE) { + long handle = client.getWindow() + .getHandle(); + if (copiedBlockPos != null && button == 1) { + clipboardHelper.setClipboardString(handle, + "util.select.fromTo(" + copiedBlockPos.getX() + ", " + copiedBlockPos.getY() + ", " + + copiedBlockPos.getZ() + ", " + hoveredBlockPos.getX() + ", " + hoveredBlockPos.getY() + ", " + + hoveredBlockPos.getZ() + ")"); + copiedBlockPos = hoveredBlockPos; + return true; + } + + if (hasShiftDown()) + clipboardHelper.setClipboardString(handle, "util.select.position(" + hoveredBlockPos.getX() + ", " + + hoveredBlockPos.getY() + ", " + hoveredBlockPos.getZ() + ")"); + else + clipboardHelper.setClipboardString(handle, "util.grid.at(" + hoveredBlockPos.getX() + ", " + + hoveredBlockPos.getY() + ", " + hoveredBlockPos.getZ() + ")"); + copiedBlockPos = hoveredBlockPos; + return true; + } + + return super.mouseClicked(x, y, button); + } + + @Override + public boolean keyPressed(int code, int p_keyPressed_2_, int p_keyPressed_3_) { + GameSettings settings = Minecraft.getInstance().gameSettings; + int sCode = settings.keyBindBack.getKey() + .getKeyCode(); + int aCode = settings.keyBindLeft.getKey() + .getKeyCode(); + int dCode = settings.keyBindRight.getKey() + .getKeyCode(); + int qCode = settings.keyBindDrop.getKey() + .getKeyCode(); + + if (code == sCode) { + replay(); + return true; + } + + if (code == aCode) { + scroll(false); + return true; + } + + if (code == dCode) { + scroll(true); + return true; + } + + if (code == qCode) { + identifyMode = !identifyMode; + if (!identifyMode) + scenes.get(index) + .deselect(); + return true; + } + + return super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_); + } + + @Override + protected String getBreadcrumbTitle() { + if (chapter != null) + return Lang.translate(PonderLocalization.LANG_PREFIX + "chapter." + chapter.getId()).getString(); + + return stack.getItem() + .getName() + .getString(); + } + + public FontRenderer getFontRenderer() { + return textRenderer; + } + + protected boolean isMouseOver(double mouseX, double mouseY, int x, int y, int w, int h) { + boolean hovered = !(mouseX < x || mouseX > x + w); + hovered &= !(mouseY < y || mouseY > y + h); + return hovered; + } + + public static void renderBox(MatrixStack ms, int x, int y, int w, int h, boolean highlighted) { + renderBox(ms, x, y, w, h, 0xff000000, highlighted ? 0xf0ffeedd : 0x40ffeedd, highlighted ? 0x60ffeedd : 0x20ffeedd); + } + + public static void renderSpeechBox(MatrixStack ms, int x, int y, int w, int h, boolean highlighted, Pointing pointing, + boolean returnWithLocalTransform) { + if (!returnWithLocalTransform) + RenderSystem.pushMatrix(); + + int boxX = x; + int boxY = y; + int divotX = x; + int divotY = y; + int divotRotation = 0; + int divotSize = 8; + int distance = 1; + int divotRadius = divotSize / 2; + + switch (pointing) { + default: + case DOWN: + divotRotation = 0; + boxX -= w / 2; + boxY -= h + divotSize + 1 + distance; + divotX -= divotRadius; + divotY -= divotSize + distance; + break; + case LEFT: + divotRotation = 90; + boxX += divotSize + 1 + distance; + boxY -= h / 2; + divotX += distance; + divotY -= divotRadius; + break; + case RIGHT: + divotRotation = 270; + boxX -= w + divotSize + 1 + distance; + boxY -= h / 2; + divotX -= divotSize + distance; + divotY -= divotRadius; + break; + case UP: + divotRotation = 180; + boxX -= w / 2; + boxY += divotSize + 1 + distance; + divotX -= divotRadius; + divotY += distance; + break; + } + + renderBox(ms, boxX, boxY, w, h, highlighted); + + RenderSystem.pushMatrix(); + AllGuiTextures toRender = highlighted ? AllGuiTextures.SPEECH_TOOLTIP_HIGHLIGHT : AllGuiTextures.SPEECH_TOOLTIP; + RenderSystem.translated(divotX + divotRadius, divotY + divotRadius, 10); + RenderSystem.rotatef(divotRotation, 0, 0, 1); + RenderSystem.translated(-divotRadius, -divotRadius, 0); + toRender.draw(ms, 0, 0); + RenderSystem.popMatrix(); + + if (returnWithLocalTransform) { + RenderSystem.translated(boxX, boxY, 0); + return; + } + + RenderSystem.popMatrix(); + + } + + public static void renderBox(MatrixStack ms, int x, int y, int w, int h, int backgroundColor, int borderColorStart, + int borderColorEnd) { + int z = 100; + Matrix4f model = ms.peek().getModel(); + GuiUtils.drawGradientRect(model, z, x - 3, y - 4, x + w + 3, y - 3, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(model, z, x - 3, y + h + 3, x + w + 3, y + h + 4, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(model, z, x - 3, y - 3, x + w + 3, y + h + 3, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(model, z, x - 4, y - 3, x - 3, y + h + 3, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(model, z, x + w + 3, y - 3, x + w + 4, y + h + 3, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(model, z, x - 3, y - 3 + 1, x - 3 + 1, y + h + 3 - 1, borderColorStart, borderColorEnd); + GuiUtils.drawGradientRect(model, z, x + w + 2, y - 3 + 1, x + w + 3, y + h + 3 - 1, borderColorStart, borderColorEnd); + GuiUtils.drawGradientRect(model, z, x - 3, y - 3, x + w + 3, y - 3 + 1, borderColorStart, borderColorStart); + GuiUtils.drawGradientRect(model, z, x - 3, y + h + 2, x + w + 3, y + h + 3, borderColorEnd, borderColorEnd); + } + + public ItemStack getHoveredTooltipItem() { + return hoveredTooltipItem; + } + + public ItemStack getSubject() { + return stack; + } + + @Override + public boolean isEquivalentTo(NavigatableSimiScreen other) { + if (other instanceof PonderUI) + return stack.isItemEqual(((PonderUI) other).stack); + return super.isEquivalentTo(other); + } + + @Override + public void shareContextWith(NavigatableSimiScreen other) { + if (other instanceof PonderUI) { + PonderUI ponderUI = (PonderUI) other; + ponderUI.referredToByTag = referredToByTag; + } + } + + public static float getPartialTicks() { + if (Minecraft.getInstance().currentScreen instanceof PonderUI) { + PonderUI ui = (PonderUI) Minecraft.getInstance().currentScreen; + if (ui.identifyMode) + return ponderPartialTicksPaused; + } + return Minecraft.getInstance() + .getRenderPartialTicks(); + } + + @Override + public boolean isPauseScreen() { + return true; + } + + public void coolDownAfterSkip() { + skipCooling = 15; + } + + @Override + public void removed() { + super.removed(); + SuperRenderTypeBuffer.vertexSortingOrigin = BlockPos.ZERO; + } + + public void drawRightAlignedString(FontRenderer fontRenderer, MatrixStack ms, String string, int x, int y, int color) { + fontRenderer.draw(ms, string, (float)(x - fontRenderer.getStringWidth(string)), (float)y, color); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderWorld.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderWorld.java new file mode 100644 index 000000000..5d4257119 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderWorld.java @@ -0,0 +1,301 @@ +package com.simibubi.create.foundation.ponder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; +import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; +import com.simibubi.create.content.schematics.SchematicWorld; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.IParticleFactory; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleManager; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.inventory.container.PlayerContainer; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.BlockParticleData; +import net.minecraft.particles.IParticleData; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.LightType; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.registries.ForgeRegistries; + +public class PonderWorld extends SchematicWorld { + + public PonderScene scene; + + protected Map originalBlocks; + protected Map originalTileEntities; + protected Map blockBreakingProgressions; + protected List originalEntities; + + protected PonderWorldParticles particles; + private final Map> particleFactories; + + int overrideLight; + Selection mask; + + public PonderWorld(BlockPos anchor, World original) { + super(anchor, original); + originalBlocks = new HashMap<>(); + originalTileEntities = new HashMap<>(); + blockBreakingProgressions = new HashMap<>(); + originalEntities = new ArrayList<>(); + particles = new PonderWorldParticles(this); + + // ParticleManager.factories - ATs don't seem to like this one + particleFactories = ObfuscationReflectionHelper.getPrivateValue(ParticleManager.class, + Minecraft.getInstance().particles, "field_178932_g"); + } + + public void createBackup() { + originalBlocks.clear(); + originalTileEntities.clear(); + blocks.forEach((k, v) -> originalBlocks.put(k, v)); + tileEntities.forEach((k, v) -> originalTileEntities.put(k, TileEntity.createFromTag(blocks.get(k), v.write(new CompoundNBT())))); + entities.forEach(e -> EntityType.loadEntityUnchecked(e.serializeNBT(), this) + .ifPresent(originalEntities::add)); + } + + public void restore() { + entities.clear(); + blocks.clear(); + tileEntities.clear(); + blockBreakingProgressions.clear(); + renderedTileEntities.clear(); + originalBlocks.forEach((k, v) -> blocks.put(k, v)); + originalTileEntities.forEach((k, v) -> { + TileEntity te = TileEntity.createFromTag(originalBlocks.get(k), v.write(new CompoundNBT())); + te.setLocation(this, te.getPos()); + tileEntities.put(k, te); + renderedTileEntities.add(te); + }); + originalEntities.forEach(e -> EntityType.loadEntityUnchecked(e.serializeNBT(), this) + .ifPresent(entities::add)); + particles.clearEffects(); + fixVirtualTileEntities(); + } + + public void restoreBlocks(Selection selection) { + selection.forEach(p -> { + if (originalBlocks.containsKey(p)) + blocks.put(p, originalBlocks.get(p)); + }); + scene.forEach(WorldSectionElement.class, WorldSectionElement::queueRedraw); + } + + public void pushFakeLight(int light) { + this.overrideLight = light; + } + + public void popLight() { + this.overrideLight = -1; + } + + @Override + public int getLightLevel(LightType p_226658_1_, BlockPos p_226658_2_) { + return overrideLight == -1 ? 15 : overrideLight; + } + + public void setMask(Selection mask) { + this.mask = mask; + } + + public void clearMask() { + this.mask = null; + } + + @Override + public BlockState getBlockState(BlockPos globalPos) { + if (mask != null && !mask.test(globalPos.subtract(anchor))) + return Blocks.AIR.getDefaultState(); + return super.getBlockState(globalPos); + } + + @Override // For particle collision + public IBlockReader getExistingChunk(int p_225522_1_, int p_225522_2_) { + return this; + } + + public void renderEntities(MatrixStack ms, SuperRenderTypeBuffer buffer, ActiveRenderInfo ari, float pt) { + Vector3d Vector3d = ari.getProjectedView(); + double d0 = Vector3d.getX(); + double d1 = Vector3d.getY(); + double d2 = Vector3d.getZ(); + + for (Entity entity : entities) { + if (entity.ticksExisted == 0) { + entity.lastTickPosX = entity.getX(); + entity.lastTickPosY = entity.getY(); + entity.lastTickPosZ = entity.getZ(); + } + renderEntity(entity, d0, d1, d2, pt, ms, buffer); + } + + buffer.draw(RenderType.getEntitySolid(PlayerContainer.BLOCK_ATLAS_TEXTURE)); + buffer.draw(RenderType.getEntityCutout(PlayerContainer.BLOCK_ATLAS_TEXTURE)); + buffer.draw(RenderType.getEntityCutoutNoCull(PlayerContainer.BLOCK_ATLAS_TEXTURE)); + buffer.draw(RenderType.getEntitySmoothCutout(PlayerContainer.BLOCK_ATLAS_TEXTURE)); + } + + private void renderEntity(Entity entity, double x, double y, double z, float pt, MatrixStack ms, + IRenderTypeBuffer buffer) { + double d0 = MathHelper.lerp((double) pt, entity.lastTickPosX, entity.getX()); + double d1 = MathHelper.lerp((double) pt, entity.lastTickPosY, entity.getY()); + double d2 = MathHelper.lerp((double) pt, entity.lastTickPosZ, entity.getZ()); + float f = MathHelper.lerp(pt, entity.prevRotationYaw, entity.rotationYaw); + EntityRendererManager renderManager = Minecraft.getInstance() + .getRenderManager(); + int light = renderManager.getRenderer(entity) + .getLight(entity, pt); + renderManager.render(entity, d0 - x, d1 - y, d2 - z, f, pt, ms, buffer, light); + } + + public void renderParticles(MatrixStack ms, IRenderTypeBuffer buffer, ActiveRenderInfo ari, float pt) { + particles.renderParticles(ms, buffer, ari, pt); + } + + public void tick() { + particles.tick(); + + for (Iterator iterator = entities.iterator(); iterator.hasNext();) { + Entity entity = iterator.next(); + + entity.ticksExisted++; + entity.lastTickPosX = entity.getX(); + entity.lastTickPosY = entity.getY(); + entity.lastTickPosZ = entity.getZ(); + entity.tick(); + + if (entity.getY() <= -.5f) + entity.remove(); + + if (!entity.isAlive()) + iterator.remove(); + } + } + + @Override + public void addParticle(IParticleData data, double x, double y, double z, double mx, double my, double mz) { + addParticle(makeParticle(data, x, y, z, mx, my, mz)); + } + + @Nullable + @SuppressWarnings("unchecked") + private Particle makeParticle(T data, double x, double y, double z, double mx, double my, + double mz) { + ResourceLocation key = ForgeRegistries.PARTICLE_TYPES.getKey(data.getType()); + IParticleFactory iparticlefactory = (IParticleFactory) particleFactories.get(key); + return null;//return iparticlefactory == null ? null : iparticlefactory.makeParticle(data, this, x, y, z, mx, my, mz); TODO 1.16 + } + + public void addParticle(Particle p) { + if (p != null) + particles.addParticle(p); + } + + public void fixVirtualTileEntities() { + for (TileEntity tileEntity : tileEntities.values()) { + if (!(tileEntity instanceof SmartTileEntity)) + continue; + SmartTileEntity smartTileEntity = (SmartTileEntity) tileEntity; + smartTileEntity.markVirtual(); + + if (!(smartTileEntity instanceof BeltTileEntity)) + continue; + BeltTileEntity beltTileEntity = (BeltTileEntity) smartTileEntity; + if (!beltTileEntity.isController()) + continue; + BlockPos controllerPos = tileEntity.getPos(); + for (BlockPos blockPos : BeltBlock.getBeltChain(this, controllerPos)) { + TileEntity tileEntity2 = getTileEntity(blockPos); + if (!(tileEntity2 instanceof BeltTileEntity)) + continue; + BeltTileEntity belt2 = (BeltTileEntity) tileEntity2; + belt2.setController(controllerPos); + } + } + } + + public void setBlockBreakingProgress(BlockPos pos, int damage) { + if (damage == 0) + blockBreakingProgressions.remove(pos); + else + blockBreakingProgressions.put(pos, damage - 1); + } + + public Map getBlockBreakingProgressions() { + return blockBreakingProgressions; + } + + public void addBlockDestroyEffects(BlockPos pos, BlockState state) { + VoxelShape voxelshape = state.getShape(this, pos); + if (voxelshape.isEmpty()) + return; + + AxisAlignedBB bb = voxelshape.getBoundingBox(); + double d1 = Math.min(1.0D, bb.maxX - bb.minX); + double d2 = Math.min(1.0D, bb.maxY - bb.minY); + double d3 = Math.min(1.0D, bb.maxZ - bb.minZ); + int i = Math.max(2, MathHelper.ceil(d1 / 0.25D)); + int j = Math.max(2, MathHelper.ceil(d2 / 0.25D)); + int k = Math.max(2, MathHelper.ceil(d3 / 0.25D)); + + for (int l = 0; l < i; ++l) { + for (int i1 = 0; i1 < j; ++i1) { + for (int j1 = 0; j1 < k; ++j1) { + double d4 = (l + 0.5D) / i; + double d5 = (i1 + 0.5D) / j; + double d6 = (j1 + 0.5D) / k; + double d7 = d4 * d1 + bb.minX; + double d8 = d5 * d2 + bb.minY; + double d9 = d6 * d3 + bb.minZ; + addParticle(new BlockParticleData(ParticleTypes.BLOCK, state), pos.getX() + d7, pos.getY() + d8, + pos.getZ() + d9, d4 - 0.5D, d5 - 0.5D, d6 - 0.5D); + } + } + } + } + + @Override + protected BlockState processBlockStateForPrinting(BlockState state) { + return state; + } + + @Override + public boolean chunkExists(int x, int y) { + return true; // fix particle lighting + } + + @Override + public boolean isBlockPresent(BlockPos pos) { + return true; // fix particle lighting + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderWorldParticles.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderWorldParticles.java new file mode 100644 index 000000000..49efd996c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderWorldParticles.java @@ -0,0 +1,108 @@ +package com.simibubi.create.foundation.ponder; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Queue; + +import com.google.common.collect.EvictingQueue; +import com.google.common.collect.Maps; +import com.google.common.collect.Queues; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.IParticleRenderType; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.Tessellator; + +public class PonderWorldParticles { + + private final Map> byType = Maps.newIdentityHashMap(); + private final Queue queue = Queues.newArrayDeque(); + + PonderWorld world; + + public PonderWorldParticles(PonderWorld world) { + this.world = world; + } + + public void addParticle(Particle p) { + this.queue.add(p); + } + + public void tick() { + this.byType.forEach((p_228347_1_, p_228347_2_) -> this.tickParticleList(p_228347_2_)); + + Particle particle; + if (queue.isEmpty()) + return; + while ((particle = this.queue.poll()) != null) + this.byType.computeIfAbsent(particle.getRenderType(), $ -> EvictingQueue.create(16384)) + .add(particle); + } + + private void tickParticleList(Collection p_187240_1_) { + if (p_187240_1_.isEmpty()) + return; + + Iterator iterator = p_187240_1_.iterator(); + while (iterator.hasNext()) { + Particle particle = iterator.next(); + particle.tick(); + if (!particle.isAlive()) + iterator.remove(); + } + } + + public void renderParticles(MatrixStack ms, IRenderTypeBuffer buffer, ActiveRenderInfo renderInfo, float pt) { + Minecraft mc = Minecraft.getInstance(); + LightTexture lightTexture = mc.gameRenderer.getLightmapTextureManager(); + + lightTexture.enableLightmap(); + Runnable enable = () -> { + RenderSystem.enableAlphaTest(); + RenderSystem.defaultAlphaFunc(); + RenderSystem.enableDepthTest(); + RenderSystem.enableFog(); + }; + RenderSystem.pushMatrix(); + RenderSystem.multMatrix(ms.peek() + .getModel()); + + for (IParticleRenderType iparticlerendertype : this.byType.keySet()) { // Forge: allow custom + // IParticleRenderType's + if (iparticlerendertype == IParticleRenderType.NO_RENDER) + continue; + enable.run(); // Forge: MC-168672 Make sure all render types have the correct GL state. + Iterable iterable = this.byType.get(iparticlerendertype); + if (iterable != null) { + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + iparticlerendertype.beginRender(bufferbuilder, mc.textureManager); + + for (Particle particle : iterable) + particle.buildGeometry(bufferbuilder, renderInfo, pt); + + iparticlerendertype.finishRender(tessellator); + } + } + + RenderSystem.popMatrix(); + RenderSystem.depthMask(true); + RenderSystem.disableBlend(); + RenderSystem.defaultAlphaFunc(); + lightTexture.disableLightmap(); + RenderSystem.disableFog(); + } + + public void clearEffects() { + this.byType.clear(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java b/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java new file mode 100644 index 000000000..8c49383b6 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java @@ -0,0 +1,793 @@ +package com.simibubi.create.foundation.ponder; + +import java.util.Optional; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; +import com.simibubi.create.content.contraptions.base.KineticBlock; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueItem; +import com.simibubi.create.content.contraptions.particle.RotationIndicatorParticleData; +import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; +import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; +import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; +import com.simibubi.create.foundation.ponder.content.PonderPalette; +import com.simibubi.create.foundation.ponder.elements.AnimatedSceneElement; +import com.simibubi.create.foundation.ponder.elements.BeltItemElement; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.MinecartElement; +import com.simibubi.create.foundation.ponder.elements.MinecartElement.MinecartConstructor; +import com.simibubi.create.foundation.ponder.elements.ParrotElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement.ParrotPose; +import com.simibubi.create.foundation.ponder.elements.ParrotElement.SpinOnComponentPose; +import com.simibubi.create.foundation.ponder.elements.TextWindowElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.ponder.instructions.AnimateMinecartInstruction; +import com.simibubi.create.foundation.ponder.instructions.AnimateParrotInstruction; +import com.simibubi.create.foundation.ponder.instructions.AnimateTileEntityInstruction; +import com.simibubi.create.foundation.ponder.instructions.AnimateWorldSectionInstruction; +import com.simibubi.create.foundation.ponder.instructions.ChaseAABBInstruction; +import com.simibubi.create.foundation.ponder.instructions.CreateMinecartInstruction; +import com.simibubi.create.foundation.ponder.instructions.CreateParrotInstruction; +import com.simibubi.create.foundation.ponder.instructions.DelayInstruction; +import com.simibubi.create.foundation.ponder.instructions.DisplayWorldSectionInstruction; +import com.simibubi.create.foundation.ponder.instructions.EmitParticlesInstruction; +import com.simibubi.create.foundation.ponder.instructions.EmitParticlesInstruction.Emitter; +import com.simibubi.create.foundation.ponder.instructions.FadeOutOfSceneInstruction; +import com.simibubi.create.foundation.ponder.instructions.HighlightValueBoxInstruction; +import com.simibubi.create.foundation.ponder.instructions.KeyframeInstruction; +import com.simibubi.create.foundation.ponder.instructions.LineInstruction; +import com.simibubi.create.foundation.ponder.instructions.MarkAsFinishedInstruction; +import com.simibubi.create.foundation.ponder.instructions.MovePoiInstruction; +import com.simibubi.create.foundation.ponder.instructions.OutlineSelectionInstruction; +import com.simibubi.create.foundation.ponder.instructions.ReplaceBlocksInstruction; +import com.simibubi.create.foundation.ponder.instructions.RotateSceneInstruction; +import com.simibubi.create.foundation.ponder.instructions.ShowInputInstruction; +import com.simibubi.create.foundation.ponder.instructions.TextInstruction; +import com.simibubi.create.foundation.ponder.instructions.TileEntityDataInstruction; +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.RedstoneTorchBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.RedstoneParticleData; +import net.minecraft.state.Property; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector3i; +import net.minecraft.world.World; + +/** + * Enqueue instructions to the schedule via this object's methods. + */ +public class SceneBuilder { + + /** + * Ponder's toolkit for showing information on top of the scene world, such as + * highlighted bounding boxes, texts, icons and keybindings. + */ + public final OverlayInstructions overlay; + + /** + * Instructions for manipulating the schematic and its currently visible areas. + * Allows to show, hide and modify blocks as the scene plays out. + */ + public final WorldInstructions world; + + /** + * Additional tools for debugging ponder and bypassing the facade + */ + public final DebugInstructions debug; + + /** + * Special effects to embellish and communicate with + */ + public final EffectInstructions effects; + + /** + * Random other instructions that might come in handy + */ + public final SpecialInstructions special; + + private final PonderScene scene; + + public SceneBuilder(PonderScene ponderScene) { + scene = ponderScene; + overlay = new OverlayInstructions(); + special = new SpecialInstructions(); + world = new WorldInstructions(); + debug = new DebugInstructions(); + effects = new EffectInstructions(); + } + + // General + + /** + * Assign a unique translation key, as well as the standard english translation + * for this scene's title using this method, anywhere inside the program + * function. + * + * @param sceneId + * @param title + */ + public void title(String sceneId, String title) { + scene.sceneId = sceneId; + PonderLocalization.registerSpecific(sceneId, PonderScene.TITLE_KEY, title); + } + + /** + * Communicates to the ponder UI which parts of the schematic make up the base + * horizontally. Use of this is encouraged whenever there are components outside + * the the base plate.
+ * As a result, showBasePlate() will only show the configured size, and the + * scene's scaling inside the UI will be consistent with its base size. + * + * @param xOffset Block spaces between the base plate and the schematic + * boundary on the Western side. + * @param zOffset Block spaces between the base plate and the schematic + * boundary on the Northern side. + * @param basePlateSize Length in blocks of the base plate itself. Ponder + * assumes it to be square + */ + public void configureBasePlate(int xOffset, int zOffset, int basePlateSize) { + scene.basePlateOffsetX = xOffset; + scene.basePlateOffsetZ = zOffset; + scene.basePlateSize = basePlateSize; + } + + /** + * Use this in case you are not happy with the scale of the scene relative to + * the overlay + * + * @param factor >1 will make the scene appear larger, smaller otherwise + */ + public void scaleSceneView(float factor) { + scene.scaleFactor = factor; + } + + /** + * Use this in case you are not happy with the vertical alignment of the scene + * relative to the overlay + * + * @param yOffset >0 moves the scene up, down otherwise + */ + public void setSceneOffsetY(float yOffset) { + scene.yOffset = yOffset; + } + + /** + * Fade the layer of blocks into the scene ponder assumes to be the base plate + * of the schematic's structure. Makes for a nice opener + */ + public void showBasePlate() { + world.showSection( + scene.getSceneBuildingUtil().select.cuboid(new BlockPos(scene.basePlateOffsetX, 0, scene.basePlateOffsetZ), + new Vector3i(scene.basePlateSize - 1, 0, scene.basePlateSize - 1)), + Direction.UP); + } + + /** + * Before running the upcoming instructions, wait for a duration to let previous + * actions play out.
+ * Idle does not stall any animations, only schedules a time gap between + * instructions. + * + * @param ticks Duration to wait for + */ + public void idle(int ticks) { + addInstruction(new DelayInstruction(ticks)); + } + + /** + * Before running the upcoming instructions, wait for a duration to let previous + * actions play out.
+ * Idle does not stall any animations, only schedules a time gap between + * instructions. + * + * @param seconds Duration to wait for + */ + public void idleSeconds(int seconds) { + idle(seconds * 20); + } + + /** + * Once the scene reaches this instruction in the timeline, mark it as + * "finished". This happens automatically when the end of a storyboard is + * reached, but can be desirable to do earlier, in order to bypass the wait for + * any residual text windows to time out.
+ * So far this event only affects the "next scene" button in the UI to flash. + */ + public void markAsFinished() { + addInstruction(new MarkAsFinishedInstruction()); + } + + /** + * Pans the scene's camera view around the vertical axis by the given amount + * + * @param degrees + */ + public void rotateCameraY(float degrees) { + addInstruction(new RotateSceneInstruction(0, degrees, true)); + } + + /** + * Adds a Key Frame at the end of the last delay() instruction for the users to + * skip to + */ + public void addKeyframe() { + addInstruction(KeyframeInstruction.IMMEDIATE); + } + + /** + * Adds a Key Frame a couple ticks after the last delay() instruction for the + * users to skip to + */ + public void addLazyKeyframe() { + addInstruction(KeyframeInstruction.DELAYED); + } + + public class EffectInstructions { + + public void emitParticles(Vector3d location, Emitter emitter, float amountPerCycle, int cycles) { + addInstruction(new EmitParticlesInstruction(location, emitter, amountPerCycle, cycles)); + } + + public void superGlue(BlockPos pos, Direction side, boolean fullBlock) { + addInstruction(scene -> SuperGlueItem.spawnParticles(scene.world, pos, side, fullBlock)); + } + + private void rotationIndicator(BlockPos pos, boolean direction) { + addInstruction(scene -> { + BlockState blockState = scene.world.getBlockState(pos); + TileEntity tileEntity = scene.world.getTileEntity(pos); + + if (!(blockState.getBlock() instanceof KineticBlock)) + return; + if (!(tileEntity instanceof KineticTileEntity)) + return; + + KineticTileEntity kte = (KineticTileEntity) tileEntity; + KineticBlock kb = (KineticBlock) blockState.getBlock(); + Axis rotationAxis = kb.getRotationAxis(blockState); + + float speed = kte.getTheoreticalSpeed(); + SpeedLevel speedLevel = SpeedLevel.of(speed); + int color = direction ? speed > 0 ? 0xeb5e0b : 0x1687a7 : speedLevel.getColor(); + int particleSpeed = speedLevel.getParticleSpeed(); + particleSpeed *= Math.signum(speed); + + Vector3d location = VecHelper.getCenterOf(pos); + RotationIndicatorParticleData particleData = new RotationIndicatorParticleData(color, particleSpeed, + kb.getParticleInitialRadius(), kb.getParticleTargetRadius(), 20, rotationAxis.name() + .charAt(0)); + + for (int i = 0; i < 20; i++) + scene.world.addParticle(particleData, location.x, location.y, location.z, 0, 0, 0); + }); + } + + public void rotationSpeedIndicator(BlockPos pos) { + rotationIndicator(pos, false); + } + + public void rotationDirectionIndicator(BlockPos pos) { + rotationIndicator(pos, true); + } + + public void indicateRedstone(BlockPos pos) { + createRedstoneParticles(pos, 0xFF0000, 10); + } + + public void indicateSuccess(BlockPos pos) { + createRedstoneParticles(pos, 0x80FFaa, 10); + } + + public void createRedstoneParticles(BlockPos pos, int color, int amount) { + Vector3d rgb = ColorHelper.getRGB(color); + addInstruction(new EmitParticlesInstruction(VecHelper.getCenterOf(pos), Emitter.withinBlockSpace( + new RedstoneParticleData((float) rgb.x, (float) rgb.y, (float) rgb.z, 1), Vector3d.ZERO), amount, 2)); + } + + } + + public class OverlayInstructions { + + public TextWindowElement.Builder showText(int duration) { + TextWindowElement textWindowElement = new TextWindowElement(); + addInstruction(new TextInstruction(textWindowElement, duration)); + return textWindowElement.new Builder(scene); + } + + public TextWindowElement.Builder showSelectionWithText(Selection selection, int duration) { + TextWindowElement textWindowElement = new TextWindowElement(); + addInstruction(new TextInstruction(textWindowElement, duration, selection)); + return textWindowElement.new Builder(scene).pointAt(selection.getCenter()); + } + + public void showControls(InputWindowElement element, int duration) { + addInstruction(new ShowInputInstruction(element.clone(), duration)); + } + + public void chaseBoundingBoxOutline(PonderPalette color, Object slot, AxisAlignedBB boundingBox, int duration) { + addInstruction(new ChaseAABBInstruction(color, slot, boundingBox, duration)); + } + + public void showCenteredScrollInput(BlockPos pos, Direction side, int duration) { + showScrollInput(scene.getSceneBuildingUtil().vector.blockSurface(pos, side), side, duration); + } + + public void showScrollInput(Vector3d location, Direction side, int duration) { + Axis axis = side.getAxis(); + float s = 1 / 16f; + float q = 1 / 4f; + Vector3d expands = new Vector3d(axis == Axis.X ? s : q, axis == Axis.Y ? s : q, axis == Axis.Z ? s : q); + addInstruction(new HighlightValueBoxInstruction(location, expands, duration)); + } + + public void showRepeaterScrollInput(BlockPos pos, int duration) { + float s = 1 / 16f; + float q = 1 / 6f; + Vector3d expands = new Vector3d(q, s, q); + addInstruction( + new HighlightValueBoxInstruction(scene.getSceneBuildingUtil().vector.blockSurface(pos, Direction.DOWN) + .add(0, 3 / 16f, 0), expands, duration)); + } + + public void showFilterSlotInput(Vector3d location, int duration) { + float s = .1f; + Vector3d expands = new Vector3d(s, s, s); + addInstruction(new HighlightValueBoxInstruction(location, expands, duration)); + } + + public void showLine(PonderPalette color, Vector3d start, Vector3d end, int duration) { + addInstruction(new LineInstruction(color, start, end, duration)); + } + + public void showOutline(PonderPalette color, Object slot, Selection selection, int duration) { + addInstruction(new OutlineSelectionInstruction(color, slot, selection, duration)); + } + + public void hideElement(ElementLink link, Direction direction) { + addInstruction(new FadeOutOfSceneInstruction<>(15, direction, link)); + } + + } + + public class SpecialInstructions { + + public ElementLink birbOnTurntable(BlockPos pos) { + return createBirb(VecHelper.getCenterOf(pos), () -> new SpinOnComponentPose(pos)); + } + + public ElementLink birbOnSpinnyShaft(BlockPos pos) { + return createBirb(VecHelper.getCenterOf(pos) + .add(0, 0.5, 0), () -> new SpinOnComponentPose(pos)); + } + + public ElementLink createBirb(Vector3d location, Supplier pose) { + ElementLink link = new ElementLink<>(ParrotElement.class); + ParrotElement parrot = ParrotElement.create(location, pose); + addInstruction(new CreateParrotInstruction(10, Direction.DOWN, parrot)); + addInstruction(scene -> scene.linkElement(parrot, link)); + return link; + } + + public void changeBirbPose(ElementLink birb, Supplier pose) { + addInstruction(scene -> scene.resolve(birb) + .setPose(pose.get())); + } + + public void movePointOfInterest(Vector3d location) { + addInstruction(new MovePoiInstruction(location)); + } + + public void movePointOfInterest(BlockPos location) { + movePointOfInterest(VecHelper.getCenterOf(location)); + } + + public void rotateParrot(ElementLink link, double xRotation, double yRotation, double zRotation, + int duration) { + addInstruction(AnimateParrotInstruction.rotate(link, new Vector3d(xRotation, yRotation, zRotation), duration)); + } + + public void moveParrot(ElementLink link, Vector3d offset, int duration) { + addInstruction(AnimateParrotInstruction.move(link, offset, duration)); + } + + public ElementLink createCart(Vector3d location, float angle, MinecartConstructor type) { + ElementLink link = new ElementLink<>(MinecartElement.class); + MinecartElement cart = new MinecartElement(location, angle, type); + addInstruction(new CreateMinecartInstruction(10, Direction.DOWN, cart)); + addInstruction(scene -> scene.linkElement(cart, link)); + return link; + } + + public void rotateCart(ElementLink link, float yRotation, int duration) { + addInstruction(AnimateMinecartInstruction.rotate(link, yRotation, duration)); + } + + public void moveCart(ElementLink link, Vector3d offset, int duration) { + addInstruction(AnimateMinecartInstruction.move(link, offset, duration)); + } + + } + + public class WorldInstructions { + + public void incrementBlockBreakingProgress(BlockPos pos) { + addInstruction(scene -> { + PonderWorld world = scene.getWorld(); + int progress = world.getBlockBreakingProgressions() + .getOrDefault(pos, -1) + 1; + if (progress == 9) { + world.addBlockDestroyEffects(pos, world.getBlockState(pos)); + world.destroyBlock(pos, false); + world.setBlockBreakingProgress(pos, 0); + scene.forEach(WorldSectionElement.class, WorldSectionElement::queueRedraw); + } else + world.setBlockBreakingProgress(pos, progress + 1); + }); + } + + public void showSection(Selection selection, Direction fadeInDirection) { + addInstruction(new DisplayWorldSectionInstruction(15, fadeInDirection, selection, + Optional.of(scene::getBaseWorldSection))); + } + + public void showSectionAndMerge(Selection selection, Direction fadeInDirection, + ElementLink link) { + addInstruction(new DisplayWorldSectionInstruction(15, fadeInDirection, selection, + Optional.of(() -> scene.resolve(link)))); + } + + public void glueBlockOnto(BlockPos position, Direction fadeInDirection, ElementLink link) { + addInstruction(new DisplayWorldSectionInstruction(15, fadeInDirection, + scene.getSceneBuildingUtil().select.position(position), Optional.of(() -> scene.resolve(link)), + position)); + } + + public ElementLink showIndependentSection(Selection selection, Direction fadeInDirection) { + DisplayWorldSectionInstruction instruction = + new DisplayWorldSectionInstruction(15, fadeInDirection, selection, Optional.empty()); + addInstruction(instruction); + return instruction.createLink(scene); + } + + public ElementLink showIndependentSectionImmediately(Selection selection) { + DisplayWorldSectionInstruction instruction = + new DisplayWorldSectionInstruction(0, Direction.DOWN, selection, Optional.empty()); + addInstruction(instruction); + return instruction.createLink(scene); + } + + public void hideSection(Selection selection, Direction fadeOutDirection) { + WorldSectionElement worldSectionElement = new WorldSectionElement(selection); + ElementLink elementLink = new ElementLink<>(WorldSectionElement.class); + + addInstruction(scene -> { + scene.getBaseWorldSection() + .erase(selection); + scene.linkElement(worldSectionElement, elementLink); + scene.addElement(worldSectionElement); + worldSectionElement.queueRedraw(); + }); + + hideIndependentSection(elementLink, fadeOutDirection); + } + + public void hideIndependentSection(ElementLink link, Direction fadeOutDirection) { + addInstruction(new FadeOutOfSceneInstruction<>(15, fadeOutDirection, link)); + } + + public void restoreBlocks(Selection selection) { + addInstruction(scene -> scene.world.restoreBlocks(selection)); + } + + public ElementLink makeSectionIndependent(Selection selection) { + WorldSectionElement worldSectionElement = new WorldSectionElement(selection); + ElementLink elementLink = new ElementLink<>(WorldSectionElement.class); + + addInstruction(scene -> { + scene.getBaseWorldSection() + .erase(selection); + scene.linkElement(worldSectionElement, elementLink); + scene.addElement(worldSectionElement); + worldSectionElement.queueRedraw(); + worldSectionElement.resetAnimatedTransform(); + worldSectionElement.setVisible(true); + worldSectionElement.forceApplyFade(1); + }); + + return elementLink; + } + + public void rotateSection(ElementLink link, double xRotation, double yRotation, + double zRotation, int duration) { + addInstruction( + AnimateWorldSectionInstruction.rotate(link, new Vector3d(xRotation, yRotation, zRotation), duration)); + } + + public void configureCenterOfRotation(ElementLink link, Vector3d anchor) { + addInstruction(scene -> scene.resolve(link) + .setCenterOfRotation(anchor)); + } + + public void configureStabilization(ElementLink link, Vector3d anchor) { + addInstruction(scene -> scene.resolve(link) + .stabilizeRotation(anchor)); + } + + public void moveSection(ElementLink link, Vector3d offset, int duration) { + addInstruction(AnimateWorldSectionInstruction.move(link, offset, duration)); + } + + public void rotateBearing(BlockPos pos, float angle, int duration) { + addInstruction(AnimateTileEntityInstruction.bearing(pos, angle, duration)); + } + + public void movePulley(BlockPos pos, float distance, int duration) { + addInstruction(AnimateTileEntityInstruction.pulley(pos, distance, duration)); + } + + public void moveDeployer(BlockPos pos, float distance, int duration) { + addInstruction(AnimateTileEntityInstruction.deployer(pos, distance, duration)); + } + + public void setBlocks(Selection selection, BlockState state, boolean spawnParticles) { + addInstruction(new ReplaceBlocksInstruction(selection, $ -> state, true, spawnParticles)); + } + + public void destroyBlock(BlockPos pos) { + setBlock(pos, Blocks.AIR.getDefaultState(), true); + } + + public void setBlock(BlockPos pos, BlockState state, boolean spawnParticles) { + setBlocks(scene.getSceneBuildingUtil().select.position(pos), state, spawnParticles); + } + + public void replaceBlocks(Selection selection, BlockState state, boolean spawnParticles) { + modifyBlocks(selection, $ -> state, spawnParticles); + } + + public void modifyBlock(BlockPos pos, UnaryOperator stateFunc, boolean spawnParticles) { + modifyBlocks(scene.getSceneBuildingUtil().select.position(pos), stateFunc, spawnParticles); + } + + public void cycleBlockProperty(BlockPos pos, Property property) { + modifyBlocks(scene.getSceneBuildingUtil().select.position(pos), + s -> s.contains(property) ? s.cycle(property) : s, false); + } + + public void modifyBlocks(Selection selection, UnaryOperator stateFunc, boolean spawnParticles) { + addInstruction(new ReplaceBlocksInstruction(selection, stateFunc, false, spawnParticles)); + } + + public void toggleRedstonePower(Selection selection) { + modifyBlocks(selection, s -> { + if (s.contains(BlockStateProperties.POWER_0_15)) + s = s.with(BlockStateProperties.POWER_0_15, s.get(BlockStateProperties.POWER_0_15) == 0 ? 15 : 0); + if (s.contains(BlockStateProperties.POWERED)) + s = s.cycle(BlockStateProperties.POWERED); + if (s.contains(RedstoneTorchBlock.LIT)) + s = s.cycle(RedstoneTorchBlock.LIT); + return s; + }, false); + } + + public void modifyEntities(Class entityClass, Consumer entityCallBack) { + addInstruction(scene -> scene.forEachWorldEntity(entityClass, entityCallBack)); + } + + public void modifyEntitiesInside(Class entityClass, Selection area, + Consumer entityCallBack) { + addInstruction(scene -> scene.forEachWorldEntity(entityClass, e -> { + if (area.test(e.getBlockPos())) + entityCallBack.accept(e); + })); + } + + public void modifyEntity(ElementLink link, Consumer entityCallBack) { + addInstruction(scene -> { + EntityElement resolve = scene.resolve(link); + if (resolve != null) + resolve.ifPresent(entityCallBack::accept); + }); + } + + public ElementLink createEntity(Function factory) { + ElementLink link = new ElementLink<>(EntityElement.class, UUID.randomUUID()); + addInstruction(scene -> { + PonderWorld world = scene.getWorld(); + Entity entity = factory.apply(world); + EntityElement handle = new EntityElement(entity); + scene.addElement(handle); + scene.linkElement(handle, link); + world.addEntity(entity); + }); + return link; + } + + public ElementLink createItemEntity(Vector3d location, Vector3d motion, ItemStack stack) { + return createEntity(world -> { + ItemEntity itemEntity = new ItemEntity(world, location.x, location.y, location.z, stack); + itemEntity.setMotion(motion); + return itemEntity; + }); + } + + public ElementLink createGlueEntity(BlockPos pos, Direction face) { + effects.superGlue(pos, face, false); + return createEntity(world -> new SuperGlueEntity(world, pos, face.getOpposite())); + } + + public void createItemOnBeltLike(BlockPos location, Direction insertionSide, ItemStack stack) { + addInstruction(scene -> { + PonderWorld world = scene.getWorld(); + TileEntity tileEntity = world.getTileEntity(location); + if (!(tileEntity instanceof SmartTileEntity)) + return; + SmartTileEntity beltTileEntity = (SmartTileEntity) tileEntity; + DirectBeltInputBehaviour behaviour = beltTileEntity.getBehaviour(DirectBeltInputBehaviour.TYPE); + if (behaviour == null) + return; + behaviour.handleInsertion(stack, insertionSide.getOpposite(), false); + }); + flapFunnel(location.up(), true); + } + + public ElementLink createItemOnBelt(BlockPos beltLocation, Direction insertionSide, + ItemStack stack) { + ElementLink link = new ElementLink<>(BeltItemElement.class); + addInstruction(scene -> { + PonderWorld world = scene.getWorld(); + TileEntity tileEntity = world.getTileEntity(beltLocation); + if (!(tileEntity instanceof BeltTileEntity)) + return; + + BeltTileEntity beltTileEntity = (BeltTileEntity) tileEntity; + DirectBeltInputBehaviour behaviour = beltTileEntity.getBehaviour(DirectBeltInputBehaviour.TYPE); + behaviour.handleInsertion(stack, insertionSide.getOpposite(), false); + + BeltTileEntity controllerTE = beltTileEntity.getControllerTE(); + if (controllerTE != null) + controllerTE.tick(); + + TransportedItemStackHandlerBehaviour transporter = + beltTileEntity.getBehaviour(TransportedItemStackHandlerBehaviour.TYPE); + transporter.handleProcessingOnAllItems(tis -> { + BeltItemElement tracker = new BeltItemElement(tis); + scene.addElement(tracker); + scene.linkElement(tracker, link); + return TransportedResult.doNothing(); + }); + }); + flapFunnel(beltLocation.up(), true); + return link; + } + + public void removeItemsFromBelt(BlockPos beltLocation) { + addInstruction(scene -> { + PonderWorld world = scene.getWorld(); + TileEntity tileEntity = world.getTileEntity(beltLocation); + if (!(tileEntity instanceof BeltTileEntity)) + return; + BeltTileEntity beltTileEntity = (BeltTileEntity) tileEntity; + TransportedItemStackHandlerBehaviour transporter = + beltTileEntity.getBehaviour(TransportedItemStackHandlerBehaviour.TYPE); + transporter.handleCenteredProcessingOnAllItems(.52f, tis -> TransportedResult.removeItem()); + }); + } + + public void stallBeltItem(ElementLink link, boolean stalled) { + addInstruction(scene -> { + BeltItemElement resolve = scene.resolve(link); + if (resolve != null) + resolve.ifPresent(tis -> tis.locked = stalled); + }); + } + + public void changeBeltItemTo(ElementLink link, ItemStack newStack) { + addInstruction(scene -> { + BeltItemElement resolve = scene.resolve(link); + if (resolve != null) + resolve.ifPresent(tis -> tis.stack = newStack); + }); + } + + public void setKineticSpeed(Selection selection, float speed) { + modifyKineticSpeed(selection, f -> speed); + } + + public void multiplyKineticSpeed(Selection selection, float modifier) { + modifyKineticSpeed(selection, f -> f * modifier); + } + + public void modifyKineticSpeed(Selection selection, UnaryOperator speedFunc) { + modifyTileNBT(selection, SpeedGaugeTileEntity.class, nbt -> { + float newSpeed = speedFunc.apply(nbt.getFloat("Speed")); + nbt.putFloat("Value", SpeedGaugeTileEntity.getDialTarget(newSpeed)); + }); + modifyTileNBT(selection, KineticTileEntity.class, nbt -> { + nbt.putFloat("Speed", speedFunc.apply(nbt.getFloat("Speed"))); + }); + } + + public void setFilterData(Selection selection, Class teType, ItemStack filter) { + modifyTileNBT(selection, teType, nbt -> { + nbt.put("Filter", filter.serializeNBT()); + }); + } + + public void modifyTileNBT(Selection selection, Class teType, + Consumer consumer) { + modifyTileNBT(selection, teType, consumer, false); + } + + public void modifyTileEntity(BlockPos position, Class teType, Consumer consumer) { + addInstruction(scene -> { + TileEntity tileEntity = scene.world.getTileEntity(position); + if (teType.isInstance(tileEntity)) + consumer.accept(teType.cast(tileEntity)); + }); + } + + public void modifyTileNBT(Selection selection, Class teType, + Consumer consumer, boolean reDrawBlocks) { + addInstruction(new TileEntityDataInstruction(selection, teType, nbt -> { + consumer.accept(nbt); + return nbt; + }, reDrawBlocks)); + } + + public void flapFunnel(BlockPos position, boolean outward) { + modifyTileEntity(position, FunnelTileEntity.class, funnel -> funnel.flap(!outward)); + } + + } + + public class DebugInstructions { + + public void debugSchematic() { + addInstruction( + scene -> scene.addElement(new WorldSectionElement(scene.getSceneBuildingUtil().select.everywhere()))); + } + + public void addInstructionInstance(PonderInstruction instruction) { + addInstruction(instruction); + } + + public void enqueueCallback(Consumer callback) { + addInstruction(callback); + } + + } + + private void addInstruction(PonderInstruction instruction) { + scene.schedule.add(instruction); + } + + private void addInstruction(Consumer callback) { + scene.schedule.add(PonderInstruction.simple(callback)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/foundation/ponder/SceneBuildingUtil.java b/src/main/java/com/simibubi/create/foundation/ponder/SceneBuildingUtil.java new file mode 100644 index 000000000..e69c5967c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/SceneBuildingUtil.java @@ -0,0 +1,118 @@ +package com.simibubi.create.foundation.ponder; + +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector3i; + +/** + * Helpful shortcuts for marking boundaries, points or sections inside the scene + */ +public class SceneBuildingUtil { + + public final SelectionUtil select; + public final VectorUtil vector; + public final PositionUtil grid; + + private final MutableBoundingBox sceneBounds; + + SceneBuildingUtil(MutableBoundingBox sceneBounds) { + this.sceneBounds = sceneBounds; + this.select = new SelectionUtil(); + this.vector = new VectorUtil(); + this.grid = new PositionUtil(); + } + + public class PositionUtil { + + public BlockPos at(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + public BlockPos zero() { + return at(0, 0, 0); + } + + } + + public class VectorUtil { + + public Vector3d centerOf(int x, int y, int z) { + return centerOf(grid.at(x, y, z)); + } + + public Vector3d centerOf(BlockPos pos) { + return VecHelper.getCenterOf(pos); + } + + public Vector3d topOf(int x, int y, int z) { + return blockSurface(grid.at(x, y, z), Direction.UP); + } + + public Vector3d topOf(BlockPos pos) { + return blockSurface(pos, Direction.UP); + } + + public Vector3d blockSurface(BlockPos pos, Direction face) { + return blockSurface(pos, face, 0); + } + + public Vector3d blockSurface(BlockPos pos, Direction face, float margin) { + return centerOf(pos).add(Vector3d.of(face.getDirectionVec()).scale(.5f + margin)); + } + + public Vector3d of(double x, double y, double z) { + return new Vector3d(x, y, z); + } + + } + + public class SelectionUtil { + + public Selection everywhere() { + return Selection.of(sceneBounds); + } + + public Selection position(int x, int y, int z) { + return position(grid.at(x, y, z)); + } + + public Selection position(BlockPos pos) { + return cuboid(pos, BlockPos.ZERO); + } + + public Selection fromTo(int x, int y, int z, int x2, int y2, int z2) { + return fromTo(new BlockPos(x, y, z), new BlockPos(x2, y2, z2)); + } + + public Selection fromTo(BlockPos pos1, BlockPos pos2) { + return cuboid(pos1, pos2.subtract(pos1)); + } + + public Selection column(int x, int z) { + return cuboid(new BlockPos(x, 1, z), new Vector3i(0, sceneBounds.getYSize(), 0)); + } + + public Selection layer(int y) { + return layers(y, 1); + } + + public Selection layersFrom(int y) { + return layers(y, sceneBounds.getYSize() - y); + } + + public Selection layers(int y, int height) { + return cuboid(new BlockPos(0, y, 0), new Vector3i(sceneBounds.getXSize() - 1, + Math.min(sceneBounds.getYSize() - y, height) - 1, sceneBounds.getZSize() - 1)); + } + + public Selection cuboid(BlockPos origin, Vector3i size) { + return Selection.of(new MutableBoundingBox(origin, origin.add(size))); + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/foundation/ponder/Selection.java b/src/main/java/com/simibubi/create/foundation/ponder/Selection.java new file mode 100644 index 000000000..2d2cd47c7 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/Selection.java @@ -0,0 +1,154 @@ +package com.simibubi.create.foundation.ponder; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams; +import com.simibubi.create.foundation.utility.outliner.Outliner; + +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.math.vector.Vector3d; + +public abstract class Selection implements Predicate { + + public static Selection of(MutableBoundingBox bb) { + return new Simple(bb); + } + + public abstract Selection add(Selection other); + + public abstract Selection substract(Selection other); + + public abstract Selection copy(); + + public abstract Vector3d getCenter(); + + public abstract void forEach(Consumer callback); + + public abstract OutlineParams makeOutline(Outliner outliner, Object slot); + + public OutlineParams makeOutline(Outliner outliner) { + return makeOutline(outliner, this); + } + + private static class Compound extends Selection { + + Set posSet; + Vector3d center; + + public Compound(Simple initial) { + posSet = new HashSet<>(); + add(initial); + } + + private Compound(Set template) { + posSet = new HashSet<>(template); + } + + @Override + public boolean test(BlockPos t) { + return posSet.contains(t); + } + + @Override + public Selection add(Selection other) { + other.forEach(p -> posSet.add(p.toImmutable())); + center = null; + return this; + } + + @Override + public Selection substract(Selection other) { + other.forEach(p -> posSet.remove(p.toImmutable())); + center = null; + return this; + } + + @Override + public void forEach(Consumer callback) { + posSet.forEach(callback); + } + + @Override + public OutlineParams makeOutline(Outliner outliner, Object slot) { + return outliner.showCluster(slot, posSet); + } + + @Override + public Vector3d getCenter() { + return center == null ? center = evalCenter() : center; + } + + private Vector3d evalCenter() { + Vector3d center = Vector3d.ZERO; + if (posSet.isEmpty()) + return center; + for (BlockPos blockPos : posSet) + center = center.add(Vector3d.of(blockPos)); + center = center.scale(1f / posSet.size()); + return center.add(new Vector3d(.5, .5, .5)); + } + + @Override + public Selection copy() { + return new Compound(posSet); + } + + } + + private static class Simple extends Selection { + + private MutableBoundingBox bb; + private AxisAlignedBB aabb; + + public Simple(MutableBoundingBox bb) { + this.bb = bb; + this.aabb = getAABB(); + } + + @Override + public boolean test(BlockPos t) { + return bb.isVecInside(t); + } + + @Override + public Selection add(Selection other) { + return new Compound(this).add(other); + } + + @Override + public Selection substract(Selection other) { + return new Compound(this).substract(other); + } + + @Override + public void forEach(Consumer callback) { + BlockPos.stream(bb).forEach(callback); + } + + @Override + public Vector3d getCenter() { + return aabb.getCenter(); + } + + @Override + public OutlineParams makeOutline(Outliner outliner, Object slot) { + return outliner.showAABB(slot, aabb); + } + + private AxisAlignedBB getAABB() { + return new AxisAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX + 1, bb.maxY + 1, bb.maxZ + 1); + } + + @Override + public Selection copy() { + return new Simple(new MutableBoundingBox(bb)); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/BearingScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/BearingScenes.java new file mode 100644 index 000000000..8cd5baa56 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/BearingScenes.java @@ -0,0 +1,566 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.components.actors.HarvesterTileEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.SailBlock; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class BearingScenes { + + public static void windmillsAsSource(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("windmill_source", "Generating Rotational Force using Windmill Bearings"); + scene.configureBasePlate(1, 1, 5); + scene.setSceneOffsetY(-1); + + scene.world.showSection(util.select.fromTo(1, 0, 1, 5, 0, 5), Direction.UP); + scene.world.setBlock(util.grid.at(2, -1, 0), AllBlocks.SAIL.getDefaultState() + .with(SailBlock.FACING, Direction.NORTH), false); + scene.idle(5); + Selection kinetics = util.select.fromTo(3, 1, 1, 4, 1, 4); + Selection largeCog = util.select.position(3, 2, 2); + BlockPos windmill = util.grid.at(3, 2, 1); + scene.world.showSection(kinetics.add(largeCog), Direction.DOWN); + scene.idle(10); + + scene.world.showSection(util.select.position(windmill), Direction.DOWN); + scene.idle(10); + + BlockPos anchorPos = windmill.north(); + scene.overlay.showSelectionWithText(util.select.position(anchorPos), 60) + .colored(PonderPalette.GREEN) + .pointAt(util.vector.blockSurface(windmill, Direction.WEST)) + .placeNearTarget() + .text("Windmill Bearings attach to the block in front of them"); + scene.idle(50); + + ElementLink structure = + scene.world.showIndependentSection(util.select.position(anchorPos), Direction.SOUTH); + scene.idle(10); + for (Direction d : Iterate.directions) + if (d.getAxis() != Axis.Z) + scene.world.showSectionAndMerge(util.select.fromTo(anchorPos.offset(d, 1), anchorPos.offset(d, 2)), + d.getOpposite(), structure); + scene.idle(10); + + scene.world.showSectionAndMerge(util.select.fromTo(anchorPos.up() + .east(), + anchorPos.up(3) + .east()), + Direction.WEST, structure); + scene.world.showSectionAndMerge(util.select.fromTo(anchorPos.down() + .west(), + anchorPos.down(3) + .west()), + Direction.EAST, structure); + scene.world.showSectionAndMerge(util.select.fromTo(anchorPos.east() + .down(), + anchorPos.east(3) + .down()), + Direction.UP, structure); + scene.world.showSectionAndMerge(util.select.fromTo(anchorPos.west() + .up(), + anchorPos.west(3) + .up()), + Direction.DOWN, structure); + + scene.idle(5); + for (Direction d : Iterate.directions) + if (d.getAxis() != Axis.Z) + scene.effects.superGlue(anchorPos.offset(d, 1), d.getOpposite(), false); + scene.idle(10); + + scene.overlay.showText(60) + .pointAt(util.vector.blockSurface(anchorPos, Direction.NORTH)) + .placeNearTarget() + .text("If enough Sail-like blocks are attached to the block, it can act as a Windmill"); + scene.idle(70); + + scene.rotateCameraY(-90); + scene.idle(20); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(windmill), Pointing.DOWN).rightClick(), 60); + scene.idle(7); + scene.world.rotateBearing(windmill, 360, 200); + scene.world.rotateSection(structure, 0, 0, 360, 200); + scene.world.setKineticSpeed(largeCog, 4); + scene.world.setKineticSpeed(kinetics, -8); + scene.effects.rotationDirectionIndicator(windmill.south()); + BlockPos gaugePos = util.grid.at(4, 1, 4); + scene.effects.indicateSuccess(gaugePos); + scene.idle(10); + + scene.overlay.showText(60) + .pointAt(util.vector.topOf(windmill)) + .placeNearTarget() + .text("Activated with Right-Click, the Windmill Bearing will start providing Rotational Force"); + scene.idle(70); + + scene.overlay.showText(60) + .pointAt(util.vector.blockSurface(gaugePos, Direction.WEST)) + .colored(PonderPalette.SLOW) + .placeNearTarget() + .text("The Amount of Sail Blocks determine its Rotation Speed"); + scene.idle(90); + + Vector3d surface = util.vector.blockSurface(windmill, Direction.WEST); + scene.overlay.showControls(new InputWindowElement(surface, Pointing.DOWN).scroll() + .withWrench(), 60); + scene.overlay.showCenteredScrollInput(windmill, Direction.WEST, 50); + scene.overlay.showText(60) + .pointAt(surface) + .placeNearTarget() + .text("Use a Wrench to configure its rotation direction"); + scene.idle(36); + + scene.world.rotateBearing(windmill, -90 - 45, 75); + scene.world.rotateSection(structure, 0, 0, -90 - 45, 75); + scene.world.modifyKineticSpeed(largeCog, f -> -f); + scene.world.modifyKineticSpeed(kinetics, f -> -f); + scene.effects.rotationDirectionIndicator(windmill.south()); + scene.idle(69); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(windmill), Pointing.DOWN).rightClick(), 60); + scene.idle(7); + scene.world.rotateBearing(windmill, -45, 0); + scene.world.rotateSection(structure, 0, 0, -45, 0); + scene.world.setKineticSpeed(largeCog, 0); + scene.world.setKineticSpeed(kinetics, 0); + scene.idle(10); + scene.overlay.showText(60) + .pointAt(util.vector.topOf(windmill)) + .placeNearTarget() + .text("Right-click the Bearing anytime to stop and edit the Structure again"); + + } + + public static void windmillsAnyStructure(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("windmill_structure", "Windmill Contraptions"); + scene.configureBasePlate(1, 1, 5); + scene.setSceneOffsetY(-1); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + BlockPos bearingPos = util.grid.at(3, 1, 3); + scene.world.showSection(util.select.position(bearingPos), Direction.DOWN); + scene.idle(10); + ElementLink contraption = + scene.world.showIndependentSection(util.select.position(bearingPos.up()), Direction.DOWN); + scene.idle(10); + scene.world.showSectionAndMerge(util.select.fromTo(3, 2, 2, 3, 3, 1), Direction.SOUTH, contraption); + scene.world.showSectionAndMerge(util.select.fromTo(3, 2, 4, 3, 3, 5), Direction.NORTH, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(3, 1, 5), Direction.NORTH, contraption); + scene.world.showSectionAndMerge(util.select.position(3, 4, 2), Direction.DOWN, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(2, 1, 5), Direction.EAST, contraption); + scene.world.showSectionAndMerge(util.select.position(3, 3, 3), Direction.DOWN, contraption); + scene.idle(5); + scene.effects.superGlue(bearingPos.up(), Direction.SOUTH, true); + scene.effects.superGlue(bearingPos.up(), Direction.NORTH, true); + scene.idle(5); + scene.effects.superGlue(util.grid.at(3, 1, 5), Direction.UP, true); + scene.idle(5); + scene.effects.superGlue(util.grid.at(3, 3, 3), Direction.DOWN, true); + scene.idle(10); + + scene.overlay.showOutline(PonderPalette.BLUE, bearingPos, util.select.fromTo(3, 2, 1, 3, 3, 2), 80); + scene.overlay.showSelectionWithText(util.select.fromTo(3, 2, 4, 3, 3, 5), 80) + .colored(PonderPalette.BLUE) + .text("Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks."); + + scene.idle(90); + scene.overlay.showControls( + new InputWindowElement(util.vector.blockSurface(bearingPos, Direction.WEST), Pointing.LEFT).rightClick(), + 40); + scene.idle(7); + scene.markAsFinished(); + scene.world.rotateBearing(bearingPos, -720, 400); + scene.world.rotateSection(contraption, 0, -720, 0, 400); + scene.world.modifyTileEntity(util.grid.at(2, 1, 5), HarvesterTileEntity.class, + hte -> hte.setAnimatedSpeed(-150)); + scene.idle(400); + scene.world.modifyTileEntity(util.grid.at(2, 1, 5), HarvesterTileEntity.class, hte -> hte.setAnimatedSpeed(0)); + } + + public static void mechanicalBearing(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_bearing", "Movings Structures using the Mechanical Bearing"); + scene.configureBasePlate(1, 1, 5); + scene.setSceneOffsetY(-1); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.layer(2), Direction.DOWN); + scene.idle(10); + + Selection cog1 = util.select.position(6, 0, 4); + Selection cog2 = util.select.position(5, 1, 4); + Selection cog3 = util.select.position(4, 1, 3); + Selection cog4 = util.select.position(3, 1, 3); + Selection all = cog1.copy() + .add(cog2) + .add(cog3) + .add(cog4); + + BlockPos bearingPos = util.grid.at(3, 2, 3); + scene.overlay.showSelectionWithText(util.select.position(bearingPos.up()), 60) + .colored(PonderPalette.GREEN) + .pointAt(util.vector.blockSurface(bearingPos, Direction.WEST)) + .placeNearTarget() + .text("Mechanical Bearings attach to the block in front of them"); + scene.idle(50); + + ElementLink plank = scene.world.showIndependentSection(util.select.position(bearingPos.up() + .east() + .north()), Direction.DOWN); + scene.world.moveSection(plank, util.vector.of(-1, 0, 1), 0); + scene.idle(20); + + scene.world.setKineticSpeed(cog1, -8); + scene.world.setKineticSpeed(cog2, 8); + scene.world.setKineticSpeed(cog3, -16); + scene.world.setKineticSpeed(cog4, 16); + scene.effects.rotationSpeedIndicator(bearingPos.down()); + scene.world.rotateBearing(bearingPos, 360, 37 * 2); + scene.world.rotateSection(plank, 0, 360, 0, 37 * 2); + + scene.overlay.showText(80) + .pointAt(util.vector.topOf(bearingPos.up())) + .placeNearTarget() + .text("Upon receiving Rotational Force, it will assemble it into a Rotating Contraption"); + scene.idle(37 * 2); + scene.world.setKineticSpeed(all, 0); + scene.idle(20); + + scene.world.hideIndependentSection(plank, Direction.UP); + scene.idle(15); + Selection plank2 = util.select.position(4, 3, 2); + ElementLink contraption = scene.world.showIndependentSection(util.select.layersFrom(3) + .substract(plank2), Direction.DOWN); + scene.idle(10); + scene.world.showSectionAndMerge(plank2, Direction.SOUTH, contraption); + scene.idle(15); + scene.effects.superGlue(util.grid.at(4, 3, 2), Direction.SOUTH, true); + scene.idle(5); + + scene.world.configureCenterOfRotation(contraption, util.vector.topOf(bearingPos)); + scene.world.setKineticSpeed(cog1, -8); + scene.world.setKineticSpeed(cog2, 8); + scene.world.setKineticSpeed(cog3, -16); + scene.world.setKineticSpeed(cog4, 16); + scene.effects.rotationSpeedIndicator(bearingPos.down()); + scene.world.rotateBearing(bearingPos, 360 * 2, 37 * 4); + scene.world.rotateSection(contraption, 0, 360 * 2, 0, 37 * 4); + + scene.overlay.showText(120) + .pointAt(util.vector.topOf(bearingPos.up())) + .placeNearTarget() + .sharedText("movement_anchors"); + + scene.idle(37 * 4); + scene.world.setKineticSpeed(all, 0); + } + + public static void bearingModes(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("bearing_modes", "Movement Modes of the Mechanical Bearing"); + scene.configureBasePlate(1, 1, 6); + scene.setSceneOffsetY(-1); + + Selection sideCog = util.select.position(util.grid.at(7, 0, 3)); + Selection cogColumn = util.select.fromTo(6, 1, 3, 6, 4, 3); + Selection cogAndClutch = util.select.fromTo(5, 3, 1, 5, 4, 2); + BlockPos leverPos = util.grid.at(5, 3, 1); + + scene.world.setKineticSpeed(sideCog, 4); + scene.world.setKineticSpeed(cogColumn, -4); + scene.world.setKineticSpeed(cogAndClutch, 8); + scene.world.toggleRedstonePower(cogAndClutch); + + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(cogColumn, Direction.DOWN); + scene.idle(5); + scene.world.showSection(cogAndClutch, Direction.DOWN); + scene.idle(10); + + BlockPos bearingPos = util.grid.at(5, 2, 2); + scene.world.showSection(util.select.position(bearingPos), Direction.UP); + scene.idle(10); + + ElementLink contraption = + scene.world.showIndependentSection(util.select.fromTo(5, 1, 2, 2, 1, 2), Direction.EAST); + scene.world.configureCenterOfRotation(contraption, util.vector.centerOf(bearingPos)); + scene.idle(20); + + scene.world.toggleRedstonePower(cogAndClutch); + scene.effects.indicateRedstone(leverPos); + scene.world.rotateSection(contraption, 0, 55, 0, 23); + scene.world.rotateBearing(bearingPos, 55, 23); + scene.idle(24); + + scene.world.toggleRedstonePower(cogAndClutch); + scene.effects.indicateRedstone(leverPos); + scene.world.rotateSection(contraption, 0, 35, 0, 0); + scene.world.rotateBearing(bearingPos, 35, 0); + + Vector3d target = util.vector.topOf(bearingPos.down()); + scene.overlay.showLine(PonderPalette.RED, target.add(-2.5, 0, 3.5), target, 50); + scene.overlay.showLine(PonderPalette.GREEN, target.add(0, 0, 4.5), target, 50); + + scene.idle(50); + + scene.overlay.showText(100) + .pointAt(util.vector.blockSurface(bearingPos, Direction.WEST)) + .placeNearTarget() + .colored(PonderPalette.RED) + .text("When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle"); + scene.idle(110); + + scene.overlay.showCenteredScrollInput(bearingPos, Direction.NORTH, 60); + scene.overlay.showControls( + new InputWindowElement(util.vector.blockSurface(bearingPos, Direction.NORTH), Pointing.DOWN).scroll() + .withWrench(), + 60); + scene.idle(10); + scene.overlay.showText(60) + .pointAt(util.vector.blockSurface(bearingPos, Direction.WEST)) + .placeNearTarget() + .sharedText("behaviour_modify_wrench"); + scene.idle(70); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.toggleRedstonePower(cogAndClutch); + scene.effects.indicateRedstone(leverPos); + scene.world.rotateSection(contraption, 0, -55, 0, 23); + scene.world.rotateBearing(bearingPos, -55, 23); + scene.idle(24); + + scene.world.toggleRedstonePower(cogAndClutch); + scene.effects.indicateRedstone(leverPos); + scene.idle(40); + + scene.overlay.showText(120) + .colored(PonderPalette.GREEN) + .pointAt(util.vector.blockSurface(util.grid.at(3, 1, 3), Direction.UP)) + .text("It can be configured never to revert to solid blocks, or only near the angle it started at"); + + } + + public static void stabilizedBearings(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("stabilized_bearings", "Stabilized Contraptions"); + scene.configureBasePlate(1, 1, 5); + scene.setSceneOffsetY(-1); + + Selection beltAndBearing = util.select.fromTo(3, 3, 4, 3, 1, 6); + Selection largeCog = util.select.position(2, 0, 6); + BlockPos parentBearingPos = util.grid.at(3, 3, 4); + BlockPos bearingPos = util.grid.at(3, 4, 2); + + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(beltAndBearing, Direction.DOWN); + scene.idle(10); + + ElementLink contraption = + scene.world.showIndependentSection(util.select.fromTo(3, 3, 3, 3, 4, 3), Direction.SOUTH); + scene.world.configureCenterOfRotation(contraption, util.vector.centerOf(parentBearingPos)); + scene.idle(20); + scene.world.glueBlockOnto(bearingPos, Direction.SOUTH, contraption); + + scene.idle(15); + + scene.overlay.showSelectionWithText(util.select.position(bearingPos), 60) + .text("Whenever Mechanical Bearings are themselves part of a moving Structure..") + .placeNearTarget(); + scene.idle(70); + + scene.world.setKineticSpeed(largeCog, -8); + scene.world.setKineticSpeed(beltAndBearing, 16); + scene.world.rotateBearing(parentBearingPos, 360, 74); + scene.world.rotateSection(contraption, 0, 0, 360, 74); + scene.world.rotateBearing(bearingPos, -360, 74); + scene.idle(74); + + scene.world.setKineticSpeed(largeCog, 0); + scene.world.setKineticSpeed(beltAndBearing, 0); + scene.overlay.showText(60) + .text("..they will attempt to keep themselves upright") + .pointAt(util.vector.blockSurface(bearingPos, Direction.NORTH)) + .placeNearTarget(); + scene.idle(70); + + scene.overlay.showSelectionWithText(util.select.position(bearingPos.north()), 60) + .colored(PonderPalette.GREEN) + .text("Once again, the bearing will attach to the block in front of it") + .placeNearTarget(); + scene.idle(70); + + ElementLink subContraption = + scene.world.showIndependentSection(util.select.fromTo(4, 4, 1, 2, 4, 1), Direction.SOUTH); + scene.world.configureCenterOfRotation(subContraption, util.vector.centerOf(parentBearingPos)); + scene.world.configureStabilization(subContraption, util.vector.centerOf(bearingPos)); + scene.idle(20); + + scene.overlay.showText(80) + .text("As a result, the entire sub-Contraption will stay upright"); + + scene.world.setKineticSpeed(largeCog, -8); + scene.world.setKineticSpeed(beltAndBearing, 16); + scene.world.rotateBearing(parentBearingPos, 360 * 2, 74 * 2); + scene.world.rotateSection(contraption, 0, 0, 360 * 2, 74 * 2); + scene.world.rotateBearing(bearingPos, -360 * 2, 74 * 2); + scene.world.rotateSection(subContraption, 0, 0, 360 * 2, 74 * 2); + + scene.markAsFinished(); + scene.idle(74 * 2); + scene.world.setKineticSpeed(largeCog, 0); + scene.world.setKineticSpeed(beltAndBearing, 0); + } + + public static void clockwork(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("clockwork_bearing", "Animating Structures using Clockwork Bearings"); + scene.configureBasePlate(1, 1, 5); + scene.setSceneOffsetY(-1); + + Selection kinetics = util.select.fromTo(3, 3, 4, 3, 1, 6); + Selection largeCog = util.select.position(2, 0, 6); + BlockPos bearingPos = util.grid.at(3, 3, 3); + + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(kinetics, Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.position(bearingPos), Direction.DOWN); + scene.idle(10); + + scene.overlay.showSelectionWithText(util.select.position(bearingPos.north()), 60) + .colored(PonderPalette.GREEN) + .pointAt(util.vector.blockSurface(bearingPos, Direction.WEST)) + .placeNearTarget() + .text("Clockwork Bearings attach to blocks in front of them"); + scene.idle(50); + + ElementLink plank = + scene.world.showIndependentSection(util.select.position(2, 3, 2), Direction.SOUTH); + scene.world.moveSection(plank, util.vector.of(1, 0, 0), 0); + scene.idle(20); + + scene.world.rotateSection(plank, 0, 0, 60, 25); + scene.world.rotateBearing(bearingPos, 60, 25); + scene.world.setKineticSpeed(kinetics, 8); + scene.world.setKineticSpeed(largeCog, -4); + + scene.idle(25); + scene.overlay.showText(80) + .pointAt(util.vector.blockSurface(bearingPos.north(), Direction.NORTH)) + .placeNearTarget() + .text("Upon receiving Rotational Force, the structure will be rotated according to the hour of the day"); + scene.idle(90); + + scene.overlay.showText(30) + .pointAt(util.vector.blockSurface(bearingPos.north(), Direction.NORTH)) + .placeNearTarget() + .text("3:00"); + scene.world.rotateSection(plank, 0, 0, 30, 12); + scene.world.rotateBearing(bearingPos, 30, 12); + scene.idle(42); + scene.overlay.showText(30) + .pointAt(util.vector.blockSurface(bearingPos.north(), Direction.NORTH)) + .placeNearTarget() + .text("4:00"); + scene.world.rotateSection(plank, 0, 0, 30, 12); + scene.world.rotateBearing(bearingPos, 30, 12); + scene.idle(42); + + InputWindowElement clickTheBearing = new InputWindowElement(util.vector.topOf(bearingPos), Pointing.DOWN); + InputWindowElement clickTheBearingSide = + new InputWindowElement(util.vector.blockSurface(bearingPos, Direction.WEST), Pointing.LEFT); + + scene.overlay.showControls(clickTheBearing.rightClick(), 60); + scene.idle(7); + scene.world.rotateSection(plank, 0, 0, -120, 0); + scene.world.rotateBearing(bearingPos, -120, 0); + scene.overlay.showText(60) + .pointAt(util.vector.blockSurface(bearingPos, Direction.WEST)) + .placeNearTarget() + .text("Right-Click the bearing to start or stop animating the structure"); + scene.idle(70); + + scene.world.hideIndependentSection(plank, Direction.NORTH); + scene.idle(15); + + ElementLink hourHand = + scene.world.showIndependentSection(util.select.fromTo(3, 3, 1, 3, 5, 2), Direction.SOUTH); + scene.world.configureCenterOfRotation(hourHand, util.vector.centerOf(bearingPos)); + scene.idle(15); + scene.overlay.showSelectionWithText(util.select.fromTo(3, 3, 1, 3, 4, 2), 80) + .placeNearTarget() + .sharedText("movement_anchors"); + scene.idle(90); + + scene.overlay.showControls(clickTheBearingSide.rightClick(), 20); + scene.idle(7); + scene.world.rotateSection(hourHand, 0, 0, 120, 50); + scene.world.rotateBearing(bearingPos, 120, 50); + scene.idle(60); + + scene.overlay.showSelectionWithText(util.select.position(bearingPos.north(3)), 80) + .placeNearTarget() + .colored(PonderPalette.BLUE) + .text("In front of the Hour Hand, a second structure can be added"); + scene.idle(90); + scene.overlay.showControls(clickTheBearingSide.rightClick(), 20); + scene.idle(7); + scene.world.rotateSection(hourHand, 0, 0, -120, 0); + scene.world.rotateBearing(bearingPos, -120, 0); + scene.idle(10); + + ElementLink minuteHand = + scene.world.showIndependentSection(util.select.fromTo(3, 3, 0, 3, 6, 0), Direction.SOUTH); + scene.world.configureCenterOfRotation(minuteHand, util.vector.centerOf(bearingPos)); + scene.idle(30); + + scene.overlay.showOutline(PonderPalette.BLUE, minuteHand, util.select.fromTo(3, 3, 0, 3, 6, 0), 85); + scene.overlay.showSelectionWithText(util.select.fromTo(3, 3, 1, 3, 4, 2), 80) + .placeNearTarget() + .colored(PonderPalette.GREEN) + .text("Ensure the two Structures are not attached to each other through super glue or similar"); + scene.idle(90); + + scene.overlay.showControls(clickTheBearingSide.rightClick(), 20); + scene.idle(7); + + scene.world.rotateSection(hourHand, 0, 0, 120, 50); + scene.world.rotateSection(minuteHand, 0, 0, 180, 75); + scene.world.rotateBearing(bearingPos, 120, 50); + scene.idle(90); + scene.world.rotateSection(minuteHand, 0, 0, 6, 3); + + scene.overlay.showText(80) + .placeNearTarget() + .pointAt(util.vector.blockSurface(bearingPos.north(3), Direction.NORTH)) + .colored(PonderPalette.GREEN) + .text("The Second Structure will now rotate as the Minute Hand"); + scene.markAsFinished(); + + for (int i = 0; i < 40; i++) { + scene.idle(23); + scene.world.rotateSection(minuteHand, 0, 0, 6, 3); + if (i == 29) + scene.world.rotateSection(hourHand, 0, 0, 30, 20); + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/BeltScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/BeltScenes.java new file mode 100644 index 000000000..bc5bea25f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/BeltScenes.java @@ -0,0 +1,464 @@ +package com.simibubi.create.foundation.ponder.content; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; +import com.simibubi.create.content.contraptions.relays.belt.BeltPart; +import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; +import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement.FaceCursorPose; +import com.simibubi.create.foundation.ponder.elements.ParrotElement.FacePointOfInterestPose; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.DyeColor; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class BeltScenes { + + public static void beltConnector(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("belt_connector", "Using Mechanical Belts"); + scene.configureBasePlate(0, 0, 5); + scene.showBasePlate(); + scene.idle(5); + + scene.world.showSection(util.select.fromTo(4, 1, 3, 4, 1, 5), Direction.DOWN); + ElementLink shafts = + scene.world.showIndependentSection(util.select.fromTo(0, 1, 3, 4, 1, 3), Direction.DOWN); + scene.world.moveSection(shafts, util.vector.of(0, 0, -1), 0); + scene.world.setKineticSpeed(util.select.position(0, 1, 3), 0); + scene.idle(20); + + BlockPos backEnd = util.grid.at(4, 1, 2); + BlockPos frontEnd = util.grid.at(0, 1, 2); + ItemStack beltItem = AllItems.BELT_CONNECTOR.asStack(); + Vector3d backEndCenter = util.vector.centerOf(backEnd); + AxisAlignedBB connectBB = new AxisAlignedBB(backEndCenter, backEndCenter); + AxisAlignedBB shaftBB = AllBlocks.SHAFT.getDefaultState() + .with(ShaftBlock.AXIS, Axis.Z) + .getShape(null, null) + .getBoundingBox(); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(backEnd), Pointing.DOWN).rightClick() + .withItem(beltItem), 57); + scene.idle(7); + + scene.overlay.chaseBoundingBoxOutline(PonderPalette.GREEN, backEnd, shaftBB.offset(backEnd), 42); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.BLACK, backEndCenter, connectBB, 50); + scene.idle(20); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(frontEnd), Pointing.DOWN).rightClick() + .withItem(beltItem), 37); + scene.idle(7); + + scene.overlay.chaseBoundingBoxOutline(PonderPalette.GREEN, frontEnd, shaftBB.offset(frontEnd), 17); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.BLACK, backEndCenter, connectBB.expand(-4, 0, 0), 20); + scene.idle(20); + + scene.world.moveSection(shafts, util.vector.of(0, -2, 0), 0); + scene.world.showSection(util.select.fromTo(0, 1, 2, 4, 1, 2), Direction.SOUTH); + scene.idle(20); + + scene.overlay.showText(80) + .text("Right-Clicking two shafts with a belt item will connect them together") + .placeNearTarget() + .pointAt(util.vector.topOf(2, 1, 2)); + scene.idle(90); + + Vector3d falseSelection = util.vector.topOf(backEnd.south(1)); + scene.overlay.showControls(new InputWindowElement(falseSelection, Pointing.DOWN).rightClick() + .withItem(beltItem), 37); + scene.idle(7); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.RED, backEnd, shaftBB.offset(backEnd.south(1)), 50); + + scene.overlay.showText(80) + .colored(PonderPalette.RED) + .text("Accidental selections can be canceled with Right-Click while Sneaking") + .placeNearTarget() + .pointAt(util.vector.centerOf(backEnd.south(1))); + scene.idle(43); + + scene.overlay.showControls(new InputWindowElement(falseSelection, Pointing.DOWN).rightClick() + .withItem(beltItem) + .whileSneaking(), 20); + scene.idle(60); + + BlockPos shaftLocation = frontEnd.east(); + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(shaftLocation), Pointing.DOWN).rightClick() + .withItem(AllBlocks.SHAFT.asStack()), 50); + scene.idle(7); + scene.world.modifyBlock(shaftLocation, s -> s.with(BeltBlock.PART, BeltPart.PULLEY), true); + scene.idle(10); + + scene.overlay.showText(43) + .text("Additional Shafts can be added throughout the Belt") + .placeNearTarget() + .pointAt(util.vector.blockSurface(shaftLocation, Direction.NORTH)); + scene.idle(50); + + Selection attachedShafts = util.select.fromTo(0, 1, 1, 1, 1, 1); + scene.world.showSection(attachedShafts, Direction.SOUTH); + scene.world.setKineticSpeed(attachedShafts, 32); + scene.idle(10); + scene.effects.rotationDirectionIndicator(util.grid.at(0, 1, 1)); + scene.effects.rotationDirectionIndicator(util.grid.at(1, 1, 1)); + scene.idle(20); + + scene.overlay.showText(50) + .text("Shafts connected via Belts will rotate with Identical Speed and Direction") + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(0, 1, 1), Direction.NORTH)); + scene.idle(60); + + scene.world.hideSection(attachedShafts, Direction.NORTH); + scene.idle(20); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(shaftLocation), Pointing.DOWN).rightClick() + .withWrench(), 50); + scene.idle(7); + scene.world.modifyBlock(shaftLocation, s -> s.with(BeltBlock.PART, BeltPart.MIDDLE), true); + scene.idle(10); + scene.overlay.showText(50) + .text("Added shafts can be removed using the wrench") + .placeNearTarget() + .pointAt(util.vector.blockSurface(shaftLocation, Direction.NORTH)); + scene.idle(70); + + scene.overlay + .showControls(new InputWindowElement(util.vector.topOf(shaftLocation.east()), Pointing.DOWN).rightClick() + .withItem(new ItemStack(Items.BLUE_DYE)), 50); + scene.idle(7); + scene.world.modifyTileNBT(util.select.fromTo(0, 1, 2, 4, 1, 2), BeltTileEntity.class, + nbt -> NBTHelper.writeEnum(nbt, "Dye", DyeColor.BLUE)); + scene.idle(20); + scene.overlay.showText(80) + .colored(PonderPalette.BLUE) + .text("Mechanical Belts can be dyed for aesthetic purposes") + .placeNearTarget() + .pointAt(util.vector.topOf(shaftLocation.east())); + } + + public static void directions(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("belt_directions", "Valid Orientations for Mechanical Belts"); + scene.configureBasePlate(0, 0, 5); + scene.setSceneOffsetY(-1); + scene.showBasePlate(); + scene.idle(5); + + ElementLink leftShaft = + scene.world.showIndependentSection(util.select.position(4, 1, 0), Direction.DOWN); + ElementLink rightShaft = + scene.world.showIndependentSection(util.select.position(0, 1, 0), Direction.DOWN); + + scene.world.moveSection(leftShaft, util.vector.of(0, 0, 2), 0); + scene.world.moveSection(rightShaft, util.vector.of(0, 0, 2), 0); + scene.idle(1); + scene.world.moveSection(leftShaft, util.vector.of(-1, 0, 0), 10); + scene.world.moveSection(rightShaft, util.vector.of(1, 1, 0), 10); + + scene.idle(20); + + Vector3d from = util.vector.centerOf(3, 1, 2); + Vector3d to = util.vector.centerOf(1, 2, 2); + + scene.overlay.showLine(PonderPalette.RED, from, to, 70); + scene.idle(10); + scene.overlay.showLine(PonderPalette.GREEN, to.add(-1, -1, 0), from, 60); + scene.overlay.showLine(PonderPalette.GREEN, from.add(0, 3, 0), from, 60); + + scene.idle(20); + scene.overlay.showText(60) + .colored(PonderPalette.RED) + .placeNearTarget() + .pointAt(to) + .text("Belts cannot connect in arbitrary directions"); + scene.idle(70); + + from = util.vector.centerOf(4, 1, 2); + to = util.vector.centerOf(0, 1, 2); + + scene.world.moveSection(leftShaft, util.vector.of(1, 0, 0), 10); + scene.world.moveSection(rightShaft, util.vector.of(-1, -1, 0), 10); + scene.idle(10); + scene.overlay.showLine(PonderPalette.GREEN, from, to, 40); + scene.idle(10); + scene.overlay.showText(40) + .colored(PonderPalette.GREEN) + .placeNearTarget() + .pointAt(to) + .text("1. They can connect horizontally"); + + scene.idle(20); + Selection firstBelt = util.select.fromTo(4, 1, 1, 0, 1, 1); + ElementLink belt = scene.world.showIndependentSection(firstBelt, Direction.SOUTH); + scene.world.moveSection(belt, util.vector.of(0, 0, 1), 0); + scene.idle(20); + scene.world.hideIndependentSection(belt, Direction.SOUTH); + scene.idle(15); + + from = util.vector.centerOf(3, 3, 2); + to = util.vector.centerOf(1, 1, 2); + + scene.world.moveSection(leftShaft, util.vector.of(-1, 2, 0), 10); + scene.world.moveSection(rightShaft, util.vector.of(1, 0, 0), 10); + scene.idle(10); + scene.world.rotateSection(leftShaft, 0, 0, 25, 5); + scene.world.rotateSection(rightShaft, 0, 0, 25, 5); + scene.overlay.showLine(PonderPalette.GREEN, from, to, 40); + scene.idle(10); + scene.overlay.showText(40) + .colored(PonderPalette.GREEN) + .placeNearTarget() + .pointAt(to) + .text("2. They can connect diagonally"); + + scene.idle(20); + Selection secondBelt = util.select.fromTo(3, 3, 2, 1, 1, 2); + belt = scene.world.showIndependentSection(secondBelt, Direction.SOUTH); + scene.idle(20); + scene.world.hideIndependentSection(belt, Direction.SOUTH); + scene.idle(15); + + from = util.vector.centerOf(2, 4, 2); + to = util.vector.centerOf(2, 1, 2); + + scene.world.moveSection(leftShaft, util.vector.of(-1, 1, 0), 10); + scene.world.moveSection(rightShaft, util.vector.of(1, 0, 0), 10); + scene.idle(10); + scene.world.rotateSection(rightShaft, 0, 0, -25, 5); + scene.overlay.showLine(PonderPalette.GREEN, from, to, 40); + scene.idle(10); + scene.overlay.showText(40) + .colored(PonderPalette.GREEN) + .placeNearTarget() + .pointAt(to) + .text("3. They can connect vertically"); + + scene.idle(20); + Selection thirdBelt = util.select.fromTo(2, 1, 3, 2, 4, 3); + belt = scene.world.showIndependentSection(thirdBelt, Direction.SOUTH); + scene.world.moveSection(belt, util.vector.of(0, 0, -1), 0); + scene.idle(20); + scene.world.hideIndependentSection(belt, Direction.SOUTH); + scene.idle(15); + + from = util.vector.centerOf(4, 1, 2); + to = util.vector.centerOf(0, 1, 2); + + scene.world.moveSection(leftShaft, util.vector.of(2, -3, 0), 10); + scene.world.moveSection(rightShaft, util.vector.of(-2, 0, 0), 10); + scene.idle(10); + scene.world.rotateSection(rightShaft, 90, 0, -25, 5); + scene.world.rotateSection(leftShaft, 90, 0, -50, 5); + scene.overlay.showLine(PonderPalette.GREEN, from, to, 60); + scene.idle(10); + scene.overlay.showText(60) + .colored(PonderPalette.GREEN) + .placeNearTarget() + .pointAt(to) + .text("4. And they can connect vertical shafts horizontally"); + + scene.idle(20); + Selection fourthBelt = util.select.fromTo(4, 1, 4, 0, 1, 4); + belt = scene.world.showIndependentSection(fourthBelt, Direction.DOWN); + scene.world.moveSection(belt, util.vector.of(0, 1 / 512f, -2), 0); + scene.idle(40); + scene.world.hideIndependentSection(belt, Direction.UP); + scene.idle(15); + scene.world.hideIndependentSection(leftShaft, Direction.UP); + scene.world.hideIndependentSection(rightShaft, Direction.UP); + scene.idle(15); + + scene.world.showSection(firstBelt, Direction.DOWN); + scene.idle(5); + scene.world.showSection(secondBelt, Direction.DOWN); + scene.idle(5); + scene.world.showSection(thirdBelt, Direction.DOWN); + scene.idle(5); + scene.world.showSection(fourthBelt, Direction.DOWN); + scene.idle(10); + + scene.overlay.showText(160) + .text("These are all possible directions.\nBelts can span any Length between 2 and 20 blocks"); + scene.markAsFinished(); + } + + public static void transport(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("belt_transport", "Using Mechanical Belts for Logistics"); + scene.configureBasePlate(0, 0, 5); + scene.setSceneOffsetY(-1); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -.6f * f); + scene.showBasePlate(); + scene.idle(5); + scene.world.showSection(util.select.fromTo(1, 1, 3, 2, 1, 5), Direction.DOWN); + scene.idle(20); + scene.world.showSection(util.select.fromTo(2, 1, 2, 4, 3, 2), Direction.SOUTH); + scene.idle(5); + scene.world.showSection(util.select.fromTo(1, 1, 2, 0, 1, 2), Direction.SOUTH); + scene.idle(10); + scene.special.movePointOfInterest(util.grid.at(2, 2, 0)); + + ItemStack stack = AllBlocks.COPPER_BLOCK.asStack(); + ElementLink item = + scene.world.createItemEntity(util.vector.centerOf(0, 4, 2), util.vector.of(0, 0, 0), stack); + scene.idle(13); + scene.world.modifyEntity(item, Entity::remove); + BlockPos beltEnd = util.grid.at(0, 1, 2); + scene.world.createItemOnBelt(beltEnd, Direction.DOWN, stack); + + scene.idle(20); + + ElementLink parrot = scene.special.createBirb(util.vector.topOf(0, 1, 2) + .add(0, -3 / 16f, 0), FacePointOfInterestPose::new); + scene.special.moveParrot(parrot, util.vector.of(1.78, 0, 0), 40); + scene.special.movePointOfInterest(util.grid.at(1, 1, 3)); + + scene.overlay.showText(60) + .placeNearTarget() + .pointAt(util.vector.topOf(beltEnd)) + .text("Moving belts will transport Items and other Entities"); + + scene.idle(20); + item = scene.world.createItemEntity(util.vector.centerOf(0, 4, 2), util.vector.of(0, 0, 0), stack); + scene.special.movePointOfInterest(util.grid.at(0, 3, 2)); + scene.idle(10); + scene.special.movePointOfInterest(beltEnd); + scene.idle(3); + scene.world.modifyEntity(item, Entity::remove); + scene.world.createItemOnBelt(beltEnd, Direction.DOWN, stack); + scene.idle(8); + + scene.special.movePointOfInterest(util.grid.at(3, 2, 1)); + scene.special.moveParrot(parrot, util.vector.of(2.1, 2.1, 0), 60); + scene.idle(20); + scene.special.movePointOfInterest(util.grid.at(5, 5, 2)); + scene.idle(30); + scene.special.movePointOfInterest(util.grid.at(2, 1, 5)); + scene.idle(10); + scene.special.moveParrot(parrot, util.vector.of(.23, 0, 0), 5); + scene.idle(5); + scene.world.setKineticSpeed(util.select.everywhere(), 0f); + scene.idle(10); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.special.movePointOfInterest(util.grid.at(2, 5, 4)); + + Vector3d topOf = util.vector.topOf(util.grid.at(3, 2, 2)) + .add(-0.1, 0.3, 0); + scene.overlay.showControls(new InputWindowElement(topOf, Pointing.DOWN).rightClick(), 60); + scene.idle(10); + scene.overlay.showText(60) + .placeNearTarget() + .pointAt(topOf.subtract(0, 0.1, 0)) + .text("Right-Click with an empty hand to take items off a belt"); + scene.idle(20); + scene.world.removeItemsFromBelt(util.grid.at(3, 2, 2)); + scene.effects.indicateSuccess(util.grid.at(3, 2, 2)); + scene.idle(20); + + scene.special.changeBirbPose(parrot, FaceCursorPose::new); + } + + public static void beltsCanBeEncased(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("belt_casing", "Encasing Belts"); + scene.configureBasePlate(0, 0, 5); + scene.setSceneOffsetY(-1); + scene.showBasePlate(); + scene.idle(5); + scene.world.showSection(util.select.layersFrom(1), Direction.DOWN); + scene.idle(20); + + ItemStack brassCasingItem = AllBlocks.BRASS_CASING.asStack(); + ItemStack andesiteCasingItem = AllBlocks.ANDESITE_CASING.asStack(); + + BlockPos beltPos = util.grid.at(3, 1, 0); + BlockPos beltPos2 = util.grid.at(0, 2, 3); + BlockPos beltPos3 = util.grid.at(1, 4, 4); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(beltPos), Pointing.DOWN).rightClick() + .withItem(brassCasingItem), 20); + scene.idle(7); + scene.world.modifyBlock(beltPos, s -> s.with(BeltBlock.CASING, true), true); + scene.idle(20); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(beltPos2), Pointing.DOWN).rightClick() + .withItem(andesiteCasingItem), 20); + scene.idle(7); + scene.world.modifyBlock(beltPos2, s -> s.with(BeltBlock.CASING, true), true); + scene.world.modifyTileNBT(util.select.position(beltPos2), BeltTileEntity.class, nbt -> { + NBTHelper.writeEnum(nbt, "Casing", BeltTileEntity.CasingType.ANDESITE); + }); + scene.idle(20); + + scene.overlay.showControls( + new InputWindowElement(util.vector.blockSurface(beltPos3, Direction.EAST), Pointing.RIGHT).rightClick() + .withItem(brassCasingItem), + 20); + scene.idle(7); + scene.world.modifyBlock(beltPos3, s -> s.with(BeltBlock.CASING, true), true); + scene.idle(20); + + scene.overlay.showText(80) + .text("Brass or Andesite Casing can be used to decorate Mechanical Belts") + .pointAt(util.vector.centerOf(beltPos2)); + + scene.idle(40); + + List brassBelts = new ArrayList<>(); + List andesiteBelts = new ArrayList<>(); + + for (int z = 1; z <= 3; z++) + brassBelts.add(beltPos.south(z)); + for (int x = 1; x <= 3; x++) + brassBelts.add(beltPos3.east(x) + .down(x)); + for (int x = 1; x <= 3; x++) + andesiteBelts.add(beltPos2.east(x)); + + Collections.shuffle(andesiteBelts); + Collections.shuffle(brassBelts); + + for (BlockPos pos : andesiteBelts) { + scene.idle(4); + scene.world.modifyBlock(pos, s -> s.with(BeltBlock.CASING, true), true); + scene.world.modifyTileNBT(util.select.position(pos), BeltTileEntity.class, nbt -> { + NBTHelper.writeEnum(nbt, "Casing", BeltTileEntity.CasingType.ANDESITE); + }); + } + for (BlockPos pos : brassBelts) { + scene.idle(4); + scene.world.modifyBlock(pos, s -> s.with(BeltBlock.CASING, true), true); + } + scene.idle(30); + + scene.overlay + .showControls(new InputWindowElement(util.vector.topOf(beltPos.south()), Pointing.DOWN).rightClick() + .withWrench(), 40); + scene.idle(7); + scene.world.modifyBlock(beltPos.south(), s -> s.with(BeltBlock.CASING, false), true); + scene.overlay.showText(80) + .text("A wrench can be used to remove the casing") + .placeNearTarget() + .pointAt(util.vector.blockSurface(beltPos.south(), Direction.WEST)); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/CartAssemblerScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/CartAssemblerScenes.java new file mode 100644 index 000000000..60915ee5c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/CartAssemblerScenes.java @@ -0,0 +1,534 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssembleRailType; +import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.MinecartElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.ponder.instructions.EmitParticlesInstruction.Emitter; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.minecart.ChestMinecartEntity; +import net.minecraft.entity.item.minecart.FurnaceMinecartEntity; +import net.minecraft.entity.item.minecart.MinecartEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.state.properties.RailShape; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class CartAssemblerScenes { + + public static void anchor(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("cart_assembler", "Moving Structures using Cart Assemblers"); + scene.configureBasePlate(0, 0, 5); + scene.scaleSceneView(.9f); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + BlockPos assemblerPos = util.grid.at(2, 1, 2); + scene.world.setBlock(assemblerPos, Blocks.RAIL.getDefaultState(), false); + for (int z = 0; z < 5; z++) { + scene.world.showSection(util.select.position(2, 1, z), Direction.DOWN); + scene.idle(2); + } + + BlockPos leverPos = util.grid.at(0, 1, 2); + Selection toggle = util.select.fromTo(assemblerPos, leverPos); + + scene.idle(10); + + scene.overlay + .showControls(new InputWindowElement(util.vector.centerOf(assemblerPos), Pointing.DOWN).rightClick() + .withItem(AllBlocks.CART_ASSEMBLER.asStack()), 30); + scene.idle(7); + scene.world.setBlock(assemblerPos, AllBlocks.CART_ASSEMBLER.getDefaultState() + .with(CartAssemblerBlock.RAIL_SHAPE, RailShape.NORTH_SOUTH) + .with(CartAssemblerBlock.RAIL_TYPE, CartAssembleRailType.REGULAR), true); + scene.idle(20); + scene.world.showSection(util.select.fromTo(0, 1, 2, 1, 1, 2), Direction.EAST); + scene.idle(20); + scene.world.toggleRedstonePower(toggle); + scene.effects.indicateRedstone(leverPos); + scene.idle(10); + + scene.overlay.showText(70) + .text("Powered Cart Assemblers mount attached structures to passing Minecarts") + .attachKeyFrame() + .pointAt(util.vector.topOf(assemblerPos)) + .placeNearTarget(); + scene.idle(80); + + ElementLink cart = + scene.special.createCart(util.vector.topOf(2, 0, 4), 90, MinecartEntity::new); + scene.world.showSection(util.select.position(assemblerPos.up()), Direction.DOWN); + scene.idle(10); + scene.special.moveCart(cart, util.vector.of(0, 0, -2), 20); + scene.idle(20); + ElementLink plank = + scene.world.makeSectionIndependent(util.select.position(assemblerPos.up())); + ElementLink anchor = + scene.world.showIndependentSectionImmediately(util.select.position(assemblerPos.east())); + scene.world.moveSection(anchor, util.vector.of(-1, 0, 0), 0); + scene.effects.indicateSuccess(assemblerPos); + scene.idle(1); + scene.world.moveSection(anchor, util.vector.of(0, 0, -2), 20); + scene.world.moveSection(plank, util.vector.of(0, 0, -2), 20); + scene.special.moveCart(cart, util.vector.of(0, 0, -2), 20); + scene.idle(20); + + scene.world.toggleRedstonePower(toggle); + scene.idle(10); + + scene.overlay.showText(70) + .text("Without a redstone signal, it disassembles passing cart contraptions back into blocks") + .colored(PonderPalette.RED) + .attachKeyFrame() + .pointAt(util.vector.topOf(assemblerPos)) + .placeNearTarget(); + scene.idle(80); + + scene.world.rotateSection(anchor, 0, 180, 0, 6); + scene.world.rotateSection(plank, 0, 180, 0, 6); + scene.idle(3); + + scene.world.moveSection(anchor, util.vector.of(0, 0, 2), 20); + scene.world.moveSection(plank, util.vector.of(0, 0, 2), 20); + scene.special.moveCart(cart, util.vector.of(0, 0, 2), 20); + scene.idle(21); + scene.world.moveSection(anchor, util.vector.of(0, -2, 0), 0); + scene.special.moveCart(cart, util.vector.of(0, 0, 2), 20); + scene.idle(30); + + scene.world.destroyBlock(assemblerPos.up()); + scene.idle(5); + ElementLink contraption = + scene.world.showIndependentSection(util.select.fromTo(1, 4, 2, 3, 3, 2), Direction.DOWN); + scene.world.moveSection(contraption, util.vector.of(0, -1, 0), 0); + scene.idle(10); + scene.world.showSectionAndMerge(util.select.position(3, 3, 1), Direction.SOUTH, contraption); + scene.idle(15); + scene.effects.superGlue(util.grid.at(3, 2, 1), Direction.SOUTH, true); + scene.overlay.showText(80) + .attachKeyFrame() + .sharedText("movement_anchors") + .pointAt(util.vector.blockSurface(util.grid.at(1, 3, 2), Direction.NORTH)) + .placeNearTarget(); + scene.idle(80); + scene.world.toggleRedstonePower(toggle); + scene.effects.indicateRedstone(leverPos); + + scene.special.moveCart(cart, util.vector.of(0, 0, -2), 20); + scene.idle(20); + scene.world.moveSection(anchor, util.vector.of(0, 2, 0), 0); + scene.idle(1); + scene.world.moveSection(anchor, util.vector.of(0, 0, -2), 20); + scene.world.moveSection(contraption, util.vector.of(0, 0, -2), 20); + scene.special.moveCart(cart, util.vector.of(0, 0, -2), 20); + scene.idle(25); + + Vector3d cartCenter = util.vector.centerOf(assemblerPos.north(2)); + scene.overlay.showControls(new InputWindowElement(cartCenter, Pointing.LEFT).rightClick() + .withWrench(), 40); + scene.idle(7); + scene.special.moveCart(cart, util.vector.of(0, -100, 4), 0); + scene.world.moveSection(anchor, util.vector.of(0, -100, 4), 0); + scene.world.moveSection(contraption, util.vector.of(0, -100, 4), 0); + ItemStack asStack = AllItems.MINECART_CONTRAPTION.asStack(); + ElementLink itemEntity = + scene.world.createItemEntity(cartCenter, util.vector.of(0, .1, 0), asStack); + scene.idle(40); + scene.overlay.showText(80) + .attachKeyFrame() + .text("Using a Wrench on the Minecart will let you carry the Contraption elsewhere") + .pointAt(cartCenter) + .placeNearTarget(); + scene.idle(80); + scene.world.modifyEntity(itemEntity, Entity::remove); + + scene.overlay.showControls(new InputWindowElement(cartCenter.add(0, 0, 4), Pointing.DOWN).rightClick() + .withItem(asStack), 20); + scene.idle(20); + scene.special.moveCart(cart, util.vector.of(0, 100.5, 0), 0); + scene.world.moveSection(anchor, util.vector.of(0, 100.5, 0), 0); + scene.world.moveSection(contraption, util.vector.of(0, 100.5, 0), 0); + scene.idle(1); + scene.special.moveCart(cart, util.vector.of(0, -.5, 0), 5); + scene.world.moveSection(anchor, util.vector.of(0, -.5, 0), 5); + scene.world.moveSection(contraption, util.vector.of(0, -.5, 0), 5); + } + + public static void modes(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("cart_assembler_modes", "Orientation Settings for Minecart Contraptions"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + for (int z = 0; z < 4; z++) { + scene.world.showSection(util.select.position(1, 1, z), Direction.DOWN); + scene.idle(2); + } + for (int x = 2; x < 5; x++) { + scene.world.showSection(util.select.position(x, 1, 3), Direction.DOWN); + scene.idle(2); + } + + BlockPos assemblerPos = util.grid.at(3, 1, 3); + scene.idle(5); + scene.world.setBlock(assemblerPos, AllBlocks.CART_ASSEMBLER.getDefaultState() + .with(CartAssemblerBlock.RAIL_SHAPE, RailShape.EAST_WEST) + .with(CartAssemblerBlock.RAIL_TYPE, CartAssembleRailType.REGULAR), true); + scene.idle(5); + scene.world.showSection(util.select.fromTo(3, 1, 1, 3, 1, 2), Direction.SOUTH); + ElementLink contraption = + scene.world.showIndependentSection(util.select.position(3, 2, 3), Direction.DOWN); + scene.idle(10); + scene.world.glueBlockOnto(util.grid.at(2, 2, 3), Direction.EAST, contraption); + scene.world.toggleRedstonePower(util.select.fromTo(3, 1, 1, 3, 1, 3)); + scene.effects.indicateRedstone(util.grid.at(3, 1, 1)); + scene.idle(10); + + ElementLink cart = + scene.special.createCart(util.vector.topOf(util.grid.at(4, 0, 3)), 0, MinecartEntity::new); + scene.idle(20); + scene.special.moveCart(cart, util.vector.of(-1, 0, 0), 10); + scene.idle(10); + ElementLink anchor = + scene.world.showIndependentSectionImmediately(util.select.position(assemblerPos.south())); + scene.world.moveSection(anchor, util.vector.of(0, 0, -1), 0); + scene.idle(1); + + scene.world.setKineticSpeed(util.select.position(2, 2, 3), 32); + scene.special.moveCart(cart, util.vector.of(-1.5, 0, 0), 15); + scene.world.moveSection(anchor, util.vector.of(-1.5, 0, 0), 15); + scene.world.moveSection(contraption, util.vector.of(-1.5, 0, 0), 15); + scene.idle(16); + scene.special.rotateCart(cart, -45, 2); + scene.special.moveCart(cart, util.vector.of(-.5, 0, -.5), 8); + scene.world.moveSection(anchor, util.vector.of(-.5, 0, -.5), 8); + scene.world.moveSection(contraption, util.vector.of(-.5, 0, -.5), 8); + scene.world.rotateSection(anchor, 0, -90, 0, 12); + scene.world.rotateSection(contraption, 0, -90, 0, 12); + scene.idle(9); + scene.special.rotateCart(cart, -45, 2); + scene.special.moveCart(cart, util.vector.of(0, 0, -1.5), 15); + scene.world.moveSection(anchor, util.vector.of(0, 0, -1.5), 15); + scene.world.moveSection(contraption, util.vector.of(0, 0, -1.5), 15); + scene.idle(15); + scene.world.setKineticSpeed(util.select.position(2, 2, 3), 0); + + scene.overlay.showText(80) + .attachKeyFrame() + .text("Cart Contraptions will rotate to face towards their carts' motion") + .pointAt(util.vector.of(1.5, 2.5, 0)) + .placeNearTarget(); + scene.idle(90); + + scene.world.hideIndependentSection(contraption, Direction.UP); + scene.world.hideIndependentSection(anchor, Direction.UP); + scene.overlay.hideElement(cart, Direction.UP); + scene.idle(25); + + Vector3d blockSurface = util.vector.blockSurface(assemblerPos, Direction.NORTH) + .add(0, 0, -2 / 16f); + scene.overlay.showScrollInput(blockSurface, Direction.NORTH, 60); + scene.overlay.showControls(new InputWindowElement(blockSurface, Pointing.DOWN).scroll() + .withWrench(), 60); + scene.idle(10); + scene.overlay.showText(60) + .pointAt(util.vector.of(3, 1.5, 3)) + .placeNearTarget() + .sharedText("behaviour_modify_wrench"); + scene.idle(70); + + contraption = scene.world.showIndependentSection(util.select.fromTo(3, 2, 3, 2, 2, 3), Direction.DOWN); + cart = scene.special.createCart(util.vector.topOf(util.grid.at(4, 0, 3)), 0, MinecartEntity::new); + scene.idle(10); + scene.special.moveCart(cart, util.vector.of(-1, 0, 0), 10); + scene.idle(10); + anchor = scene.world.showIndependentSectionImmediately(util.select.position(assemblerPos.south())); + scene.world.moveSection(anchor, util.vector.of(0, 0, -1), 0); + scene.idle(1); + + scene.world.setKineticSpeed(util.select.position(2, 2, 3), 32); + scene.special.moveCart(cart, util.vector.of(-1.5, 0, 0), 15); + scene.world.moveSection(anchor, util.vector.of(-1.5, 0, 0), 15); + scene.world.moveSection(contraption, util.vector.of(-1.5, 0, 0), 15); + scene.idle(16); + scene.special.rotateCart(cart, -45, 2); + scene.special.moveCart(cart, util.vector.of(-.5, 0, -.5), 8); + scene.world.moveSection(anchor, util.vector.of(-.5, 0, -.5), 8); + scene.world.moveSection(contraption, util.vector.of(-.5, 0, -.5), 8); + scene.idle(9); + scene.special.rotateCart(cart, -45, 2); + scene.special.moveCart(cart, util.vector.of(0, 0, -1.5), 15); + scene.world.moveSection(anchor, util.vector.of(0, 0, -1.5), 15); + scene.world.moveSection(contraption, util.vector.of(0, 0, -1.5), 15); + scene.idle(15); + scene.world.setKineticSpeed(util.select.position(2, 2, 3), 0); + + scene.overlay.showText(80) + .attachKeyFrame() + .text("If the Assembler is set to Lock Rotation, the contraptions' orientation will never change") + .pointAt(util.vector.of(0, 2.5, 1.5)) + .placeNearTarget(); + scene.idle(90); + } + + public static void dual(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("cart_assembler_dual", "Assembling Carriage Contraptions"); + scene.configureBasePlate(0, 0, 6); + scene.scaleSceneView(.9f); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + for (int z = 0; z < 5; z++) { + scene.world.showSection(util.select.position(1, 1, z), Direction.DOWN); + scene.idle(2); + } + for (int x = 2; x < 6; x++) { + scene.world.showSection(util.select.position(x, 1, 4), Direction.DOWN); + scene.idle(2); + } + + BlockPos assembler1 = util.grid.at(2, 1, 4); + BlockPos assembler2 = util.grid.at(5, 1, 4); + Selection chassis = util.select.fromTo(5, 2, 4, 2, 2, 4); + + scene.idle(5); + scene.world.showSection(util.select.fromTo(2, 1, 3, 2, 1, 2), Direction.SOUTH); + scene.idle(5); + ElementLink cart = + scene.special.createCart(util.vector.topOf(assembler1.down()), 0, MinecartEntity::new); + ElementLink cart2 = + scene.special.createCart(util.vector.topOf(assembler2.down()), 0, ChestMinecartEntity::new); + scene.idle(15); + scene.world.setBlock(assembler1, AllBlocks.CART_ASSEMBLER.getDefaultState() + .with(CartAssemblerBlock.RAIL_SHAPE, RailShape.EAST_WEST) + .with(CartAssemblerBlock.RAIL_TYPE, CartAssembleRailType.CONTROLLER_RAIL), true); + scene.idle(5); + scene.world.setBlock(assembler2, AllBlocks.CART_ASSEMBLER.getDefaultState() + .with(CartAssemblerBlock.RAIL_SHAPE, RailShape.EAST_WEST) + .with(CartAssemblerBlock.RAIL_TYPE, CartAssembleRailType.REGULAR), true); + scene.idle(5); + + ElementLink contraption = scene.world.showIndependentSection(chassis, Direction.DOWN); + scene.idle(15); + scene.overlay.showOutline(PonderPalette.GREEN, new Object(), util.select.position(assembler2), 60); + scene.overlay.showSelectionWithText(util.select.position(assembler1), 60) + .colored(PonderPalette.GREEN) + .pointAt(util.vector.blockSurface(util.grid.at(2, 2, 4), Direction.NORTH)) + .placeNearTarget() + .text("Whenever two Cart Assembers share an attached structure...") + .attachKeyFrame(); + scene.idle(70); + + scene.overlay.showText(60) + .pointAt(util.vector.blockSurface(util.grid.at(2, 1, 4), Direction.NORTH)) + .placeNearTarget() + .text("Powering either of them will create a Carriage Contraption"); + scene.idle(70); + + scene.effects.indicateRedstone(util.grid.at(2, 1, 2)); + scene.world.toggleRedstonePower(util.select.fromTo(2, 1, 2, 2, 1, 4)); + ElementLink anchors = + scene.world.showIndependentSectionImmediately(util.select.fromTo(assembler1.south(), assembler2.south())); + scene.world.moveSection(anchors, util.vector.of(0, 0, -1), 0); + scene.world.configureCenterOfRotation(anchors, util.vector.centerOf(util.grid.at(2, 2, 5))); + scene.world.configureCenterOfRotation(contraption, util.vector.centerOf(util.grid.at(2, 2, 4))); + scene.idle(5); + + Vector3d m = util.vector.of(-0.5, 0, 0); + scene.special.moveCart(cart, m, 5); + scene.special.moveCart(cart2, m, 5); + scene.world.moveSection(contraption, m, 5); + scene.world.moveSection(anchors, m, 5); + scene.idle(5); + scene.special.rotateCart(cart, -45, 2); + scene.special.moveCart(cart2, util.vector.of(-.3, 0, 0), 8); + m = util.vector.of(-.5, 0, -.5); + scene.special.moveCart(cart, m, 8); + scene.world.moveSection(anchors, m, 8); + scene.world.moveSection(contraption, m, 8); + scene.world.rotateSection(anchors, 0, -10, 0, 8); + scene.world.rotateSection(contraption, 0, -10, 0, 8); + scene.idle(8); + scene.special.rotateCart(cart, -45, 2); + scene.special.moveCart(cart2, util.vector.of(-.4, 0, 0), 5); + m = util.vector.of(0, 0, -3.5); + scene.special.moveCart(cart, m, 25); + scene.world.moveSection(anchors, m, 25); + scene.world.moveSection(contraption, m, 25); + scene.world.rotateSection(anchors, 0, -33, 0, 10); + scene.world.rotateSection(contraption, 0, -33, 0, 10); + scene.idle(5); + scene.special.moveCart(cart2, util.vector.of(-0.8, 0, 0), 5); + scene.idle(5); + scene.special.moveCart(cart2, util.vector.of(-1.5, 0, 0), 9); + scene.world.rotateSection(anchors, 0, -42, 0, 9); + scene.world.rotateSection(contraption, 0, -42, 0, 9); + scene.idle(9); + m = util.vector.of(-.5, 0, -.5); + scene.special.moveCart(cart2, m, 2); + scene.special.rotateCart(cart2, -45, 2); + scene.world.rotateSection(anchors, 0, -5, 0, 5); + scene.world.rotateSection(contraption, 0, -5, 0, 5); + scene.idle(2); + scene.special.moveCart(cart2, util.vector.of(0, 0, -.5), 5); + scene.special.rotateCart(cart2, -45, 2); + scene.idle(10); + + scene.overlay.showText(70) + .attachKeyFrame() + .pointAt(util.vector.blockSurface(util.grid.at(1, 1, 3), Direction.WEST)) + .placeNearTarget() + .text("The carts will behave like those connected via Minecart Coupling"); + scene.idle(80); + + } + + public static void rails(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("cart_assembler_rails", "Other types of Minecarts and Rails"); + scene.configureBasePlate(0, 0, 6); + scene.scaleSceneView(.9f); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + for (int x = 0; x < 6; x++) { + scene.world.showSection(util.select.position(x, 1, 3), Direction.DOWN); + scene.idle(2); + } + + BlockPos assembler = util.grid.at(3, 1, 3); + + Selection chassis = util.select.fromTo(4, 2, 3, 2, 2, 3); + + scene.idle(5); + scene.overlay.showText(70) + .attachKeyFrame() + .pointAt(util.vector.blockSurface(assembler, Direction.DOWN)) + .placeNearTarget() + .text("Cart Assemblers on Regular Tracks will not affect the passing carts' motion"); + scene.idle(10); + scene.world.setBlock(assembler, AllBlocks.CART_ASSEMBLER.getDefaultState() + .with(CartAssemblerBlock.RAIL_SHAPE, RailShape.EAST_WEST) + .with(CartAssemblerBlock.RAIL_TYPE, CartAssembleRailType.REGULAR), true); + scene.idle(70); + + ElementLink cart = scene.special.createCart(util.vector.topOf(assembler.east(2) + .down()), 0, MinecartEntity::new); + ElementLink anchor = + scene.world.showIndependentSection(util.select.position(assembler.south()), Direction.DOWN); + ElementLink contraption = + scene.world.showIndependentSection(util.select.position(assembler.south() + .up()), Direction.DOWN); + scene.world.moveSection(contraption, util.vector.of(2, 0, -1), 0); + scene.world.moveSection(anchor, util.vector.of(2, 0, -1), 0); + scene.idle(10); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 10); + scene.world.moveSection(anchor, util.vector.of(-2, 0, 0), 10); + scene.special.moveCart(cart, util.vector.of(-5, 0, 0), 25); + scene.idle(30); + scene.overlay.hideElement(cart, Direction.UP); + scene.world.hideIndependentSection(contraption, Direction.UP); + scene.world.moveSection(anchor, util.vector.of(0, -3, 0), 0); + scene.idle(30); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(assembler), Pointing.DOWN) + .withItem(new ItemStack(Items.POWERED_RAIL)), 50); + scene.idle(7); + scene.world.setBlock(assembler, AllBlocks.CART_ASSEMBLER.getDefaultState() + .with(CartAssemblerBlock.RAIL_SHAPE, RailShape.EAST_WEST) + .with(CartAssemblerBlock.RAIL_TYPE, CartAssembleRailType.POWERED_RAIL), true); + scene.overlay.showText(100) + .attachKeyFrame() + .pointAt(util.vector.topOf(assembler)) + .placeNearTarget() + .text("When on Powered or Controller Rail, the carts will be held in place until it's Powered"); + scene.idle(110); + + scene.world.hideIndependentSection(anchor, Direction.DOWN); + cart = scene.special.createCart(util.vector.topOf(assembler.east(2) + .down()), 0, MinecartEntity::new); + anchor = scene.world.showIndependentSection(util.select.position(assembler.south()), Direction.DOWN); + contraption = scene.world.showIndependentSection(util.select.position(assembler.south() + .up()), Direction.DOWN); + scene.world.moveSection(contraption, util.vector.of(2, 0, -1), 0); + scene.world.moveSection(anchor, util.vector.of(2, 0, -1), 0); + scene.idle(10); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 10); + scene.world.moveSection(anchor, util.vector.of(-2, 0, 0), 10); + scene.special.moveCart(cart, util.vector.of(-2, 0, 0), 10); + scene.world.showSection(util.select.fromTo(3, 1, 1, 3, 1, 2), Direction.SOUTH); + scene.idle(30); + + scene.world.toggleRedstonePower(util.select.fromTo(3, 1, 1, 3, 1, 3)); + scene.effects.indicateRedstone(util.grid.at(3, 1, 1)); + scene.idle(5); + + scene.world.moveSection(contraption, util.vector.of(-3, 0, 0), 15); + scene.world.moveSection(anchor, util.vector.of(-3, 0, 0), 15); + scene.special.moveCart(cart, util.vector.of(-3, 0, 0), 15); + + scene.idle(30); + scene.overlay.hideElement(cart, Direction.UP); + scene.world.hideIndependentSection(anchor, Direction.UP); + scene.world.hideIndependentSection(contraption, Direction.UP); + scene.idle(20); + + cart = scene.special.createCart(util.vector.topOf(assembler.east(2) + .down()), 0, FurnaceMinecartEntity::new); + scene.idle(10); + scene.overlay.showText(50) + .attachKeyFrame() + .pointAt(util.vector.topOf(assembler.east(2))) + .placeNearTarget() + .text("Other types of Minecarts can be used as the anchor"); + scene.idle(50); + contraption = scene.world.showIndependentSection(chassis, Direction.DOWN); + scene.idle(5); + scene.world.glueBlockOnto(assembler.up(2), Direction.DOWN, contraption); + scene.idle(15); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(assembler.up()), Pointing.UP) + .withItem(new ItemStack(Items.CHARCOAL)), 40); + scene.idle(7); + scene.overlay.showText(80) + .pointAt(util.vector.blockSurface(assembler.up(2), Direction.WEST)) + .placeNearTarget() + .text("Furnace Carts will keep themselves powered, pulling fuel from any attached inventories"); + scene.idle(85); + + Emitter smoke = Emitter.simple(ParticleTypes.LARGE_SMOKE, util.vector.of(0, 0, 0)); + + scene.special.moveCart(cart, util.vector.of(-5, 0, 0), 50); + scene.idle(20); + anchor = scene.world.showIndependentSectionImmediately(util.select.position(assembler.south())); + scene.world.moveSection(anchor, util.vector.of(0, 0, -1), 0); + scene.idle(1); + scene.world.setKineticSpeed(util.select.position(2, 2, 3), 32); + scene.world.moveSection(contraption, util.vector.of(-3, 0, 0), 30); + scene.world.moveSection(anchor, util.vector.of(-3, 0, 0), 30); + + Vector3d vec = util.vector.centerOf(assembler) + .add(.25, .25, -0.5); + for (int i = 0; i < 7; i++) { + scene.effects.emitParticles(vec = vec.add(-.5, 0, 0), smoke, 2, 1); + scene.idle(5); + } + + scene.world.setKineticSpeed(util.select.position(2, 2, 3), 0); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/ChainDriveScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/ChainDriveScenes.java new file mode 100644 index 000000000..168e171c2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/ChainDriveScenes.java @@ -0,0 +1,260 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.content.contraptions.relays.encased.EncasedBeltBlock; +import com.simibubi.create.content.logistics.block.redstone.AnalogLeverTileEntity; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.TextWindowElement.Builder; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.RedstoneWireBlock; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; + +public class ChainDriveScenes { + + public static void chainDriveAsRelay(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("chain_drive", "Relaying rotational force with Chain Drives"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + BlockPos gaugePos = util.grid.at(0, 1, 3); + Selection gauge = util.select.position(gaugePos); + scene.world.showSection(gauge, Direction.UP); + scene.world.setKineticSpeed(gauge, 0); + + scene.idle(5); + scene.world.showSection(util.select.fromTo(5, 1, 2, 4, 1, 2), Direction.DOWN); + scene.idle(10); + + for (int i = 0; i < 3; i++) { + scene.idle(5); + scene.world.showSection(util.select.position(3, 1, 2 - i), Direction.DOWN); + if (i != 0) + scene.world.showSection(util.select.position(3, 1, 2 + i), Direction.DOWN); + } + + scene.idle(10); + scene.world.showSection(util.select.position(gaugePos.east(2)), Direction.DOWN); + scene.idle(5); + scene.world.showSection(util.select.position(gaugePos.east()), Direction.DOWN); + scene.idle(5); + + scene.world.setKineticSpeed(gauge, 64); + scene.effects.indicateSuccess(gaugePos); + scene.idle(20); + scene.overlay.showText(60) + .text("Chain Drives relay rotation to each other in a row") + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(3, 1, 4), Direction.WEST)); + scene.idle(60); + + Selection shafts = util.select.fromTo(2, 1, 0, 2, 1, 1); + BlockPos rotatedECD = util.grid.at(3, 1, 0); + Selection verticalShaft = util.select.fromTo(rotatedECD.up(), rotatedECD.up(2)); + + scene.world.showSection(shafts, Direction.EAST); + scene.idle(10); + scene.effects.rotationDirectionIndicator(util.grid.at(2, 1, 0)); + scene.effects.rotationDirectionIndicator(util.grid.at(2, 1, 1)); + scene.idle(20); + scene.overlay.showText(60) + .text("All shafts connected like this will rotate in the same direction") + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(2, 1, 1), Direction.WEST)); + scene.idle(50); + scene.world.hideSection(shafts, Direction.WEST); + scene.idle(25); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(rotatedECD), Pointing.DOWN).rightClick() + .withWrench(), 30); + scene.idle(7); + scene.world.modifyBlock(rotatedECD, s -> s.with(EncasedBeltBlock.AXIS, Axis.Y), true); + scene.idle(40); + + scene.world.showSection(verticalShaft, Direction.DOWN); + scene.idle(10); + + scene.effects.rotationDirectionIndicator(util.grid.at(3, 3, 0)); + scene.idle(10); + scene.overlay.showText(60) + .text("Any part of the row can be rotated by 90 degrees") + .placeNearTarget() + .pointAt(util.vector.centerOf(3, 2, 0)); + + scene.markAsFinished(); + } + + public static void adjustableChainGearshift(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("chain_gearshift", "Controlling rotational speed with Chain Gearshifts"); + scene.configureBasePlate(0, 0, 5); + scene.setSceneOffsetY(-1); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos leverPos = util.grid.at(3, 1, 0); + BlockPos eastDrive = util.grid.at(3, 1, 2); + + BlockPos eastGauge = eastDrive.up(3); + BlockPos middleGauge = eastGauge.west() + .down(); + BlockPos westGauge = eastGauge.west(2) + .down(2); + + ElementLink lever = + scene.world.showIndependentSection(util.select.fromTo(leverPos, leverPos.south()), Direction.UP); + + scene.idle(5); + scene.world.showSection(util.select.fromTo(4, 1, 3, 4, 2, 3), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.fromTo(eastDrive, eastDrive.west(2)) + .add(util.select.position(eastDrive.up())), Direction.DOWN); + scene.idle(10); + + scene.overlay.showText(60) + .text("Unpowered Chain Gearshifts behave exacly like Chain Drives") + .placeNearTarget() + .pointAt(util.vector.blockSurface(eastDrive, Direction.NORTH)); + scene.idle(60); + + scene.world.showSection(util.select.fromTo(eastGauge, eastGauge.down()), Direction.DOWN); + scene.idle(5); + scene.world.showSection(util.select.fromTo(middleGauge, middleGauge.down()), Direction.DOWN); + scene.idle(5); + scene.world.showSection(util.select.position(westGauge), Direction.DOWN); + scene.idle(5); + + for (BlockPos gauge : new BlockPos[] { eastGauge, middleGauge, westGauge }) { + scene.idle(5); + scene.overlay.showText(50) + .sharedText(gauge == eastGauge ? "rpm16_source" : "rpm16") + .colored(PonderPalette.MEDIUM) + .placeNearTarget() + .pointAt(util.vector.blockSurface(gauge, Direction.NORTH)); + } + + scene.idle(60); + + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.south(2))); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(util.select.fromTo(westGauge.down(), middleGauge), f -> 2 * f); + + scene.idle(10); + + AxisAlignedBB bb = new AxisAlignedBB(eastDrive); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.MEDIUM, eastDrive, bb, 160); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.FAST, eastDrive.west(), bb.offset(-2, 0, 0) + .expand(15 / 16f, 0, 0), 160); + scene.idle(20); + + scene.overlay.showText(80) + .text("When Powered, the speed transmitted to other Chain Drives in the row is doubled") + .placeNearTarget() + .colored(PonderPalette.FAST) + .pointAt(util.vector.blockSurface(eastDrive.west(2), Direction.WEST)); + scene.idle(80); + + for (BlockPos gauge : new BlockPos[] { eastGauge, middleGauge, westGauge }) { + scene.idle(5); + scene.overlay.showText(70) + .sharedText(gauge == eastGauge ? "rpm16_source" : "rpm32") + .colored(gauge == eastGauge ? PonderPalette.MEDIUM : PonderPalette.FAST) + .placeNearTarget() + .pointAt(util.vector.blockSurface(gauge, Direction.NORTH)); + } + + scene.idle(80); + + scene.world.hideSection(util.select.fromTo(eastDrive, eastDrive.west(2)), Direction.SOUTH); + scene.idle(15); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.south(2))); + Selection newDriveSelect = util.select.fromTo(eastDrive.south(2), eastDrive.south(2) + .west(2)); + ElementLink drives = scene.world.showIndependentSection(newDriveSelect, Direction.NORTH); + scene.world.modifyKineticSpeed(util.select.fromTo(westGauge.down(), middleGauge), f -> .5f * f); + scene.world.setKineticSpeed(newDriveSelect, -32); + scene.world.moveSection(drives, util.vector.of(0, 0, -2), 0); + scene.world.moveSection(lever, util.vector.of(-2, 0, 0), 10); + + scene.idle(40); + + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.south(1))); + scene.world.toggleRedstonePower(util.select.position(1, 1, 4)); + BlockPos analogPos = leverPos.west(2); + scene.effects.indicateRedstone(analogPos); + scene.world.modifyKineticSpeed(util.select.position(westGauge), f -> .5f * f); + + scene.idle(10); + + bb = new AxisAlignedBB(eastDrive); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.MEDIUM, eastDrive, bb.expand(-15 / 16f, 0, 0), 160); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.SLOW, eastDrive.west(), bb.offset(-2, 0, 0), 160); + scene.idle(20); + + scene.overlay.showText(80) + .text("Whenever the Powered Gearshift is not at the source, its speed will be halved instead") + .placeNearTarget() + .colored(PonderPalette.SLOW) + .pointAt(util.vector.blockSurface(eastDrive.west(2), Direction.WEST)); + scene.idle(80); + + for (BlockPos gauge : new BlockPos[] { eastGauge, middleGauge, westGauge }) { + scene.idle(5); + scene.overlay.showText(180) + .sharedText(gauge == westGauge ? "rpm8" : gauge == eastGauge ? "rpm16_source" : "rpm16") + .colored(gauge == westGauge ? PonderPalette.SLOW : PonderPalette.MEDIUM) + .placeNearTarget() + .pointAt(util.vector.blockSurface(gauge, Direction.NORTH)); + } + + scene.idle(80); + + scene.overlay.showText(100) + .text("In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift") + .placeNearTarget() + .pointAt(util.vector.blockSurface(eastDrive.west(2), Direction.WEST)); + scene.idle(100); + + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.south(2))); + scene.world.toggleRedstonePower(util.select.position(1, 1, 4)); + scene.world.modifyKineticSpeed(util.select.position(westGauge), f -> 2f * f); + scene.world.hideIndependentSection(lever, Direction.UP); + scene.idle(15); + + scene.world.showSection(util.select.fromTo(analogPos, analogPos.south()), Direction.DOWN); + + scene.idle(15); + scene.world.modifyTileNBT(util.select.position(analogPos), AnalogLeverTileEntity.class, nbt -> { + nbt.putInt("State", 8); + }); + scene.world.modifyBlock(analogPos.south(), s -> s.with(RedstoneWireBlock.POWER, 8), false); + scene.world.toggleRedstonePower(util.select.position(1, 1, 4)); + scene.world.modifyKineticSpeed(util.select.position(westGauge), f -> .75f * f); + scene.effects.indicateRedstone(analogPos); + + scene.idle(20); + + scene.overlay.showText(100) + .text("Using analog signals, the ratio can be adjusted more precisely between 1 and 2") + .placeNearTarget() + .pointAt(util.vector.blockSurface(eastDrive.west(2), Direction.WEST)); + scene.idle(40); + + for (BlockPos gauge : new BlockPos[] { eastGauge, middleGauge, westGauge }) { + scene.idle(5); + Builder builder = scene.overlay.showText(180) + .colored(gauge == westGauge ? PonderPalette.SLOW : PonderPalette.MEDIUM) + .placeNearTarget() + .pointAt(util.vector.blockSurface(gauge, Direction.NORTH)); + if (gauge == westGauge) + builder.text("12 RPM"); + else + builder.sharedText(gauge == eastGauge ? "rpm16_source" : "rpm16"); + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/ChassisScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/ChassisScenes.java new file mode 100644 index 000000000..24c7a768f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/ChassisScenes.java @@ -0,0 +1,570 @@ +package com.simibubi.create.foundation.ponder.content; + +import org.apache.commons.lang3.mutable.MutableObject; + +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.LinearChassisBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.RadialChassisBlock; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class ChassisScenes { + + public static void linearGroup(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("linear_chassis_group", "Moving Linear Chassis in groups"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(10); + + BlockPos centralChassis = util.grid.at(2, 2, 2); + ElementLink chassis = + scene.world.showIndependentSection(util.select.position(centralChassis), Direction.DOWN); + scene.idle(10); + scene.world.showSectionAndMerge(util.select.position(centralChassis.west()), Direction.EAST, chassis); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(centralChassis.east()), Direction.WEST, chassis); + scene.idle(4); + scene.world.showSectionAndMerge(util.select.position(centralChassis.east() + .north()), Direction.SOUTH, chassis); + scene.idle(3); + scene.world.showSectionAndMerge(util.select.position(centralChassis.up()), Direction.DOWN, chassis); + scene.idle(2); + scene.world.showSectionAndMerge(util.select.position(centralChassis.up() + .east()), Direction.DOWN, chassis); + scene.idle(10); + + scene.overlay.showText(80) + .attachKeyFrame() + .placeNearTarget() + .text("Linear Chassis connect to identical Chassis blocks next to them") + .pointAt(util.vector.topOf(util.grid.at(2, 3, 2))); + scene.idle(90); + + BlockPos bearingPos = util.grid.at(2, 1, 2); + scene.world.moveSection(chassis, util.vector.of(0, -1 / 1024f, 0), 0); + scene.world.configureCenterOfRotation(chassis, util.vector.centerOf(bearingPos)); + scene.world.rotateBearing(bearingPos, 360, 80); + scene.world.rotateSection(chassis, 0, 360, 0, 80); + + scene.idle(20); + scene.overlay.showText(80) + .placeNearTarget() + .text("When one is moved by a Contraption, the others are dragged with it") + .pointAt(util.vector.topOf(util.grid.at(2, 3, 2))); + scene.idle(90); + + Selection wrong1 = util.select.position(2, 4, 2); + Selection wrong2 = util.select.position(0, 2, 2); + + scene.addKeyframe(); + scene.world.showSection(wrong2, Direction.EAST); + scene.idle(10); + scene.world.showSection(wrong1, Direction.DOWN); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.RED, wrong2, wrong2, 80); + scene.overlay.showSelectionWithText(wrong1, 80) + .colored(PonderPalette.RED) + .placeNearTarget() + .text("Chassis of a different type or facing another direction will not attach"); + scene.idle(40); + + scene.world.rotateBearing(bearingPos, 360, 80); + scene.world.rotateSection(chassis, 0, 360, 0, 80); + } + + public static void linearAttachement(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("linear_chassis_attachment", "Attaching blocks using Linear Chassis"); + scene.configureBasePlate(0, 0, 5); + scene.setSceneOffsetY(-1); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + BlockPos chassisPos = util.grid.at(2, 2, 2); + Selection chassis = util.select.position(chassisPos); + + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.world.showSection(chassis, Direction.DOWN); + scene.idle(10); + + InputWindowElement input = + new InputWindowElement(util.vector.blockSurface(chassisPos, Direction.WEST), Pointing.LEFT).rightClick() + .withItem(new ItemStack(Items.SLIME_BALL)); + scene.overlay.showControls(input, 30); + scene.idle(7); + scene.world.modifyBlock(chassisPos, s -> s.with(LinearChassisBlock.STICKY_BOTTOM, true), false); + scene.effects.superGlue(chassisPos, Direction.WEST, false); + scene.idle(30); + + scene.overlay.showText(60) + .text("The open faces of a Linear Chassis can be made Sticky") + .placeNearTarget() + .pointAt(util.vector.blockSurface(chassisPos, Direction.WEST)); + scene.idle(70); + + scene.overlay.showControls(input, 15); + scene.idle(7); + scene.world.modifyBlock(chassisPos, s -> s.with(LinearChassisBlock.STICKY_TOP, true), false); + scene.effects.superGlue(chassisPos, Direction.EAST, false); + scene.idle(15); + + scene.overlay.showText(60) + .text("Click again to make the opposite side sticky") + .placeNearTarget() + .pointAt(util.vector.topOf(chassisPos)); + scene.idle(10); + scene.rotateCameraY(60); + scene.idle(35); + scene.rotateCameraY(-60); + scene.idle(25); + + scene.overlay.showControls( + new InputWindowElement(util.vector.blockSurface(chassisPos, Direction.WEST), Pointing.LEFT).rightClick() + .whileSneaking(), + 30); + scene.idle(7); + scene.world.modifyBlock(chassisPos, s -> s.with(LinearChassisBlock.STICKY_BOTTOM, false), false); + scene.effects.superGlue(chassisPos, Direction.WEST, false); + scene.idle(30); + + scene.overlay.showText(60) + .text("Sneak and Right-Click with an empty hand to remove the slime") + .placeNearTarget() + .pointAt(util.vector.blockSurface(chassisPos, Direction.WEST)); + scene.idle(70); + + scene.world.hideSection(chassis, Direction.UP); + + scene.idle(20); + ElementLink glassSection = + scene.world.showIndependentSection(util.select.position(chassisPos.up()), Direction.DOWN); + scene.world.moveSection(glassSection, util.vector.of(0, -1, 0), 0); + scene.idle(25); + scene.addKeyframe(); + scene.world.showSectionAndMerge(util.select.fromTo(2, 4, 2, 2, 5, 2), Direction.DOWN, glassSection); + ElementLink topGlassSection = + scene.world.showIndependentSection(util.select.position(2, 6, 2), Direction.DOWN); + scene.world.moveSection(topGlassSection, util.vector.of(0, -1, 0), 0); + scene.idle(30); + + Selection column1 = util.select.fromTo(2, 3, 2, 2, 3, 2); + Selection column2 = util.select.fromTo(2, 3, 2, 2, 4, 2); + Selection column3 = util.select.fromTo(2, 3, 2, 2, 5, 2); + + scene.overlay.showSelectionWithText(column3, 80) + .colored(PonderPalette.GREEN) + .text("Stickied faces of the Linear Chassis will attach a line of blocks in front of it") + .placeNearTarget(); + scene.idle(90); + + BlockPos bearingPos = util.grid.at(2, 1, 2); + scene.world.configureCenterOfRotation(glassSection, util.vector.centerOf(bearingPos)); + scene.world.rotateBearing(bearingPos, 180, 40); + scene.world.rotateSection(glassSection, 0, 180, 0, 40); + scene.world.rotateSection(topGlassSection, 0, 180, 0, 40); + scene.idle(50); + + Vector3d blockSurface = util.vector.blockSurface(chassisPos, Direction.NORTH); + scene.overlay.showCenteredScrollInput(chassisPos, Direction.NORTH, 50); + scene.overlay.showControls(new InputWindowElement(blockSurface, Pointing.UP).scroll() + .withWrench(), 50); + + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, column3, 20); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, column2, 20); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, column1, 20); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, column2, 15); + scene.idle(10); + + scene.overlay.showText(60) + .pointAt(blockSurface) + .text("Using a Wrench, a precise Range can be specified for this chassis") + .placeNearTarget(); + scene.idle(70); + + scene.world.rotateBearing(bearingPos, 180, 40); + scene.world.rotateSection(glassSection, 0, 180, 0, 40); + scene.idle(50); + + scene.world.rotateSection(topGlassSection, 0, 180, 0, 0); + scene.world.showSectionAndMerge(util.select.position(1, 3, 2), Direction.UP, glassSection); + scene.world.showSectionAndMerge(util.select.position(3, 3, 2), Direction.UP, glassSection); + scene.world.showSectionAndMerge(util.select.fromTo(1, 4, 2, 1, 6, 2), Direction.DOWN, glassSection); + scene.world.showSectionAndMerge(util.select.fromTo(3, 4, 2, 3, 6, 2), Direction.DOWN, glassSection); + scene.addKeyframe(); + scene.idle(20); + + scene.overlay.showCenteredScrollInput(chassisPos, Direction.NORTH, 50); + scene.overlay.showControls(new InputWindowElement(blockSurface, Pointing.UP).whileCTRL() + .scroll() + .withWrench(), 50); + + column1 = util.select.fromTo(1, 3, 2, 3, 3, 2); + column2 = util.select.fromTo(1, 3, 2, 3, 4, 2); + column3 = util.select.fromTo(1, 3, 2, 3, 5, 2); + + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, column2, 20); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, column1, 20); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, column2, 20); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, column3, 15); + scene.idle(10); + + scene.overlay.showText(80) + .pointAt(blockSurface) + .text("Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks") + .placeNearTarget(); + scene.idle(90); + + scene.world.rotateBearing(bearingPos, 180, 40); + scene.world.rotateSection(glassSection, 0, 180, 0, 40); + scene.world.rotateSection(topGlassSection, 0, 180, 0, 40); + scene.idle(50); + + Vector3d glueSurface = util.vector.blockSurface(chassisPos.west(), Direction.NORTH); + scene.overlay.showText(80) + .attachKeyFrame() + .pointAt(glueSurface) + .text("Attaching blocks to any other side requires the use of Super Glue") + .placeNearTarget(); + scene.idle(90); + scene.overlay.showControls(new InputWindowElement(glueSurface, Pointing.DOWN).rightClick() + .withItem(AllItems.SUPER_GLUE.asStack()), 30); + scene.idle(7); + ElementLink glueEntity = scene.world.createGlueEntity(chassisPos.west(), Direction.NORTH); + scene.idle(20); + ElementLink gluedPlank = + scene.world.showIndependentSection(util.select.position(3, 3, 1), Direction.SOUTH); + scene.world.moveSection(gluedPlank, util.vector.of(-2, -1, 0), 0); + scene.idle(15); + scene.effects.superGlue(chassisPos.west(), Direction.NORTH, true); + scene.idle(20); + + scene.world.modifyEntity(glueEntity, Entity::remove); + scene.world.hideIndependentSection(glassSection, Direction.UP); + scene.world.hideIndependentSection(gluedPlank, Direction.UP); + scene.world.hideIndependentSection(topGlassSection, Direction.UP); + scene.idle(15); + + scene.addKeyframe(); + ElementLink chain = + scene.world.showIndependentSection(util.select.position(2, 7, 2), Direction.DOWN); + scene.world.configureCenterOfRotation(chain, util.vector.centerOf(bearingPos)); + scene.world.moveSection(chain, util.vector.of(0, -5, 0), 0); + scene.idle(10); + scene.world.showSectionAndMerge(util.select.fromTo(2, 8, 2, 3, 9, 2), Direction.DOWN, chain); + scene.idle(10); + scene.world.showSectionAndMerge(util.select.fromTo(3, 9, 1, 3, 9, 0), Direction.SOUTH, chain); + scene.idle(10); + scene.world.showSectionAndMerge(util.select.fromTo(2, 9, 0, 1, 9, 0), Direction.EAST, chain); + scene.idle(20); + + scene.overlay.showText(80) + .pointAt(util.vector.topOf(chassisPos.up(2))) + .text("Using these mechanics, structures of any shape can move as a Contraption") + .placeNearTarget(); + scene.idle(30); + + scene.world.rotateBearing(bearingPos, 720, 160); + scene.world.rotateSection(chain, 0, 720, 0, 160); + } + + public static void radial(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("radial_chassis", "Attaching blocks using Radial Chassis"); + scene.configureBasePlate(0, 0, 5); + scene.setSceneOffsetY(-1); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + util.select.position(2, 4, 2); + + BlockPos chassisPos = util.grid.at(2, 2, 2); + Selection chassis = util.select.position(chassisPos); + + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(10); + ElementLink contraption = scene.world.showIndependentSection(chassis, Direction.DOWN); + scene.idle(5); + ElementLink top = + scene.world.showIndependentSection(util.select.position(chassisPos.up()), Direction.DOWN); + scene.idle(10); + + scene.overlay.showText(50) + .attachKeyFrame() + .placeNearTarget() + .text("Radial Chassis connect to identical Chassis blocks in a row") + .pointAt(util.vector.topOf(chassisPos.up())); + scene.idle(60); + + BlockPos bearingPos = util.grid.at(2, 1, 2); + scene.world.moveSection(contraption, util.vector.of(0, -1 / 1024f, 0), 0); + scene.world.configureCenterOfRotation(contraption, util.vector.centerOf(bearingPos)); + scene.world.rotateBearing(bearingPos, 360, 80); + scene.world.rotateSection(contraption, 0, 360, 0, 80); + scene.world.rotateSection(top, 0, 360, 0, 80); + + scene.idle(20); + scene.overlay.showText(70) + .placeNearTarget() + .text("When one is moved by a Contraption, the others are dragged with it") + .pointAt(util.vector.topOf(util.grid.at(2, 3, 2))); + scene.idle(80); + + scene.world.hideIndependentSection(top, Direction.UP); + scene.idle(15); + + scene.addKeyframe(); + InputWindowElement input = + new InputWindowElement(util.vector.blockSurface(chassisPos, Direction.WEST), Pointing.LEFT).rightClick() + .withItem(new ItemStack(Items.SLIME_BALL)); + scene.overlay.showControls(input, 30); + scene.idle(7); + scene.world.modifyBlock(chassisPos, s -> s.with(RadialChassisBlock.STICKY_WEST, true), false); + scene.effects.superGlue(chassisPos, Direction.WEST, false); + scene.idle(30); + + scene.overlay.showText(60) + .text("The side faces of a Radial Chassis can be made Sticky") + .placeNearTarget() + .pointAt(util.vector.blockSurface(chassisPos, Direction.WEST)); + scene.idle(70); + + scene.overlay.showControls(input, 15); + scene.idle(7); + scene.world.modifyBlock(chassisPos, s -> s.with(RadialChassisBlock.STICKY_EAST, true) + .with(RadialChassisBlock.STICKY_NORTH, true) + .with(RadialChassisBlock.STICKY_SOUTH, true), false); + scene.effects.superGlue(chassisPos, Direction.EAST, false); + scene.effects.superGlue(chassisPos, Direction.SOUTH, false); + scene.effects.superGlue(chassisPos, Direction.NORTH, false); + scene.idle(15); + + scene.overlay.showText(60) + .text("Click again to make all other sides sticky") + .placeNearTarget() + .pointAt(util.vector.topOf(chassisPos)); + scene.idle(10); + scene.rotateCameraY(60); + scene.idle(35); + scene.rotateCameraY(-60); + scene.idle(25); + + scene.overlay.showControls( + new InputWindowElement(util.vector.blockSurface(chassisPos, Direction.WEST), Pointing.LEFT).rightClick() + .whileSneaking(), + 30); + scene.idle(7); + scene.world.modifyBlock(chassisPos, s -> s.with(RadialChassisBlock.STICKY_WEST, false), false); + scene.effects.superGlue(chassisPos, Direction.WEST, false); + scene.idle(30); + + scene.overlay.showText(60) + .text("Sneak and Right-Click with an empty hand to remove the slime") + .placeNearTarget() + .pointAt(util.vector.blockSurface(chassisPos, Direction.WEST)); + scene.idle(70); + + Selection s = util.select.position(chassisPos.north()); + Selection growing = s.copy(); + Selection r1 = util.select.fromTo(1, 2, 1, 3, 2, 3) + .substract(chassis); + Selection r2 = r1.copy() + .add(util.select.fromTo(0, 2, 1, 0, 2, 3)) + .add(util.select.fromTo(1, 2, 0, 3, 2, 0)) + .add(util.select.fromTo(1, 2, 4, 3, 2, 4)) + .add(util.select.fromTo(4, 2, 1, 4, 2, 3)); + Selection r3 = util.select.layer(2) + .add(util.select.fromTo(-1, 2, 1, 5, 2, 3)) + .add(util.select.fromTo(1, 2, -1, 3, 2, 5)) + .substract(chassis); + + scene.addKeyframe(); + scene.world.showSectionAndMerge(r1, Direction.DOWN, contraption); + ElementLink outer = scene.world.showIndependentSection(util.select.layer(2) + .substract(chassis) + .substract(r1), Direction.DOWN); + scene.world.showSection(util.select.fromTo(0, 3, 3, 1, 3, 4), Direction.DOWN); + scene.idle(10); + Vector3d blockSurface = util.vector.blockSurface(chassisPos, Direction.NORTH); + AxisAlignedBB bb = new AxisAlignedBB(blockSurface, blockSurface).grow(.501, .501, 0); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.GREEN, bb, bb, 60); + scene.overlay.showOutline(PonderPalette.WHITE, s, s, 80); + scene.overlay.showText(40) + .text("Whenever a Block is next to a sticky face...") + .placeNearTarget() + .pointAt(blockSurface.add(0, .5, 0)); + scene.idle(60); + + MutableObject obj = new MutableObject<>(growing); + r2.forEach(pos -> { + scene.idle(1); + Selection add = obj.getValue() + .copy() + .add(util.select.position(pos)); + scene.overlay.showOutline(PonderPalette.WHITE, s, add, 3); + obj.setValue(add); + }); + + scene.overlay.showSelectionWithText(obj.getValue(), 60) + .colored(PonderPalette.GREEN) + .text("...it will attach all reachable blocks within a radius on that layer"); + scene.idle(70); + + scene.world.configureCenterOfRotation(outer, util.vector.centerOf(bearingPos)); + scene.world.rotateBearing(bearingPos, 360, 80); + scene.world.rotateSection(contraption, 0, 360, 0, 80); + scene.world.rotateSection(outer, 0, 360, 0, 80); + scene.idle(90); + + scene.addKeyframe(); + blockSurface = util.vector.topOf(chassisPos); + scene.overlay.showCenteredScrollInput(chassisPos, Direction.UP, 50); + scene.overlay.showControls(new InputWindowElement(blockSurface, Pointing.DOWN).scroll() + .withWrench(), 50); + + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, r2, 20); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, r3, 20); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, r2, 20); + scene.idle(10); + scene.overlay.showOutline(PonderPalette.WHITE, chassis, r1, 15); + scene.idle(10); + + scene.overlay.showText(60) + .pointAt(blockSurface) + .text("Using a Wrench, a precise Radius can be specified for this chassis") + .placeNearTarget(); + scene.idle(70); + + scene.world.rotateBearing(bearingPos, 360, 80); + scene.world.rotateSection(contraption, 0, 360, 0, 80); + scene.idle(90); + + scene.world.destroyBlock(util.grid.at(1, 2, 0)); + scene.idle(1); + scene.world.destroyBlock(util.grid.at(1, 2, 1)); + scene.idle(1); + scene.world.destroyBlock(util.grid.at(1, 2, 3)); + scene.idle(1); + scene.world.destroyBlock(util.grid.at(1, 2, 4)); + scene.idle(10); + + Selection ignored = util.select.fromTo(0, 2, 1, 0, 2, 3) + .add(util.select.position(1, 2, 2)); + scene.overlay.showOutline(PonderPalette.GREEN, r2, r2.copy() + .substract(util.select.fromTo(0, 2, 0, 1, 2, 4)), 80); + scene.markAsFinished(); + scene.overlay.showSelectionWithText(ignored, 80) + .colored(PonderPalette.RED) + .text("Blocks not reachable by any sticky face will not attach"); + } + + public static void superGlue(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("super_glue", "Attaching blocks using Super Glue"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(10); + + BlockPos central = util.grid.at(2, 2, 2); + ElementLink plank = + scene.world.showIndependentSection(util.select.position(central), Direction.DOWN); + scene.idle(15); + Vector3d blockSurface = util.vector.blockSurface(central, Direction.NORTH); + scene.overlay.showControls(new InputWindowElement(blockSurface, Pointing.DOWN).rightClick() + .withItem(AllItems.SUPER_GLUE.asStack()), 40); + scene.idle(7); + ElementLink glueEntity = scene.world.createGlueEntity(central, Direction.NORTH); + scene.idle(10); + scene.overlay.showText(60) + .pointAt(blockSurface) + .placeNearTarget() + .text("Super Glue can be used between any two blocks") + .colored(PonderPalette.GREEN); + scene.idle(50); + + scene.world.glueBlockOnto(central.north(), Direction.SOUTH, plank); + scene.idle(20); + scene.world.modifyEntity(glueEntity, Entity::remove); + + BlockPos bearingPos = util.grid.at(2, 1, 2); + scene.world.configureCenterOfRotation(plank, util.vector.centerOf(bearingPos)); + scene.world.rotateBearing(bearingPos, 360, 80); + scene.world.rotateSection(plank, 0, 360, 0, 80); + scene.idle(30); + scene.overlay.showText(80) + .attachKeyFrame() + .pointAt(util.vector.topOf(central)) + .placeNearTarget() + .text("The attached blocks will move together when assembled into a Contraption"); + scene.idle(90); + + scene.overlay.showText(50) + .attachKeyFrame() + .pointAt(util.vector.topOf(central)) + .placeNearTarget() + .text("Whenever Super Glue is held in the off-hand..."); + scene.idle(60); + + scene.world.glueBlockOnto(central.south(), Direction.NORTH, plank); + scene.idle(5); + scene.world.glueBlockOnto(central.north() + .east(), Direction.WEST, plank); + scene.idle(5); + scene.world.glueBlockOnto(central.up(), Direction.DOWN, plank); + scene.idle(5); + scene.world.glueBlockOnto(central.south() + .west(), Direction.EAST, plank); + scene.idle(10); + + scene.overlay.showText(80) + .pointAt(util.vector.topOf(central) + .subtract(.5, 0, 0)) + .placeNearTarget() + .text("...added blocks will be glued to the face they were placed on automatically"); + scene.idle(90); + + scene.world.rotateBearing(bearingPos, 360, 80); + scene.world.rotateSection(plank, 0, 360, 0, 80); + scene.idle(90); + + glueEntity = scene.world.createGlueEntity(central, Direction.UP); + scene.world.destroyBlock(central.up()); + scene.idle(20); + scene.addKeyframe(); + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(central), Pointing.DOWN).leftClick(), 40); + scene.idle(7); + scene.world.modifyEntity(glueEntity, Entity::remove); + scene.effects.superGlue(central, Direction.UP, false); + scene.idle(10); + scene.overlay.showText(60) + .pointAt(util.vector.topOf(central)) + .placeNearTarget() + .text("Super Glue can be removed with Left-Click"); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/DebugScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/DebugScenes.java new file mode 100644 index 000000000..30199ef5c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/DebugScenes.java @@ -0,0 +1,437 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; +import com.simibubi.create.content.contraptions.particle.RotationIndicatorParticleData; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.PonderRegistry; +import com.simibubi.create.foundation.ponder.PonderStoryBoardEntry.PonderStoryBoard; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.BeltItemElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement.DancePose; +import com.simibubi.create.foundation.ponder.elements.ParrotElement.FacePointOfInterestPose; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.ponder.instructions.EmitParticlesInstruction.Emitter; +import com.simibubi.create.foundation.utility.Pointing; +import com.tterrag.registrate.util.entry.ItemEntry; + +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class DebugScenes { + + private static int index; + + public static void registerAll() { + index = 1; + add(DebugScenes::coordinateScene); + add(DebugScenes::blocksScene); + add(DebugScenes::fluidsScene); + add(DebugScenes::offScreenScene); + add(DebugScenes::particleScene); + add(DebugScenes::controlsScene); + add(DebugScenes::birbScene); + add(DebugScenes::sectionsScene); + add(DebugScenes::itemScene); + } + + private static void add(PonderStoryBoard sb) { + ItemEntry item = AllItems.BRASS_HAND; + String schematicPath = "debug/scene_" + index; + PonderRegistry.addStoryBoard(item, schematicPath, sb) + .highlightAllTags() + .chapter(PonderChapter.of("debug")); + index++; + } + + public static void empty(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_empty", "Missing Content"); + scene.showBasePlate(); + scene.idle(5); + } + + public static void coordinateScene(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_coords", "Coordinate Space"); + scene.showBasePlate(); + scene.idle(10); + scene.world.showSection(util.select.layersFrom(1), Direction.DOWN); + + Selection xAxis = util.select.fromTo(2, 1, 1, 4, 1, 1); + Selection yAxis = util.select.fromTo(1, 2, 1, 1, 4, 1); + Selection zAxis = util.select.fromTo(1, 1, 2, 1, 1, 4); + + scene.idle(10); + scene.overlay.showSelectionWithText(xAxis, 20) + .colored(PonderPalette.RED) + .text("Das X axis"); + scene.idle(20); + scene.overlay.showSelectionWithText(yAxis, 20) + .colored(PonderPalette.GREEN) + .text("Das Y axis"); + scene.idle(20); + scene.overlay.showSelectionWithText(zAxis, 20) + .colored(PonderPalette.BLUE) + .text("Das Z axis"); + } + + public static void blocksScene(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_blocks", "Changing Blocks"); + scene.showBasePlate(); + scene.idle(10); + scene.world.showSection(util.select.layersFrom(1), Direction.DOWN); + scene.idle(10); + scene.overlay.showText(1000) + .independent(10) + .text("Blocks can be modified"); + scene.idle(20); + scene.world.replaceBlocks(util.select.fromTo(1, 1, 3, 2, 2, 4), + AllBlocks.REFINED_RADIANCE_CASING.getDefaultState(), true); + scene.idle(10); + scene.world.replaceBlocks(util.select.position(3, 1, 1), Blocks.GOLD_BLOCK.getDefaultState(), true); + scene.rotateCameraY(180); + scene.markAsFinished(); + } + + public static void fluidsScene(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_fluids", "Showing Fluids"); + scene.showBasePlate(); + scene.idle(10); + Vector3d parrotPos = util.vector.topOf(1, 0, 1); + scene.special.createBirb(parrotPos, FacePointOfInterestPose::new); + scene.world.showSection(util.select.layersFrom(1), Direction.DOWN); + scene.overlay.showText(1000) + .text("Fluid rendering test.") + .pointAt(new Vector3d(1, 2.5, 4.5)); + scene.markAsFinished(); + + Object outlineSlot = new Object(); + + Vector3d vec1 = util.vector.topOf(1, 0, 0); + Vector3d vec2 = util.vector.topOf(0, 0, 1); + AxisAlignedBB boundingBox1 = new AxisAlignedBB(vec1, vec1).expand(0, 2.5, 0) + .grow(.15, 0, .15); + AxisAlignedBB boundingBox2 = new AxisAlignedBB(vec2, vec2).expand(0, .125, 0) + .grow(.45, 0, .45); + Vector3d poi1 = boundingBox1.getCenter(); + Vector3d poi2 = boundingBox2.getCenter(); + + for (int i = 0; i < 10; i++) { + scene.overlay.chaseBoundingBoxOutline(PonderPalette.RED, outlineSlot, + i % 2 == 0 ? boundingBox1 : boundingBox2, 15); + scene.idle(3); + scene.special.movePointOfInterest(i % 2 == 0 ? poi1 : poi2); + scene.idle(12); + } + + scene.idle(12); + scene.special.movePointOfInterest(util.grid.at(-4, 5, 4)); + scene.overlay.showText(40) + .colored(PonderPalette.RED) + .text("wut?") + .pointAt(parrotPos.add(-.25f, 0.25f, .25f)); + + } + + public static void offScreenScene(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_baseplate", "Out of bounds / configureBasePlate"); + scene.configureBasePlate(1, 0, 6); + scene.showBasePlate(); + + Selection out1 = util.select.fromTo(7, 0, 0, 8, 0, 5); + Selection out2 = util.select.fromTo(0, 0, 0, 0, 0, 5); + Selection blocksExceptBasePlate = util.select.layersFrom(1) + .add(out1) + .add(out2); + + scene.idle(10); + scene.world.showSection(blocksExceptBasePlate, Direction.DOWN); + scene.idle(10); + + scene.overlay.showSelectionWithText(out1, 100) + .colored(PonderPalette.BLACK) + .text("Blocks outside of the base plate do not affect scaling"); + scene.overlay.showSelectionWithText(out2, 100) + .colored(PonderPalette.BLACK) + .text("configureBasePlate() makes sure of that."); + scene.markAsFinished(); + } + + public static void particleScene(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_particles", "Emitting particles"); + scene.showBasePlate(); + scene.idle(10); + scene.world.showSection(util.select.layersFrom(1), Direction.DOWN); + scene.idle(10); + + Vector3d emitterPos = util.vector.of(2.5, 2.25, 2.5); + Emitter emitter = Emitter.simple(ParticleTypes.LAVA, util.vector.of(0, .1, 0)); + Emitter rotation = + Emitter.simple(new RotationIndicatorParticleData(SpeedLevel.MEDIUM.getColor(), 12, 1, 1, 20, 'Y'), + util.vector.of(0, .1, 0)); + + scene.overlay.showText(20) + .text("Incoming...") + .pointAt(emitterPos); + scene.idle(30); + scene.effects.emitParticles(emitterPos, emitter, 1, 60); + scene.effects.emitParticles(emitterPos, rotation, 20, 1); + scene.idle(30); + scene.rotateCameraY(180); + } + + public static void controlsScene(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_controls", "Basic player interaction"); + scene.showBasePlate(); + scene.idle(10); + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(4); + scene.world.showSection(util.select.layer(2), Direction.DOWN); + scene.idle(4); + scene.world.showSection(util.select.layer(3), Direction.DOWN); + scene.idle(10); + + BlockPos shaftPos = util.grid.at(3, 1, 1); + Selection shaftSelection = util.select.position(shaftPos); + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(shaftPos), Pointing.DOWN).rightClick() + .whileSneaking() + .withWrench(), 40); + scene.idle(20); + scene.world.replaceBlocks(shaftSelection, AllBlocks.SHAFT.getDefaultState(), true); + + scene.idle(20); + scene.world.hideSection(shaftSelection, Direction.UP); + + scene.idle(20); + + scene.overlay.showControls(new InputWindowElement(util.vector.of(1, 4.5, 3.5), Pointing.LEFT).rightClick() + .withItem(new ItemStack(Blocks.POLISHED_ANDESITE)), 20); + scene.world.showSection(util.select.layer(4), Direction.DOWN); + + scene.idle(40); + + BlockPos chassis = util.grid.at(1, 1, 3); + Vector3d chassisSurface = util.vector.blockSurface(chassis, Direction.NORTH); + + Object chassisValueBoxHighlight = new Object(); + Object chassisEffectHighlight = new Object(); + + AxisAlignedBB point = new AxisAlignedBB(chassisSurface, chassisSurface); + AxisAlignedBB expanded = point.grow(1 / 4f, 1 / 4f, 1 / 16f); + + Selection singleBlock = util.select.position(1, 2, 3); + Selection twoBlocks = util.select.fromTo(1, 2, 3, 1, 3, 3); + Selection threeBlocks = util.select.fromTo(1, 2, 3, 1, 4, 3); + + Selection singleRow = util.select.fromTo(1, 2, 3, 3, 2, 3); + Selection twoRows = util.select.fromTo(1, 2, 3, 3, 3, 3); + Selection threeRows = twoRows.copy() + .add(threeBlocks); + + scene.overlay.chaseBoundingBoxOutline(PonderPalette.GREEN, chassisValueBoxHighlight, point, 1); + scene.idle(1); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.GREEN, chassisValueBoxHighlight, expanded, 120); + scene.overlay.showControls(new InputWindowElement(chassisSurface, Pointing.UP).scroll() + .withWrench(), 40); + + PonderPalette white = PonderPalette.WHITE; + scene.overlay.showOutline(white, chassisEffectHighlight, singleBlock, 10); + scene.idle(10); + scene.overlay.showOutline(white, chassisEffectHighlight, twoBlocks, 10); + scene.idle(10); + scene.overlay.showOutline(white, chassisEffectHighlight, threeBlocks, 10); + scene.idle(10); + scene.overlay.showOutline(white, chassisEffectHighlight, twoBlocks, 10); + scene.idle(10); + scene.overlay.showOutline(white, chassisEffectHighlight, singleBlock, 10); + scene.idle(10); + + scene.idle(30); + scene.overlay.showControls(new InputWindowElement(chassisSurface, Pointing.UP).whileCTRL() + .scroll() + .withWrench(), 40); + + scene.overlay.showOutline(white, chassisEffectHighlight, singleRow, 10); + scene.idle(10); + scene.overlay.showOutline(white, chassisEffectHighlight, twoRows, 10); + scene.idle(10); + scene.overlay.showOutline(white, chassisEffectHighlight, threeRows, 10); + scene.idle(10); + scene.overlay.showOutline(white, chassisEffectHighlight, twoRows, 10); + scene.idle(10); + scene.overlay.showOutline(white, chassisEffectHighlight, singleRow, 10); + scene.idle(10); + + scene.markAsFinished(); + } + + public static void birbScene(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_birbs", "Birbs"); + scene.showBasePlate(); + scene.idle(10); + scene.world.showSection(util.select.layersFrom(1), Direction.DOWN); + scene.idle(10); + + BlockPos pos = new BlockPos(1, 2, 3); + scene.special.birbOnSpinnyShaft(pos); + scene.overlay.showText(100) + .colored(PonderPalette.GREEN) + .text("More birbs = More interesting") + .pointAt(util.vector.topOf(pos)); + + scene.idle(10); + scene.special.createBirb(util.vector.topOf(0, 1, 2), DancePose::new); + scene.idle(10); + + scene.special.createBirb(util.vector.centerOf(3, 1, 3) + .add(0, 0.25f, 0), FacePointOfInterestPose::new); + scene.idle(20); + + BlockPos poi1 = util.grid.at(4, 1, 0); + BlockPos poi2 = util.grid.at(0, 1, 4); + + scene.world.setBlock(poi1, Blocks.GOLD_BLOCK.getDefaultState(), true); + scene.special.movePointOfInterest(poi1); + scene.idle(20); + + scene.world.setBlock(poi2, Blocks.GOLD_BLOCK.getDefaultState(), true); + scene.special.movePointOfInterest(poi2); + scene.overlay.showText(20) + .text("Point of Interest") + .pointAt(util.vector.centerOf(poi2)); + scene.idle(20); + + scene.world.destroyBlock(poi1); + scene.special.movePointOfInterest(poi1); + scene.idle(20); + + scene.world.destroyBlock(poi2); + scene.special.movePointOfInterest(poi2); + } + + public static void sectionsScene(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_sections", "Sections"); + scene.showBasePlate(); + scene.idle(10); + scene.rotateCameraY(95); + + BlockPos mergePos = util.grid.at(1, 1, 1); + BlockPos independentPos = util.grid.at(3, 1, 1); + Selection toMerge = util.select.position(mergePos); + Selection independent = util.select.position(independentPos); + Selection start = util.select.layersFrom(1) + .substract(toMerge) + .substract(independent); + + scene.world.showSection(start, Direction.DOWN); + scene.idle(20); + + scene.world.showSection(toMerge, Direction.DOWN); + ElementLink link = scene.world.showIndependentSection(independent, Direction.DOWN); + + scene.idle(20); + + scene.overlay.showText(40) + .colored(PonderPalette.GREEN) + .text("This Section got merged to base.") + .pointAt(util.vector.topOf(mergePos)); + scene.idle(10); + scene.overlay.showText(40) + .colored(PonderPalette.RED) + .text("This Section renders independently.") + .pointAt(util.vector.topOf(independentPos)); + + scene.idle(40); + + scene.world.hideIndependentSection(link, Direction.DOWN); + scene.world.hideSection(util.select.fromTo(mergePos, util.grid.at(1, 1, 4)), Direction.DOWN); + + scene.idle(20); + + Selection hiddenReplaceArea = util.select.fromTo(2, 1, 2, 4, 1, 4) + .substract(util.select.position(4, 1, 3)) + .substract(util.select.position(2, 1, 3)); + + scene.world.hideSection(hiddenReplaceArea, Direction.UP); + scene.idle(20); + scene.world.setBlocks(hiddenReplaceArea, AllBlocks.REFINED_RADIANCE_CASING.getDefaultState(), false); + scene.world.showSection(hiddenReplaceArea, Direction.DOWN); + scene.idle(20); + scene.overlay.showSelectionWithText(hiddenReplaceArea, 30) + .colored(PonderPalette.BLUE) + .text("Seamless substitution of blocks"); + + scene.idle(40); + + ElementLink helicopter = scene.world.makeSectionIndependent(hiddenReplaceArea); + scene.world.rotateSection(helicopter, 50, 5 * 360, 0, 60); + scene.world.moveSection(helicopter, util.vector.of(0, 4, 5), 50); + scene.overlay.showText(30) + .colored(PonderPalette.BLUE) + .text("Up, up and away.") + .independent(30); + + scene.idle(40); + scene.world.hideIndependentSection(helicopter, Direction.UP); + + } + + public static void itemScene(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("debug_items", "Manipulating Items"); + scene.configureBasePlate(0, 0, 6); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(10); + scene.world.showSection(util.select.layersFrom(1), Direction.DOWN); + + ItemStack brassItem = AllItems.BRASS_INGOT.asStack(); + ItemStack copperItem = AllItems.COPPER_INGOT.asStack(); + + for (int z = 4; z >= 2; z--) { + scene.world.createItemEntity(util.vector.centerOf(0, 4, z), Vector3d.ZERO, brassItem.copy()); + scene.idle(10); + } + + BlockPos beltPos = util.grid.at(2, 1, 3); + ElementLink itemOnBelt = + scene.world.createItemOnBelt(beltPos, Direction.EAST, copperItem.copy()); + + scene.idle(10); + scene.world.stallBeltItem(itemOnBelt, true); + scene.idle(5); + scene.overlay.showText(40) + .colored(PonderPalette.FAST) + .text("Belt Items can only be force-stalled on the belt they were created on.") + .pointAt(util.vector.topOf(2, 1, 2)); + scene.idle(45); + scene.world.stallBeltItem(itemOnBelt, false); + scene.idle(20); + + scene.world.modifyEntities(ItemEntity.class, entity -> { + if (copperItem.isItemEqual(entity.getItem())) + entity.setNoGravity(true); + }); + + scene.idle(20); + + scene.world.modifyEntities(ItemEntity.class, entity -> { + if (brassItem.isItemEqual(entity.getItem())) + entity.setMotion(util.vector.of(-.15f, .5f, 0)); + }); + + scene.idle(27); + + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/DeployerScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/DeployerScenes.java new file mode 100644 index 000000000..49af64c7c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/DeployerScenes.java @@ -0,0 +1,460 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.ponder.instructions.EmitParticlesInstruction.Emitter; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.passive.SheepEntity; +import net.minecraft.item.DyeColor; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.particles.BlockParticleData; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class DeployerScenes { + + public static void filter(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("deployer", "Using the Deployer"); + scene.configureBasePlate(0, 0, 5); + + BlockPos potPosition = util.grid.at(1, 1, 2); + BlockPos deployerPos = util.grid.at(3, 1, 2); + Selection deployerSelection = util.select.position(deployerPos); + + scene.world.setBlock(potPosition, Blocks.AIR.getDefaultState(), false); + scene.world.showSection(util.select.layer(0) + .add(util.select.position(1, 1, 2)), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(3, 1, 3, 3, 1, 5), Direction.DOWN); + scene.idle(10); + + scene.world.showSection(deployerSelection, Direction.SOUTH); + scene.idle(10); + + scene.overlay.showText(60) + .placeNearTarget() + .pointAt(util.vector.topOf(deployerPos)) + .text("Given Rotational Force, a Deployer can imitate player interactions"); + scene.world.moveDeployer(deployerPos, 1, 25); + scene.idle(26); + scene.world.moveDeployer(deployerPos, -1, 25); + scene.idle(44); + + scene.overlay.showSelectionWithText(util.select.position(deployerPos.west(2)), 60) + .text("It will always interact with the position 2 blocks in front of itself") + .attachKeyFrame() + .placeNearTarget() + .colored(PonderPalette.GREEN) + .attachKeyFrame(); + scene.world.moveDeployer(deployerPos, 1, 25); + scene.idle(26); + scene.world.moveDeployer(deployerPos, -1, 25); + scene.idle(20); + scene.world.showSection(util.select.fromTo(2, 1, 3, 2, 1, 1), Direction.DOWN); + scene.idle(24); + + scene.overlay.showText(50) + .pointAt(util.vector.topOf(deployerPos.west())) + .text("Blocks directly in front will not obstruct it") + .placeNearTarget(); + scene.world.moveDeployer(deployerPos, 1, 25); + scene.idle(26); + scene.world.moveDeployer(deployerPos, -1, 25); + scene.idle(34); + scene.world.hideSection(util.select.fromTo(2, 1, 3, 2, 1, 1), Direction.UP); + scene.idle(20); + + String[] actions = + new String[] { "Place Blocks,", "Use Items,", "Activate Blocks,", "Harvest blocks", "and Attack Mobs" }; + + scene.overlay.showText(80) + .attachKeyFrame() + .independent(40) + .placeNearTarget() + .text("Deployers can:"); + + int y = 60; + for (String s : actions) { + scene.idle(15); + scene.overlay.showText(50) + .colored(PonderPalette.MEDIUM) + .placeNearTarget() + .independent(y) + .text(s); + y += 16; + } + scene.idle(50); + + ItemStack pot = new ItemStack(Items.FLOWER_POT); + Vector3d frontVec = util.vector.blockSurface(deployerPos, Direction.WEST) + .add(-.125, 0, 0); + + scene.overlay.showControls(new InputWindowElement(frontVec, Pointing.DOWN).rightClick() + .withItem(pot), 40); + scene.idle(7); + Class teType = DeployerTileEntity.class; + scene.world.modifyTileNBT(deployerSelection, teType, nbt -> nbt.put("HeldItem", pot.serializeNBT())); + scene.idle(10); + + scene.overlay.showText(40) + .attachKeyFrame() + .placeNearTarget() + .pointAt(frontVec) + .text("Right-click the front to give it an Item to use"); + scene.idle(40); + scene.world.moveDeployer(deployerPos, 1, 25); + scene.idle(26); + scene.world.restoreBlocks(util.select.position(potPosition)); + scene.world.modifyTileNBT(deployerSelection, teType, + nbt -> nbt.put("HeldItem", ItemStack.EMPTY.serializeNBT())); + scene.world.moveDeployer(deployerPos, -1, 25); + scene.idle(20); + + scene.world.showSection(util.select.position(deployerPos.up()), Direction.DOWN); + + ItemStack tulip = new ItemStack(Items.RED_TULIP); + Vector3d entitySpawn = util.vector.topOf(deployerPos.up(3)); + + ElementLink entity1 = + scene.world.createItemEntity(entitySpawn, util.vector.of(0, 0.2, 0), tulip); + scene.idle(17); + scene.world.modifyEntity(entity1, Entity::remove); + scene.world.modifyTileNBT(deployerSelection, teType, nbt -> nbt.put("HeldItem", tulip.serializeNBT())); + scene.idle(10); + scene.overlay.showText(40) + .placeNearTarget() + .pointAt(util.vector.of(3, 2.5, 3)) + .text("Items can also be inserted automatically"); + scene.idle(30); + scene.world.moveDeployer(deployerPos, 1, 25); + scene.idle(26); + scene.world.setBlock(potPosition, Blocks.POTTED_RED_TULIP.getDefaultState(), false); + scene.world.modifyTileNBT(deployerSelection, teType, + nbt -> nbt.put("HeldItem", ItemStack.EMPTY.serializeNBT())); + scene.world.moveDeployer(deployerPos, -1, 25); + scene.idle(25); + scene.world.hideSection(util.select.position(potPosition), Direction.UP); + scene.world.hideSection(util.select.position(deployerPos.up()), Direction.EAST); + scene.idle(20); + + Vector3d filterSlot = frontVec.add(0.375, 0.25, 0); + scene.overlay.showFilterSlotInput(filterSlot, 80); + scene.overlay.showText(40) + .attachKeyFrame() + .placeNearTarget() + .pointAt(filterSlot) + .text("Deployers carry a filter slot"); + scene.idle(50); + + ItemStack shears = new ItemStack(Items.SHEARS); + + scene.overlay.showControls(new InputWindowElement(filterSlot, Pointing.DOWN).rightClick() + .withItem(shears), 40); + scene.idle(7); + scene.world.setFilterData(deployerSelection, teType, shears); + scene.overlay.showText(60) + .placeNearTarget() + .pointAt(filterSlot) + .text("When a filter is set, it activates only while holding a matching item"); + scene.idle(70); + + ElementLink sheep = scene.world.createEntity(w -> { + SheepEntity entity = EntityType.SHEEP.create(w); + entity.setFleeceColor(DyeColor.PINK); + Vector3d p = util.vector.topOf(util.grid.at(1, 0, 2)); + entity.setPosition(p.x, p.y, p.z); + entity.prevPosX = p.x; + entity.prevPosY = p.y; + entity.prevPosZ = p.z; + entity.limbSwing = 0; + entity.prevRotationYaw = 210; + entity.rotationYaw = 210; + entity.prevRotationYawHead = 210; + entity.rotationYawHead = 210; + return entity; + }); + scene.idle(20); + scene.world.showSection(util.select.position(deployerPos.up()), Direction.WEST); + entity1 = scene.world.createItemEntity(entitySpawn, util.vector.of(0, 0.2, 0), shears); + scene.idle(17); + scene.world.modifyEntity(entity1, Entity::remove); + scene.world.modifyTileNBT(deployerSelection, teType, nbt -> nbt.put("HeldItem", shears.serializeNBT())); + scene.idle(10); + + scene.overlay.showText(60) + .placeNearTarget() + .pointAt(util.vector.of(3, 2.5, 3)) + .text("Only items matching the filter can now be inserted..."); + + scene.idle(70); + scene.world.moveDeployer(deployerPos, 1, 25); + scene.idle(26); + scene.world.modifyEntity(sheep, e -> ((SheepEntity) e).setSheared(true)); + scene.effects.emitParticles(util.vector.topOf(deployerPos.west(2)) + .add(0, -.25, 0), + Emitter.withinBlockSpace(new BlockParticleData(ParticleTypes.BLOCK, Blocks.PINK_WOOL.getDefaultState()), + util.vector.of(0, 0, 0)), + 25, 1); + scene.world.moveDeployer(deployerPos, -1, 25); + scene.world.showSection(util.select.position(deployerPos.north()), Direction.SOUTH); + scene.idle(25); + + scene.overlay.showText(80) + .placeNearTarget() + .pointAt(util.vector.of(3.5, 1.25, 1.25)) + .text("...and only non-matching items will be extracted"); + scene.world.flapFunnel(deployerPos.north(), true); + scene.world.createItemEntity(util.vector.centerOf(deployerPos.north()) + .subtract(0, .45, 0), util.vector.of(0, 0, -0.1), new ItemStack(Items.PINK_WOOL)); + + scene.markAsFinished(); + for (int i = 0; i < 10; i++) { + scene.idle(26); + scene.world.moveDeployer(deployerPos, 1, 25); + scene.idle(26); + scene.world.moveDeployer(deployerPos, -1, 25); + scene.idle(26); + } + } + + public static void modes(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("deployer_modes", "Modes of the Deployer"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(3, 1, 3, 3, 1, 5), Direction.DOWN); + scene.idle(10); + + BlockPos deployerPos = util.grid.at(3, 1, 2); + Vector3d frontVec = util.vector.blockSurface(deployerPos, Direction.WEST) + .add(-.125, 0, 0); + Selection grassBlock = util.select.position(1, 1, 2); + + Selection deployerSelection = util.select.position(deployerPos); + scene.world.showSection(deployerSelection, Direction.DOWN); + scene.idle(10); + scene.world.showSection(grassBlock, Direction.DOWN); + scene.idle(10); + + ItemStack tool = new ItemStack(Items.GOLDEN_HOE); + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(deployerPos), Pointing.DOWN).withItem(tool), + 30); + scene.idle(7); + scene.world.modifyTileNBT(deployerSelection, DeployerTileEntity.class, + nbt -> nbt.put("HeldItem", tool.serializeNBT())); + scene.idle(45); + + scene.world.setKineticSpeed(util.select.position(2, 0, 5), 16); + scene.world.setKineticSpeed(util.select.layer(1), -32); + scene.world.moveDeployer(deployerPos, 1, 25); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.topOf(1, 1, 2)) + .text("By default, a Deployer imitates a Right-click interaction"); + + scene.idle(26); + scene.world.replaceBlocks(grassBlock, Blocks.FARMLAND.getDefaultState(), false); + scene.world.moveDeployer(deployerPos, -1, 25); + scene.idle(46); + + scene.overlay.showControls(new InputWindowElement(frontVec, Pointing.LEFT).rightClick() + .withWrench(), 40); + scene.idle(7); + scene.world.modifyTileNBT(deployerSelection, DeployerTileEntity.class, nbt -> nbt.putString("Mode", "PUNCH")); + scene.idle(45); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.topOf(1, 1, 2)) + .text("Using a Wrench, it can be set to imitate a Left-click instead"); + + BlockPos breakingPos = deployerPos.west(2); + for (int i = 0; i < 4; i++) { + scene.idle(26); + scene.world.moveDeployer(deployerPos, 1, 25); + scene.idle(26); + scene.world.incrementBlockBreakingProgress(breakingPos); + scene.world.incrementBlockBreakingProgress(breakingPos); + scene.world.incrementBlockBreakingProgress(breakingPos); + scene.world.moveDeployer(deployerPos, -1, 25); + if (i == 3) + scene.world.createItemEntity(util.vector.centerOf(breakingPos), util.vector.of(0, 0, 0), + new ItemStack(Blocks.DIRT)); + scene.idle(26); + + if (i == 0) + scene.markAsFinished(); + } + } + + public static void redstone(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("deployer_redstone", "Controlling Deployers with Redstone"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(3, 1, 5, 3, 1, 3), Direction.DOWN); + + BlockPos deployerPos = util.grid.at(3, 1, 3); + Selection redstone = util.select.fromTo(3, 1, 1, 3, 1, 2); + BlockPos leverPos = util.grid.at(3, 1, 1); + + scene.world.toggleRedstonePower(redstone); + + scene.idle(26); + scene.world.moveDeployer(deployerPos, 1, 30); + scene.idle(31); + scene.world.moveDeployer(deployerPos, -1, 30); + scene.world.showSection(redstone, Direction.SOUTH); + scene.idle(31); + + scene.world.toggleRedstonePower(redstone); + scene.effects.indicateRedstone(leverPos); + scene.idle(10); + + scene.overlay.showText(60) + .colored(PonderPalette.RED) + .attachKeyFrame() + .pointAt(util.vector.topOf(deployerPos)) + .placeNearTarget() + .text("When powered by Redstone, Deployers will not activate"); + scene.idle(70); + + scene.world.toggleRedstonePower(redstone); + scene.idle(10); + scene.world.moveDeployer(deployerPos, 1f, 30); + scene.idle(10); + + scene.world.toggleRedstonePower(redstone); + scene.effects.indicateRedstone(leverPos); + scene.idle(21); + + scene.overlay.showText(60) + .pointAt(util.vector.topOf(deployerPos)) + .placeNearTarget() + .text("Before stopping, the Deployer will finish any started cycles"); + + scene.world.moveDeployer(deployerPos, -1f, 30); + scene.idle(70); + + scene.world.toggleRedstonePower(redstone); + scene.idle(3); + scene.world.toggleRedstonePower(redstone); + scene.effects.indicateRedstone(leverPos); + scene.world.moveDeployer(deployerPos, 1, 30); + scene.overlay.showText(100) + .colored(PonderPalette.GREEN) + .attachKeyFrame() + .pointAt(util.vector.topOf(deployerPos)) + .placeNearTarget() + .text("Thus, a negative pulse can be used to trigger exactly one activation cycle"); + scene.idle(31); + scene.world.moveDeployer(deployerPos, -1, 30); + + } + + public static void contraption(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("deployer_contraption", "Using Deployers on Contraptions"); + scene.configureBasePlate(0, 0, 6); + scene.scaleSceneView(.9f); + Selection flowers = util.select.fromTo(4, 1, 1, 1, 1, 1); + scene.world.replaceBlocks(flowers, Blocks.AIR.getDefaultState(), false); + + Selection kinetics = util.select.fromTo(5, 1, 6, 5, 1, 3); + BlockPos deployerPos = util.grid.at(4, 1, 3); + Selection deployerSelection = util.select.position(deployerPos); + + scene.world.showSection(util.select.layer(0) + .add(flowers), Direction.UP); + scene.idle(5); + + ElementLink pistonHead = + scene.world.showIndependentSection(util.select.fromTo(5, 1, 2, 8, 1, 2), Direction.DOWN); + scene.world.moveSection(pistonHead, util.vector.of(0, 0, 1), 0); + scene.world.showSection(kinetics, Direction.DOWN); + scene.idle(5); + + ElementLink contraption = + scene.world.showIndependentSection(deployerSelection, Direction.DOWN); + scene.idle(5); + scene.world.glueBlockOnto(util.grid.at(4, 2, 3), Direction.DOWN, contraption); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.blockSurface(deployerPos, Direction.WEST)) + .text("Whenever Deployers are moved as part of an animated Contraption..."); + scene.idle(70); + + scene.world.setKineticSpeed(util.select.position(4, 0, 6), -8); + scene.world.setKineticSpeed(kinetics, 16); + scene.world.moveSection(pistonHead, util.vector.of(-3, 0, 0), 100); + scene.world.moveSection(contraption, util.vector.of(-3, 0, 0), 100); + + for (int x = 0; x < 4; x++) { + scene.world.moveDeployer(deployerPos, 1, 9); + scene.idle(10); + scene.world.moveDeployer(deployerPos, -1, 9); + scene.world.restoreBlocks(util.select.position(4 - x, 1, 1)); + scene.idle(18); + } + + scene.overlay.showSelectionWithText(flowers, 90) + .attachKeyFrame() + .colored(PonderPalette.GREEN) + .text("They activate at each visited location, using items from inventories anywhere on the contraption"); + scene.idle(100); + + scene.world.hideSection(flowers, Direction.UP); + scene.idle(15); + scene.world.replaceBlocks(flowers, Blocks.AIR.getDefaultState(), false); + scene.world.showSection(flowers, Direction.UP); + + Vector3d frontVec = util.vector.blockSurface(deployerPos.west(3), Direction.NORTH) + .add(0, 0, -.125); + Vector3d filterSlot = frontVec.add(0, 0.25, 0.375); + scene.overlay.showFilterSlotInput(filterSlot, 80); + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(filterSlot) + .text("The Filter slot can be used to specify which items to pull"); + scene.idle(70); + + ItemStack poppy = new ItemStack(Items.POPPY); + scene.overlay.showControls(new InputWindowElement(filterSlot, Pointing.DOWN).withItem(poppy), 30); + scene.idle(7); + scene.world.setFilterData(deployerSelection, DeployerTileEntity.class, poppy); + scene.idle(25); + + scene.world.setKineticSpeed(util.select.position(4, 0, 6), 8); + scene.world.setKineticSpeed(kinetics, -16); + scene.world.moveSection(pistonHead, util.vector.of(3, 0, 0), 100); + scene.world.moveSection(contraption, util.vector.of(3, 0, 0), 100); + + for (int x = 0; x < 4; x++) { + scene.world.moveDeployer(deployerPos, 1, 9); + scene.idle(10); + scene.world.moveDeployer(deployerPos, -1, 9); + scene.world.setBlock(util.grid.at(1 + x, 1, 1), Blocks.POPPY.getDefaultState(), false); + scene.idle(18); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/FanScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/FanScenes.java new file mode 100644 index 000000000..6a22d56ed --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/FanScenes.java @@ -0,0 +1,297 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; +import com.simibubi.create.content.logistics.block.depot.DepotTileEntity; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.BeltItemElement; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement.FlappyPose; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.ponder.instructions.EmitParticlesInstruction.Emitter; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class FanScenes { + + public static void direction(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("fan_direction", "Air flow of Encased Fans"); + scene.configureBasePlate(0, 1, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(3, 1, 0, 3, 1, 5) + .add(util.select.position(3, 2, 4)), Direction.DOWN); + scene.world.showSection(util.select.fromTo(2, 1, 5, 1, 1, 5), Direction.DOWN); + scene.idle(10); + + BlockPos fanPos = util.grid.at(1, 1, 4); + scene.world.showSection(util.select.position(fanPos), Direction.SOUTH); + + scene.idle(40); + scene.effects.rotationDirectionIndicator(fanPos.south()); + + ElementLink flappyBirb = scene.special.createBirb(util.vector.topOf(1, 0, 3), FlappyPose::new); + scene.idle(2); + scene.special.rotateParrot(flappyBirb, 0, 235, 0, 30); + scene.special.moveParrot(flappyBirb, util.vector.of(0, 0, -2.5), 30); + scene.idle(20); + + scene.overlay.showText(80) + .text("Encased Fans use Rotational Force to create an Air Current") + .placeNearTarget() + .pointAt(util.vector.topOf(fanPos)); + scene.idle(90); + + BlockPos leverPos = util.grid.at(3, 2, 4); + Selection reverse = util.select.fromTo(3, 1, 5, 1, 1, 4); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reverse, f -> -f); + scene.effects.rotationDirectionIndicator(fanPos.south()); + scene.special.rotateParrot(flappyBirb, 0, 215 * 2, 0, 30); + scene.special.moveParrot(flappyBirb, util.vector.of(0, 0, 2.5), 30); + scene.idle(31); + + scene.overlay.showText(60) + .text("Strength and Direction of Flow depends on the Rotational Input") + .placeNearTarget() + .pointAt(util.vector.topOf(fanPos)); + scene.markAsFinished(); + scene.idle(70); + + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reverse, f -> -f); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> 4 * f); + scene.effects.rotationSpeedIndicator(fanPos.south()); + scene.special.rotateParrot(flappyBirb, 0, 245 * 4, 0, 30); + scene.special.moveParrot(flappyBirb, util.vector.of(0, 0, -20), 30); + + } + + public static void processing(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("fan_processing", "Processing Items using Encased Fans"); + scene.configureBasePlate(1, 0, 5); + scene.world.showSection(util.select.layer(0) + .substract(util.select.position(0, 0, 4)), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(6, 1, 2, 5, 1, 2) + .add(util.select.position(1, 1, 2)), Direction.DOWN); + scene.idle(25); + + BlockPos blockPos = util.grid.at(4, 1, 2); + + // blasting start + + ElementLink blockInFront = + scene.world.showIndependentSection(util.select.position(3, 1, 0), Direction.SOUTH); + scene.world.moveSection(blockInFront, util.vector.of(1, 0, 2), 0); + scene.world.setBlock(blockPos, Blocks.LAVA.getDefaultState(), false); + scene.idle(10); + + scene.overlay.showSelectionWithText(util.select.fromTo(blockPos, blockPos.west(2)), 80) + .colored(PonderPalette.RED) + .text("When passing through lava, the Air Flow becomes Heated"); + scene.idle(80); + + ItemStack stack = new ItemStack(Items.GOLD_ORE); + ItemStack smelted = new ItemStack(Items.GOLD_INGOT); + + ElementLink entityLink = scene.world.createItemEntity(util.vector.centerOf(blockPos.west(2) + .up(2)), util.vector.of(0, 0.1, 0), stack); + scene.idle(15); + scene.world.modifyEntity(entityLink, e -> e.setMotion(-0.2f, 0, 0)); + Vector3d itemVec = util.vector.blockSurface(util.grid.at(1, 1, 2), Direction.EAST) + .add(0.1, 0, 0); + scene.overlay.showControls(new InputWindowElement(itemVec, Pointing.DOWN).withItem(stack), 20); + scene.idle(20); + scene.effects.emitParticles(itemVec.add(0, 0.2f, 0), Emitter.simple(ParticleTypes.LARGE_SMOKE, Vector3d.ZERO), 1, + 60); + + scene.overlay.showText(80) + .colored(PonderPalette.WHITE) + .pointAt(itemVec) + .placeNearTarget() + .text("Items caught in the area will be smelted"); + + scene.idle(60); + scene.world.modifyEntities(ItemEntity.class, ie -> ie.setItem(smelted)); + scene.idle(40); + scene.overlay.showControls(new InputWindowElement(itemVec, Pointing.DOWN).withItem(smelted), 20); + scene.idle(20); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.idle(20); + + scene.overlay.showText(80) + .colored(PonderPalette.RED) + .pointAt(itemVec) + .placeNearTarget() + .text("Food items thrown here would be incinerated"); + scene.idle(40); + + // smoking start + + BlockState campfire = Blocks.FIRE.getDefaultState(); + scene.world.hideIndependentSection(blockInFront, Direction.NORTH); + scene.idle(15); + scene.world.setBlock(util.grid.at(3, 1, 0), campfire, false); + scene.world.setBlock(blockPos, campfire, true); + blockInFront = scene.world.showIndependentSection(util.select.position(3, 1, 0), Direction.NORTH); + scene.world.moveSection(blockInFront, util.vector.of(1, 0, 2), 0); + scene.idle(50); + + scene.overlay.showSelectionWithText(util.select.fromTo(blockPos, blockPos.west(2)), 60) + .colored(PonderPalette.BLACK) + .text("Instead, a setup for Smoking using Fire should be used for them"); + scene.idle(80); + + // washing start + + BlockState water = Blocks.WATER.getDefaultState(); + scene.world.hideIndependentSection(blockInFront, Direction.NORTH); + scene.idle(15); + scene.world.setBlock(util.grid.at(3, 1, 0), water, false); + scene.world.setBlock(blockPos, water, true); + blockInFront = scene.world.showIndependentSection(util.select.position(3, 1, 0), Direction.NORTH); + scene.world.moveSection(blockInFront, util.vector.of(1, 0, 2), 0); + scene.idle(20); + + scene.overlay.showSelectionWithText(util.select.fromTo(blockPos, blockPos.west(2)), 60) + .colored(PonderPalette.MEDIUM) + .text("Air Flows passing through water create a Washing Setup"); + scene.idle(70); + + stack = AllItems.CRUSHED_GOLD.asStack(); + ItemStack washed = new ItemStack(Items.GOLD_NUGGET, 16); + + entityLink = scene.world.createItemEntity(util.vector.centerOf(blockPos.west(2) + .up(2)), util.vector.of(0, 0.1, 0), stack); + scene.idle(15); + scene.world.modifyEntity(entityLink, e -> e.setMotion(-0.2f, 0, 0)); + scene.overlay.showControls(new InputWindowElement(itemVec, Pointing.DOWN).withItem(stack), 20); + scene.idle(20); + scene.effects.emitParticles(itemVec.add(0, 0.2f, 0), Emitter.simple(ParticleTypes.SPIT, Vector3d.ZERO), 1, 60); + + scene.overlay.showText(50) + .colored(PonderPalette.WHITE) + .pointAt(itemVec) + .placeNearTarget() + .text("Some interesting new processing can be done with it"); + + scene.idle(60); + scene.world.modifyEntities(ItemEntity.class, ie -> ie.setItem(washed)); + scene.overlay.showControls(new InputWindowElement(itemVec, Pointing.DOWN).withItem(washed), 20); + scene.idle(20); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.idle(20); + + scene.overlay.showText(100) + .colored(PonderPalette.RED) + .pointAt(util.vector.topOf(blockPos.east())) + .placeNearTarget() + .text("The Speed of the Fan does NOT affect the processing speed, only its range"); + scene.world.destroyBlock(util.grid.at(1, 1, 2)); + scene.idle(110); + + ElementLink cogs = scene.world.makeSectionIndependent(util.select.fromTo(6, 1, 2, 6, 0, 3) + .add(util.select.fromTo(4, 0, 2, 5, 0, 2))); + scene.world.modifyKineticSpeed(util.select.position(5, 2, 2), f -> f / 3f); + scene.world.moveSection(cogs, util.vector.of(0, 1, 0), 15); + scene.world.moveSection(blockInFront, util.vector.of(0, 1, 0), 15); + scene.world.destroyBlock(blockPos.east()); + scene.world.showSection(util.select.position(blockPos.east() + .up()), Direction.DOWN); + scene.world.setBlock(blockPos.up(), Blocks.WATER.getDefaultState(), false); + + ItemStack sand = new ItemStack(Items.SAND); + ItemStack clay = new ItemStack(Items.CLAY_BALL); + + scene.idle(20); + BlockPos depos = util.grid.at(3, 4, 2); + ElementLink depot = + scene.world.showIndependentSection(util.select.position(depos), Direction.DOWN); + scene.world.moveSection(depot, util.vector.of(-1, -3, 0), 0); + scene.world.createItemOnBeltLike(depos, Direction.NORTH, sand); + scene.idle(10); + Vector3d depotTop = util.vector.topOf(2, 1, 2) + .add(0, 0.25, 0); + scene.effects.emitParticles(depotTop, Emitter.simple(ParticleTypes.SPIT, Vector3d.ZERO), .5f, 30); + scene.idle(30); + scene.world.modifyTileNBT(util.select.position(depos), DepotTileEntity.class, + nbt -> nbt.put("HeldItem", new TransportedItemStack(clay).serializeNBT())); + scene.effects.emitParticles(depotTop, Emitter.simple(ParticleTypes.SPIT, Vector3d.ZERO), .5f, 30); + scene.overlay.showText(90) + .pointAt(depotTop) + .text("Fan Processing can also be applied to Items on Depots and Belts"); + + scene.idle(100); + scene.world.moveSection(depot, util.vector.of(-1, 0, 0), 15); + scene.idle(15); + ElementLink largeCog = + scene.world.showIndependentSection(util.select.position(1, 2, 4), Direction.UP); + ElementLink belt = + scene.world.showIndependentSection(util.select.fromTo(3, 3, 1, 1, 3, 3), Direction.DOWN); + scene.world.moveSection(largeCog, util.vector.of(-1, -2, 0), 0); + scene.world.moveSection(belt, util.vector.of(-1, -2, 0), 0); + ElementLink transported = + scene.world.createItemOnBelt(util.grid.at(3, 3, 3), Direction.SOUTH, sand); + scene.idle(60); + scene.effects.emitParticles(depotTop, Emitter.simple(ParticleTypes.SPIT, Vector3d.ZERO), .5f, 25); + scene.idle(25); + scene.world.changeBeltItemTo(transported, new ItemStack(Items.CLAY_BALL)); + scene.effects.emitParticles(depotTop, Emitter.simple(ParticleTypes.SPIT, Vector3d.ZERO), .5f, 25); + scene.idle(60); + + scene.world.setKineticSpeed(util.select.position(1, 2, 4) + .add(util.select.fromTo(3, 3, 1, 1, 3, 3)), 0); + + } + + public static void source(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("fan_source", "Generating Rotational Force using Encased Fans"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.layersFrom(2), Direction.DOWN); + scene.idle(10); + BlockPos rightFan = util.grid.at(1, 2, 2); + scene.overlay.showText(80) + .text("Fans facing down into a source of heat can provide Rotational Force") + .placeNearTarget() + .pointAt(util.vector.blockSurface(rightFan, Direction.WEST)); + scene.idle(80); + + for (BlockPos pos : new BlockPos[] { rightFan, util.grid.at(3, 2, 2) }) { + scene.idle(10); + scene.world.toggleRedstonePower(util.select.position(pos.north())); + scene.effects.indicateRedstone(pos.north()); + scene.world.setKineticSpeed(util.select.fromTo(pos, pos.up()), 4); + scene.effects.rotationSpeedIndicator(pos.up()); + } + + scene.overlay.showText(90) + .text("When given a Redstone Signal, the Fans will start providing power") + .colored(PonderPalette.RED) + .placeNearTarget() + .pointAt(util.vector.blockSurface(rightFan, Direction.WEST)); + scene.markAsFinished(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/FunnelScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/FunnelScenes.java new file mode 100644 index 000000000..216539a0b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/FunnelScenes.java @@ -0,0 +1,508 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; +import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; +import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.Blocks; +import net.minecraft.block.LeverBlock; +import net.minecraft.block.RedstoneWireBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraftforge.items.ItemHandlerHelper; + +public class FunnelScenes { + + public static void intro(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("funnel_intro", "Using funnels"); + scene.configureBasePlate(0, 1, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> f / 2f); + + scene.idle(10); + + Selection verticalFunnel = util.select.fromTo(2, -1, 4, 2, 4, 4) + .add(util.select.fromTo(1, 1, 4, 1, 4, 4)); + Selection beltFunnels = util.select.fromTo(1, 2, 2, 3, 2, 2); + Selection beltFunnelEnv = util.select.fromTo(0, 1, 0, 5, 2, 2) + .substract(beltFunnels); + + scene.world.showSection(beltFunnelEnv, Direction.DOWN); + + scene.idle(20); + scene.world.showSection(beltFunnels, Direction.DOWN); + + BlockPos entryBeltPos = util.grid.at(3, 1, 2); + BlockPos exitBeltPos = util.grid.at(1, 1, 2); + ItemStack itemStack = AllBlocks.BRASS_BLOCK.asStack(); + + for (int i = 0; i < 8; i++) { + scene.idle(8); + scene.world.removeItemsFromBelt(exitBeltPos); + scene.world.flapFunnel(exitBeltPos.up(), false); + if (i == 2) + scene.rotateCameraY(70); + if (i < 6) + scene.world.createItemOnBelt(entryBeltPos, Direction.EAST, itemStack); + } + + scene.rotateCameraY(-70); + scene.idle(10); + + Selection outputFunnel = util.select.position(1, 2, 4); + scene.world.setBlocks(outputFunnel, Blocks.AIR.getDefaultState(), false); + scene.world.setBlocks(util.select.fromTo(2, -1, 4, 2, 0, 4), AllBlocks.ANDESITE_CASING.getDefaultState(), true); + ElementLink independentSection = + scene.world.showIndependentSection(verticalFunnel, Direction.UP); + + Vector3d topItemSpawn = util.vector.centerOf(2, 6, 4); + Vector3d sideItemSpawn = util.vector.centerOf(1, 3, 4) + .add(0.15f, -0.45f, 0); + ElementLink lastItemEntity = null; + + for (int i = 0; i < 4; i++) { + if (lastItemEntity != null) + scene.world.modifyEntity(lastItemEntity, Entity::remove); + if (i < 3) + lastItemEntity = scene.world.createItemEntity(topItemSpawn, util.vector.of(0, -0.4, 0), itemStack); + scene.idle(8); + } + + scene.world.moveSection(independentSection, util.vector.of(0, 1, 0), 15); + scene.idle(10); + scene.world.setBlocks(outputFunnel, AllBlocks.ANDESITE_FUNNEL.getDefaultState() + .with(FunnelBlock.FACING, Direction.WEST) + .with(FunnelBlock.EXTRACTING, true), false); + + for (int i = 0; i < 3; i++) { + scene.idle(8); + scene.world.flapFunnel(util.grid.at(1, 2, 4), false); + scene.world.createItemEntity(sideItemSpawn, util.vector.of(-.05, 0, 0), itemStack); + } + + scene.idle(8); + scene.overlay.showText(360) + .text("Funnels are ideal for transferring items from and to inventories.") + .independent(); + scene.markAsFinished(); + } + + public static void directionality(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("funnel_direction", "Direction of Transfer"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> f / 2f); + scene.world.setBlocks(util.select.position(3, 1, 1), AllBlocks.ANDESITE_CASING.getDefaultState(), false); + + BlockPos topFunnel = util.grid.at(3, 3, 2); + Selection topFunnelSelection = util.select.position(topFunnel); + Selection firstShow = util.select.fromTo(3, 1, 2, 3, 2, 2); + scene.idle(5); + + scene.world.showSection(firstShow, Direction.DOWN); + scene.idle(15); + + ItemStack itemStack = AllBlocks.BRASS_BLOCK.asStack(); + Vector3d topCenter = util.vector.centerOf(topFunnel); + Vector3d topSide = util.vector.blockSurface(topFunnel, Direction.EAST); + + InputWindowElement controlsSneak = new InputWindowElement(topCenter, Pointing.DOWN).rightClick() + .whileSneaking(); + + // Placing funnels without sneak + scene.world.showSection(topFunnelSelection, Direction.DOWN); + scene.overlay.showText(80) + .text("Placed normally, it pulls items from the inventory.") + .pointAt(topCenter) + .placeNearTarget(); + scene.idle(45); + + ElementLink itemLink = + scene.world.createItemEntity(topCenter, util.vector.of(0, 4 / 16f, 0), itemStack); + scene.idle(40); + + scene.world.modifyEntity(itemLink, Entity::remove); + scene.world.hideSection(topFunnelSelection, Direction.UP); + scene.idle(20); + + // Placing funnels with sneak + scene.world.modifyBlock(topFunnel, s -> s.with(FunnelBlock.EXTRACTING, false), false); + scene.idle(5); + + scene.world.showSection(topFunnelSelection, Direction.DOWN); + scene.overlay.showControls(controlsSneak, 35); + scene.overlay.showText(80) + .text("Placed while sneaking, it puts items into the inventory.") + .pointAt(topCenter) + .placeNearTarget(); + scene.idle(45); + + itemLink = scene.world.createItemEntity(topCenter.add(0, 3, 0), util.vector.of(0, -0.2, 0), itemStack); + scene.idle(10); + + scene.world.modifyEntity(itemLink, Entity::remove); + scene.idle(45); + + // Wrench interaction + InputWindowElement wrenchControls = new InputWindowElement(topSide, Pointing.RIGHT).rightClick() + .withWrench(); + scene.overlay.showControls(wrenchControls, 40); + scene.idle(10); + scene.world.modifyBlock(topFunnel, s -> s.cycle(FunnelBlock.EXTRACTING), true); + scene.idle(10); + scene.overlay.showText(80) + .text("Using a wrench, the funnel can be flipped after placement.") + .pointAt(topCenter) + .placeNearTarget(); + + itemLink = scene.world.createItemEntity(topCenter, util.vector.of(0, 4 / 16f, 0), itemStack); + scene.idle(30); + + scene.overlay.showControls(wrenchControls, 40); + scene.idle(10); + scene.world.modifyBlock(topFunnel, s -> s.cycle(FunnelBlock.EXTRACTING), true); + scene.idle(10); + scene.world.modifyEntity(itemLink, Entity::remove); + + scene.idle(20); + + // Side funnel + BlockPos sideFunnel = util.grid.at(3, 2, 1); + Selection sideFunnelSelection = util.select.fromTo(sideFunnel.down(), sideFunnel); + Vector3d sideCenter = util.vector.centerOf(sideFunnel); + + scene.world.modifyBlock(sideFunnel, s -> s.cycle(FunnelBlock.EXTRACTING), false); + scene.world.showSection(sideFunnelSelection, Direction.DOWN); + scene.overlay.showText(70) + .text("Same rules will apply for most orientations.") + .pointAt(sideCenter) + .placeNearTarget(); + + scene.idle(20); + + scene.world.flapFunnel(sideFunnel, true); + itemLink = scene.world.createItemEntity(sideCenter.subtract(0, .45, 0), util.vector.of(0, 0, -0.1), itemStack); + scene.idle(60); + scene.world.hideSection(sideFunnelSelection, Direction.UP); + scene.world.hideSection(topFunnelSelection, Direction.UP); + scene.world.modifyEntity(itemLink, Entity::remove); + scene.idle(20); + + // Belt funnel + Selection beltFunnelSetup = util.select.fromTo(0, 1, 0, 2, 2, 5); + Selection gearshiftAndLever = util.select.fromTo(1, 1, 4, 1, 2, 4); + Selection gearshiftedKinetics = util.select.fromTo(1, 1, 2, 2, 1, 4); + Vector3d topOfBeltFunnel = util.vector.topOf(2, 2, 2); + BlockPos beltPos = util.grid.at(2, 1, 2); + BlockPos cogPos = util.grid.at(1, 1, 3); + + scene.world.showSection(beltFunnelSetup, Direction.DOWN); + scene.overlay.showText(140) + .text("Funnels on belts will extract/insert depending on its movement direction.") + .pointAt(topOfBeltFunnel); + + scene.idle(15); + + for (int i = 0; i < 2; i++) { + scene.world.createItemOnBelt(beltPos, Direction.EAST, itemStack); + scene.effects.rotationDirectionIndicator(cogPos); + scene.idle(50); + + scene.world.modifyBlocks(gearshiftAndLever, s -> s.cycle(BlockStateProperties.POWERED), false); + scene.world.modifyKineticSpeed(gearshiftedKinetics, f -> -f); + scene.effects.indicateRedstone(util.grid.at(1, 2, 4)); + scene.effects.rotationDirectionIndicator(cogPos); + scene.idle(35); + + scene.world.removeItemsFromBelt(beltPos); + scene.world.flapFunnel(util.grid.at(2, 2, 2), false); + + if (i == 0) { + scene.idle(50); + scene.world.modifyBlocks(gearshiftAndLever, s -> s.cycle(BlockStateProperties.POWERED), false); + scene.world.modifyKineticSpeed(gearshiftedKinetics, f -> -f); + scene.effects.indicateRedstone(util.grid.at(1, 2, 4)); + } + } + } + + public static void compat(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("funnel_compat", "Funnel compatibility"); + scene.configureBasePlate(0, 0, 5); + + BlockPos sawFunnel = util.grid.at(4, 2, 1); + BlockPos depotFunnel = util.grid.at(2, 2, 2); + BlockPos drainFunnel = util.grid.at(0, 2, 3); + + scene.world.showSection(util.select.layer(0), Direction.UP); + Selection firstShow = util.select.layer(1) + .add(util.select.position(sawFunnel.south())) + .add(util.select.position(depotFunnel.south())) + .add(util.select.position(drainFunnel.south())); + scene.idle(5); + + scene.world.showSection(firstShow, Direction.DOWN); + + scene.idle(8); + scene.overlay.showText(360) + .text("Funnels should also interact nicely with a handful of other components.") + .independent(0); + scene.idle(40); + + scene.world.showSection(util.select.position(sawFunnel), Direction.DOWN); + scene.overlay.showText(40) + .text("Vertical Saws") + .colored(PonderPalette.BLUE) + .placeNearTarget() + .pointAt(util.vector.centerOf(sawFunnel.down())); + scene.idle(8); + scene.world.createItemOnBeltLike(sawFunnel.down(), Direction.SOUTH, new ItemStack(Blocks.OAK_LOG)); + scene.idle(40); + + scene.world.showSection(util.select.position(depotFunnel), Direction.DOWN); + scene.overlay.showText(40) + .text("Depots") + .colored(PonderPalette.BLUE) + .placeNearTarget() + .pointAt(util.vector.centerOf(depotFunnel.down())); + scene.idle(8); + scene.world.createItemOnBeltLike(depotFunnel.down(), Direction.SOUTH, new ItemStack(Items.GOLDEN_PICKAXE)); + scene.idle(40); + + scene.world.showSection(util.select.position(drainFunnel), Direction.DOWN); + scene.overlay.showText(40) + .text("Item Drains") + .colored(PonderPalette.BLUE) + .placeNearTarget() + .pointAt(util.vector.centerOf(drainFunnel.down())); + scene.idle(8); + scene.world.createItemOnBeltLike(drainFunnel.down(), Direction.SOUTH, new ItemStack(Items.WATER_BUCKET)); + scene.idle(40); + + scene.markAsFinished(); + } + + public static void redstone(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("funnel_redstone", "Redstone control"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.layersFrom(1), Direction.DOWN); + + ItemStack itemStack = AllBlocks.BRASS_BLOCK.asStack(); + Vector3d topItemSpawn = util.vector.centerOf(3, 6, 2); + ElementLink lastItemEntity = null; + + BlockPos lever = util.grid.at(1, 2, 2); + BlockPos redstone = util.grid.at(2, 2, 2); + BlockPos funnel = util.grid.at(3, 2, 2); + + AxisAlignedBB redstoneBB = new AxisAlignedBB(funnel).grow(-1 / 16f, -6 / 16f, -1 / 16f) + .offset(0, -5 / 16f, 0); + + for (int i = 0; i < 4; i++) { + if (lastItemEntity != null) + scene.world.modifyEntity(lastItemEntity, Entity::remove); + lastItemEntity = scene.world.createItemEntity(topItemSpawn, util.vector.of(0, -0.2, 0), itemStack); + scene.idle(8); + + if (i == 3) { + scene.world.modifyBlock(lever, s -> s.cycle(LeverBlock.POWERED), false); + scene.world.modifyBlock(redstone, s -> s.with(RedstoneWireBlock.POWER, 15), false); + scene.world.modifyBlock(funnel, s -> s.cycle(FunnelBlock.POWERED), false); + scene.effects.indicateRedstone(lever); + scene.idle(4); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.RED, funnel, redstoneBB, 80); + scene.overlay.showText(80) + .colored(PonderPalette.RED) + .text("Redstone power will prevent any funnel from acting.") + .pointAt(util.vector.blockSurface(funnel, Direction.DOWN)); + } else { + scene.idle(4); + } + } + + } + + public static void brass(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("brass_funnel", "The Brass Funnel"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + BlockPos firstDepot = util.grid.at(3, 1, 1); + BlockPos secondDepot = util.grid.at(1, 1, 1); + Selection depots = util.select.fromTo(firstDepot, secondDepot); + Selection beltAndStuff = util.select.fromTo(0, 1, 2, 4, 1, 2) + .add(util.select.fromTo(0, 1, 3, 0, 2, 5)); + Selection withoutBelt = util.select.layersFrom(1) + .substract(beltAndStuff) + .substract(depots); + + scene.world.showSection(withoutBelt, Direction.DOWN); + ElementLink independentSection = + scene.world.showIndependentSection(depots, Direction.DOWN); + scene.world.moveSection(independentSection, util.vector.of(0, 0, 1), 0); + + BlockPos andesiteFunnel = util.grid.at(3, 2, 2); + BlockPos brassFunnel = util.grid.at(1, 2, 2); + ItemStack itemStack = AllItems.BRASS_INGOT.asStack(); + scene.idle(10); + + scene.overlay.showText(60) + .text("Andesite Funnels can only ever extract single items.") + .pointAt(util.vector.topOf(andesiteFunnel)) + .placeNearTarget(); + scene.idle(10); + scene.world.createItemOnBeltLike(andesiteFunnel.down() + .north(), Direction.SOUTH, itemStack); + scene.world.flapFunnel(andesiteFunnel, true); + scene.idle(60); + + scene.overlay.showText(60) + .text("Brass Funnels can extract up to a full stack.") + .pointAt(util.vector.topOf(brassFunnel)) + .placeNearTarget(); + scene.idle(10); + scene.world.createItemOnBeltLike(brassFunnel.down() + .north(), Direction.SOUTH, ItemHandlerHelper.copyStackWithSize(itemStack, 64)); + scene.world.flapFunnel(brassFunnel, true); + scene.idle(60); + + AxisAlignedBB filterSlot = new AxisAlignedBB(brassFunnel).grow(-.35, -.35, -.35) + .offset(0, 0.2, 0); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.WHITE, filterSlot, filterSlot, 80); + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(brassFunnel), Pointing.DOWN).scroll(), 60); + scene.idle(10); + scene.overlay.showText(80) + .text("Scrolling on the filter slot allows for precise control over the extracted stack size.") + .pointAt(filterSlot.getCenter()) + .placeNearTarget(); + scene.idle(90); + + // belt + scene.world.hideIndependentSection(independentSection, Direction.NORTH); + scene.world.hideSection(util.select.position(brassFunnel), Direction.UP); + scene.idle(20); + + scene.world.modifyBlock(brassFunnel, s -> s.cycle(BeltFunnelBlock.SHAPE), false); + scene.world.showSection(util.select.position(brassFunnel), Direction.DOWN); + scene.world.showSection(beltAndStuff, Direction.SOUTH); + scene.idle(10); + + ItemStack dirt = new ItemStack(Items.DIRT); + ItemStack gravel = new ItemStack(Items.GRAVEL); + ItemStack emerald = new ItemStack(Items.EMERALD); + + for (int i = 0; i < 14; i++) { + + if (i < 12) + scene.world.createItemOnBelt(andesiteFunnel.down(), Direction.SOUTH, + i % 3 == 0 ? dirt : i % 3 == 1 ? gravel : emerald); + scene.idle(10); + + if (i > 0 && (i < 3 || i % 3 == 0)) { + scene.world.removeItemsFromBelt(brassFunnel.down()); + scene.world.flapFunnel(brassFunnel, false); + } + + scene.world.modifyEntities(ItemEntity.class, e -> { + if (e.getY() < 1) + e.remove(); + }); + + if (i == 2) { + scene.overlay.chaseBoundingBoxOutline(PonderPalette.WHITE, filterSlot, filterSlot, 80); + scene.overlay + .showControls(new InputWindowElement(util.vector.topOf(brassFunnel), Pointing.DOWN).rightClick() + .withItem(emerald), 60); + scene.idle(10); + scene.overlay.showText(80) + .text("Using items on the filter slot will restrict the funnel to only transfer matching stacks.") + .pointAt(filterSlot.getCenter()) + .placeNearTarget(); + scene.world.setFilterData(util.select.position(brassFunnel), FunnelTileEntity.class, emerald); + } else + scene.idle(10); + + if (i == 8) + scene.markAsFinished(); + } + } + + public static void transposer(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("funnel_transfer", "Direct transfer"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + BlockPos funnelPos = util.grid.at(2, 2, 2); + Selection funnelSelect = util.select.position(funnelPos); + + ElementLink rightChest = + scene.world.showIndependentSection(util.select.position(0, 2, 2), Direction.DOWN); + ElementLink leftChest = + scene.world.showIndependentSection(util.select.position(4, 2, 2), Direction.DOWN); + scene.world.moveSection(rightChest, util.vector.of(2, 1, 0), 0); + scene.world.moveSection(leftChest, util.vector.of(-2, -1, 0), 0); + scene.idle(5); + + scene.world.showSection(funnelSelect, Direction.DOWN); + scene.idle(20); + + scene.overlay.showSelectionWithText(funnelSelect, 40) + .colored(PonderPalette.RED) + .text("Funnels cannot ever transfer between closed inventories directly.") + .placeNearTarget(); + scene.idle(50); + + scene.world.hideSection(funnelSelect, Direction.SOUTH); + scene.idle(20); + + scene.world.setBlocks(funnelSelect, AllBlocks.CHUTE.getDefaultState(), false); + scene.world.showSection(funnelSelect, Direction.NORTH); + scene.idle(10); + + scene.overlay.showText(40) + .colored(PonderPalette.GREEN) + .text("Chutes or Smart chutes might be more suitable for such purposes.") + .pointAt(util.vector.centerOf(funnelPos)) + .placeNearTarget(); + scene.idle(50); + + scene.world.hideSection(funnelSelect, Direction.UP); + scene.world.hideIndependentSection(leftChest, Direction.UP); + scene.world.hideIndependentSection(rightChest, Direction.UP); + scene.idle(20); + + Selection belt = util.select.layer(1); + scene.world.setBlocks(funnelSelect, Blocks.AIR.getDefaultState(), false); + scene.world.showSection(belt, Direction.DOWN); + scene.world.showSection(util.select.fromTo(0, 2, 2, 4, 2, 2), Direction.DOWN); + scene.overlay.showText(120) + .colored(PonderPalette.GREEN) + .text("Same applies for horizontal movement.\nA mechanical belt should help here.") + .pointAt(util.vector.topOf(1, 2, 2)) + .placeNearTarget(); + + scene.markAsFinished(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/GantryScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/GantryScenes.java new file mode 100644 index 000000000..d1642ccfd --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/GantryScenes.java @@ -0,0 +1,305 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Iterate; + +import net.minecraft.block.RedstoneWireBlock; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class GantryScenes { + + public static void introForPinion(SceneBuilder scene, SceneBuildingUtil util) { + intro(scene, util, true); + } + + public static void introForShaft(SceneBuilder scene, SceneBuildingUtil util) { + intro(scene, util, false); + } + + private static void intro(SceneBuilder scene, SceneBuildingUtil util, boolean pinion) { + String id = "gantry_" + (pinion ? "carriage" : "shaft"); + String title = "Using Gantry " + (pinion ? "Carriages" : "Shafts"); + scene.title(id, title); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -2 * f); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(10); + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(10); + ElementLink gantry = + scene.world.showIndependentSection(util.select.layer(2), Direction.DOWN); + scene.idle(10); + + BlockPos centralShaft = util.grid.at(2, 1, 2); + + scene.world.moveSection(gantry, util.vector.of(-4, 0, 0), 60); + + String text = pinion ? "Gantry Carriages can mount to and slide along a Gantry Shaft." + : "Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them."; + + scene.overlay.showText(80) + .attachKeyFrame() + .text(text) + .pointAt(util.vector.centerOf(centralShaft)); + scene.idle(80); + + scene.world.hideIndependentSection(gantry, Direction.UP); + scene.idle(10); + gantry = scene.world.showIndependentSection(util.select.layer(2), Direction.DOWN); + Vector3d gantryTop = util.vector.topOf(4, 2, 2); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> 0f); + scene.overlay.showText(40) + .attachKeyFrame() + .text("Gantry setups can move attached Blocks.") + .pointAt(gantryTop) + .placeNearTarget(); + scene.idle(30); + + Selection planks = util.select.position(5, 3, 1); + + scene.world.showSectionAndMerge(util.select.layersFrom(3) + .substract(planks), Direction.DOWN, gantry); + scene.idle(10); + scene.world.showSectionAndMerge(planks, Direction.SOUTH, gantry); + scene.idle(10); + scene.effects.superGlue(util.grid.at(5, 3, 1), Direction.SOUTH, true); + + scene.idle(20); + scene.overlay.showText(80) + .attachKeyFrame() + .sharedText("movement_anchors") + .pointAt(gantryTop) + .placeNearTarget(); + scene.idle(80); + + scene.world.modifyKineticSpeed(util.select.layer(0), f -> 32f); + scene.world.modifyKineticSpeed(util.select.layer(1), f -> -64f); + + scene.world.moveSection(gantry, util.vector.of(-4, 0, 0), 60); + scene.idle(20); + scene.markAsFinished(); + } + + public static void redstone(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("gantry_redstone", "Gantry Power Propagation"); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + + Selection leverRedstone = util.select.fromTo(3, 1, 0, 3, 1, 1); + Selection shaft = util.select.fromTo(0, 1, 2, 4, 1, 2); + Selection shaftAndCog = util.select.fromTo(0, 1, 2, 5, 1, 2); + + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0) + .add(leverRedstone), Direction.UP); + + scene.idle(10); + scene.world.showSection(shaftAndCog, Direction.DOWN); + scene.idle(10); + + BlockPos gantryPos = util.grid.at(4, 2, 2); + ElementLink gantry = + scene.world.showIndependentSection(util.select.position(gantryPos), Direction.DOWN); + scene.idle(15); + scene.world.moveSection(gantry, util.vector.of(-3, 0, 0), 40); + scene.idle(40); + + scene.world.toggleRedstonePower(shaft); + scene.world.toggleRedstonePower(util.select.position(3, 1, 0)); + scene.world.toggleRedstonePower(util.select.position(3, 1, 1)); + scene.effects.indicateRedstone(util.grid.at(3, 1, 0)); + scene.world.modifyKineticSpeed(util.select.position(gantryPos), f -> 32f); + scene.idle(40); + + BlockPos cogPos = util.grid.at(1, 2, 1); + scene.overlay.showText(60) + .attachKeyFrame() + .colored(PonderPalette.RED) + .pointAt(util.vector.centerOf(cogPos.down() + .south())) + .text("Redstone-powered gantry shafts stop moving their carriages") + .placeNearTarget(); + scene.idle(70); + + Selection cogSelection = util.select.position(cogPos); + scene.world.showSection(cogSelection, Direction.SOUTH); + scene.world.modifyKineticSpeed(cogSelection, f -> 32f); + scene.overlay.showText(180) + .colored(PonderPalette.GREEN) + .pointAt(util.vector.blockSurface(cogPos, Direction.NORTH)) + .text("Instead, its rotational force is relayed to the carriages' output shaft") + .placeNearTarget(); + scene.idle(10); + + scene.effects.rotationSpeedIndicator(cogPos); + scene.markAsFinished(); + } + + public static void direction(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("gantry_direction", "Gantry Movement Direction"); + scene.configureBasePlate(0, 0, 5); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(10); + + Selection shaftAndGearshiftAndLever = util.select.fromTo(0, 1, 2, 5, 2, 2); + Selection shafts = util.select.fromTo(0, 1, 2, 3, 1, 2); + + scene.world.showSection(shaftAndGearshiftAndLever, Direction.DOWN); + scene.overlay.showText(60) + .text("Gantry Shafts can have opposite orientations") + .pointAt(util.vector.of(2, 1.5, 2.5)) + .placeNearTarget(); + scene.idle(60); + + ElementLink gantry1 = + scene.world.showIndependentSection(util.select.position(0, 1, 3), Direction.NORTH); + ElementLink gantry2 = + scene.world.showIndependentSection(util.select.position(3, 1, 3), Direction.NORTH); + scene.idle(10); + + scene.world.moveSection(gantry1, util.vector.of(1, 0, 0), 20); + scene.world.moveSection(gantry2, util.vector.of(-1, 0, 0), 20); + + scene.overlay.showText(80) + .attachKeyFrame() + .text("The movement direction of carriages depend on their shafts' orientation") + .pointAt(util.vector.topOf(1, 1, 3)) + .placeNearTarget(); + scene.idle(80); + + BlockPos lastShaft = util.grid.at(0, 1, 2); + boolean flip = true; + + for (int i = 0; i < 3; i++) { + scene.world.modifyBlocks(util.select.fromTo(4, 1, 2, 4, 2, 2), s -> s.cycle(BlockStateProperties.POWERED), + false); + scene.effects.indicateRedstone(util.grid.at(4, 2, 2)); + scene.world.moveSection(gantry1, util.vector.of(flip ? -1 : 1, 0, 0), 20); + scene.world.moveSection(gantry2, util.vector.of(flip ? 1 : -1, 0, 0), 20); + scene.world.modifyKineticSpeed(shafts, f -> -f); + scene.effects.rotationDirectionIndicator(lastShaft.east(flip ? 1 : 0)); + scene.idle(20); + + if (i == 0) { + scene.overlay.showText(80) + .attachKeyFrame() + .text("...as well as the rotation direction of the shaft") + .pointAt(util.vector.blockSurface(lastShaft, Direction.WEST)) + .placeNearTarget(); + } + + scene.idle(30); + flip = !flip; + } + + Selection kinetics = util.select.fromTo(0, 2, 3, 3, 3, 3); + Selection gears1 = util.select.fromTo(0, 1, 3, 0, 3, 3); + Selection gears2 = util.select.fromTo(3, 1, 3, 3, 3, 3); + + scene.world.showSection(kinetics, Direction.DOWN); + scene.world.showSection(util.select.fromTo(0, 1, 0, 4, 1, 1), Direction.SOUTH); + scene.idle(20); + + BlockPos leverPos = util.grid.at(4, 1, 0); + scene.world.modifyBlocks(util.select.fromTo(1, 1, 0, 3, 1, 1), + s -> s.contains(RedstoneWireBlock.POWER) ? s.with(RedstoneWireBlock.POWER, 15) : s, false); + scene.world.toggleRedstonePower(util.select.position(leverPos)); + scene.world.toggleRedstonePower(shafts); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(gears1, f -> -32f); + scene.world.modifyKineticSpeed(gears2, f -> 32f); + + scene.idle(20); + scene.overlay.showText(120) + .attachKeyFrame() + .text("Same rules apply for the propagated rotation") + .pointAt(util.vector.topOf(0, 3, 3)) + .placeNearTarget(); + scene.idle(20); + + for (boolean flip2 : Iterate.trueAndFalse) { + scene.effects.rotationDirectionIndicator(util.grid.at(0, 3, 3)); + scene.effects.rotationDirectionIndicator(util.grid.at(3, 3, 3)); + + scene.idle(60); + scene.world.modifyBlocks(util.select.fromTo(4, 1, 2, 4, 2, 2), s -> s.cycle(BlockStateProperties.POWERED), + false); + scene.effects.indicateRedstone(util.grid.at(4, 2, 2)); + scene.world.modifyKineticSpeed(gears1, f -> -f); + scene.world.modifyKineticSpeed(gears2, f -> -f); + + if (!flip2) { + scene.effects.rotationDirectionIndicator(util.grid.at(0, 3, 3)); + scene.effects.rotationDirectionIndicator(util.grid.at(3, 3, 3)); + scene.markAsFinished(); + } + } + + } + + public static void subgantry(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("gantry_cascaded", "Cascaded Gantries"); + scene.configureBasePlate(0, 0, 5); + scene.setSceneOffsetY(-1); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -2 * f); + scene.world.showSection(util.select.layer(0) + .add(util.select.column(5, 3)) + .add(util.select.fromTo(2, 1, 3, 4, 1, 3)), Direction.UP); + scene.idle(10); + + BlockPos gantryPos = util.grid.at(5, 1, 2); + BlockPos gantryPos2 = util.grid.at(3, 2, 2); + ElementLink gantry = + scene.world.showIndependentSection(util.select.position(gantryPos), Direction.SOUTH); + scene.idle(5); + + scene.world.showSectionAndMerge(util.select.fromTo(0, 1, 2, 4, 1, 2), Direction.EAST, gantry); + scene.idle(15); + + scene.world.moveSection(gantry, util.vector.of(0, 2, 0), 40); + scene.overlay.showText(60) + .attachKeyFrame() + .text("Gantry shafts attach to a carriage without the need of super glue") + .independent(20); + scene.idle(40); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.moveSection(gantry, util.vector.of(0, -2, 0), 40); + scene.idle(40); + + ElementLink secondGantry = + scene.world.showIndependentSection(util.select.position(gantryPos2), Direction.DOWN); + scene.idle(15); + scene.overlay.showText(60) + .attachKeyFrame() + .text("Same applies for carriages on moved Gantry Shafts") + .independent(20); + scene.idle(15); + + scene.world.moveSection(gantry, util.vector.of(0, 2, 0), 40); + scene.world.moveSection(secondGantry, util.vector.of(0, 2, 0), 40); + + scene.idle(40); + BlockPos leverPos = util.grid.at(2, 1, 3); + scene.world.toggleRedstonePower(util.select.position(leverPos)); + scene.world.toggleRedstonePower(util.select.fromTo(3, 1, 3, 4, 1, 3)); + scene.world.toggleRedstonePower(util.select.fromTo(5, 1, 3, 5, 4, 3)); + scene.world.modifyKineticSpeed(util.select.fromTo(0, 1, 2, 5, 1, 2), f -> -32f); + scene.effects.indicateRedstone(leverPos); + scene.world.moveSection(secondGantry, util.vector.of(-3, 0, 0), 60); + + scene.idle(20); + scene.overlay.showText(120) + .text("Thus, a gantry system can be cascaded to cover multiple axes of movement") + .independent(20); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/KineticsScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/KineticsScenes.java new file mode 100644 index 000000000..1f0246f2e --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/KineticsScenes.java @@ -0,0 +1,1013 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.components.crank.ValveHandleBlock; +import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheelBlock; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftBlock; +import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; +import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; +import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock; +import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.ponder.instructions.EmitParticlesInstruction.Emitter; +import com.simibubi.create.foundation.utility.Pointing; +import com.tterrag.registrate.util.entry.BlockEntry; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.FurnaceBlock; +import net.minecraft.block.RedstoneWireBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector3i; + +public class KineticsScenes { + + public static void shaftAsRelay(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("shaft", "Relaying rotational force using Shafts"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos gaugePos = util.grid.at(0, 1, 2); + Selection gauge = util.select.position(gaugePos); + scene.world.showSection(gauge, Direction.UP); + scene.world.setKineticSpeed(gauge, 0); + + scene.idle(5); + scene.world.showSection(util.select.position(5, 1, 2), Direction.DOWN); + scene.idle(10); + + for (int i = 4; i >= 1; i--) { + if (i == 2) + scene.rotateCameraY(70); + scene.idle(5); + scene.world.showSection(util.select.position(i, 1, 2), Direction.DOWN); + } + + scene.world.setKineticSpeed(gauge, 64); + scene.effects.indicateSuccess(gaugePos); + scene.idle(10); + scene.overlay.showText(1000) + .text("Shafts will relay rotation in a straight line.") + .pointAt(util.vector.of(3, 1.5, 2.5)); + + scene.idle(20); + scene.markAsFinished(); + } + + public static void shaftsCanBeEncased(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("shaft_casing", "Encasing Shafts"); + scene.configureBasePlate(0, 0, 5); + scene.showBasePlate(); + + Selection shaft = util.select.cuboid(new BlockPos(0, 1, 2), new Vector3i(5, 0, 2)); + Selection andesite = util.select.position(3, 1, 2); + Selection brass = util.select.position(1, 1, 2); + + scene.world.showSection(shaft, Direction.DOWN); + scene.idle(20); + + BlockEntry andesiteEncased = AllBlocks.ANDESITE_ENCASED_SHAFT; + ItemStack andesiteCasingItem = AllBlocks.ANDESITE_CASING.asStack(); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(3, 1, 2), Pointing.DOWN).rightClick() + .withItem(andesiteCasingItem), 60); + scene.idle(7); + scene.world.setBlocks(andesite, andesiteEncased.getDefaultState() + .with(EncasedShaftBlock.AXIS, Axis.X), true); + scene.world.setKineticSpeed(shaft, 32); + scene.idle(10); + + BlockEntry brassEncased = AllBlocks.BRASS_ENCASED_SHAFT; + ItemStack brassCasingItem = AllBlocks.BRASS_CASING.asStack(); + + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(1, 0, 2), Pointing.UP).rightClick() + .withItem(brassCasingItem), 60); + scene.idle(7); + scene.world.setBlocks(brass, brassEncased.getDefaultState() + .with(EncasedShaftBlock.AXIS, Axis.X), true); + scene.world.setKineticSpeed(shaft, 32); + + scene.idle(10); + scene.overlay.showText(1000) + .text("Brass or Andesite Casing can be used to decorate Shafts") + .pointAt(util.vector.topOf(1, 1, 2)); + } + + public static void cogAsRelay(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("cogwheel", "Relaying rotational force using Cogwheels"); + scene.configureBasePlate(0, 0, 5); + BlockPos gauge = util.grid.at(4, 1, 1); + Selection gaugeSelect = util.select.position(gauge); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.world.showSection(gaugeSelect, Direction.UP); + scene.world.setKineticSpeed(gaugeSelect, 0); + scene.idle(5); + scene.world.showSection(util.select.fromTo(1, 1, 3, 1, 1, 5), Direction.DOWN); + scene.idle(10); + + for (int i = 1; i <= 4; i++) { + scene.idle(5); + if (i == 2) + scene.world.showSection(util.select.position(0, 1, 2), Direction.DOWN); + scene.world.showSection(util.select.position(i, 1, 2), Direction.DOWN); + } + + scene.world.setKineticSpeed(gaugeSelect, 64); + scene.effects.indicateSuccess(gauge); + scene.idle(10); + scene.overlay.showText(60) + .text("Cogwheels will relay rotation to other adjacent cogwheels") + .pointAt(util.vector.blockSurface(util.grid.at(0, 1, 2), Direction.EAST)); + + scene.idle(60); + scene.world.showSection(util.select.fromTo(1, 1, 1, 2, 1, 1), Direction.SOUTH); + scene.idle(10); + scene.effects.rotationDirectionIndicator(util.grid.at(1, 1, 1)); + scene.effects.rotationDirectionIndicator(util.grid.at(2, 1, 1)); + scene.idle(20); + scene.overlay.showText(100) + .text("Neighbouring shafts connected like this will rotate in opposite directions") + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(1, 1, 2), Direction.NORTH)); + + } + + public static void largeCogAsRelay(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("large_cogwheel", "Relaying rotational force using Large Cogwheels"); + scene.configureBasePlate(1, 1, 5); + scene.world.setBlock(util.grid.at(4, 2, 3), AllBlocks.LARGE_COGWHEEL.getDefaultState() + .with(CogWheelBlock.AXIS, Axis.X), false); + + scene.showBasePlate(); + scene.idle(5); + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(5); + scene.world.showSection(util.select.position(3, 2, 4), Direction.NORTH); + + for (int i = 3; i >= 1; i--) { + scene.idle(5); + if (i == 3) + scene.world.showSection(util.select.position(3, 2, 5), Direction.DOWN); + scene.world.showSection(util.select.position(3, 2, i), Direction.DOWN); + } + + scene.overlay.showText(70) + .text("Large cogwheels can connect to each other at right angles") + .placeNearTarget() + .pointAt(util.vector.centerOf(3, 1, 4)); + scene.idle(70); + scene.world.hideSection(util.select.fromTo(3, 2, 1, 3, 2, 5), Direction.SOUTH); + + scene.idle(15); + scene.world.modifyBlock(util.grid.at(3, 2, 3), s -> s.with(ShaftBlock.AXIS, Axis.X), false); + scene.world.setKineticSpeed(util.select.fromTo(1, 2, 3, 5, 2, 3), 16); + scene.world.showSection(util.select.position(4, 2, 3), Direction.WEST); + + for (int i = 3; i >= 1; i--) { + scene.idle(5); + if (i == 3) + scene.world.showSection(util.select.position(5, 2, 3), Direction.DOWN); + scene.world.showSection(util.select.position(i, 2, 3), Direction.DOWN); + } + + scene.idle(5); + scene.overlay.showText(90) + .text("It will help relaying conveyed speed to other axes of rotation") + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(1, 2, 3), Direction.WEST)); + scene.effects.rotationSpeedIndicator(util.grid.at(3, 1, 3)); + scene.effects.rotationSpeedIndicator(util.grid.at(4, 2, 3)); + + } + + public static void cogsSpeedUp(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("cog_speedup", "Gearshifting with Cogs"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(5, 1, 2, 4, 1, 2), Direction.DOWN); + scene.idle(10); + + BlockPos lowerCog = util.grid.at(3, 1, 2); + BlockPos upperCog = util.grid.at(3, 2, 3); + BlockState largeCogState = AllBlocks.LARGE_COGWHEEL.getDefaultState() + .with(CogWheelBlock.AXIS, Axis.X); + BlockState smallCogState = AllBlocks.COGWHEEL.getDefaultState() + .with(CogWheelBlock.AXIS, Axis.X); + + scene.world.setBlock(lowerCog, largeCogState, false); + scene.world.setBlock(upperCog, smallCogState, false); + BlockPos upperShaftEnd = upperCog.west(3); + BlockPos lowerShaftEnd = lowerCog.west(3); + + scene.world.setKineticSpeed(util.select.fromTo(upperCog, upperShaftEnd), -64); + scene.world.showSection(util.select.fromTo(lowerCog, upperCog), Direction.EAST); + scene.overlay.showText(60) + .text("Large and Small cogs can be connected diagonally") + .placeNearTarget() + .pointAt(util.vector.blockSurface(upperCog, Direction.WEST)); + scene.idle(80); + + Selection gaugesSelect = util.select.fromTo(0, 1, 2, 2, 2, 3); + scene.world.showSection(gaugesSelect, Direction.DOWN); + scene.overlay.showText(60) + .text("Shifting from large to small cogs, the conveyed speed will be doubled") + .colored(PonderPalette.GREEN) + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(1, 2, 3), Direction.NORTH)); + scene.idle(10); + scene.effects.rotationSpeedIndicator(upperCog); + scene.idle(60); + + scene.overlay.showText(30) + .sharedText("rpm32") + .colored(PonderPalette.FAST) + .placeNearTarget() + .pointAt(util.vector.blockSurface(upperShaftEnd, Direction.WEST)); + scene.idle(5); + scene.overlay.showText(30) + .sharedText("rpm16") + .colored(PonderPalette.MEDIUM) + .placeNearTarget() + .pointAt(util.vector.blockSurface(lowerShaftEnd, Direction.WEST)); + scene.idle(45); + + scene.world.setKineticSpeed(util.select.fromTo(lowerCog, upperShaftEnd), 0); + ElementLink cogs = + scene.world.makeSectionIndependent(util.select.fromTo(lowerCog, upperCog)); + scene.world.moveSection(cogs, util.vector.of(0, 1, 0), 5); + scene.idle(5); + scene.world.rotateSection(cogs, 180, 0, 0, 10); + scene.idle(10); + scene.world.setBlock(lowerCog, smallCogState, false); + scene.world.setBlock(upperCog, largeCogState, false); + scene.world.rotateSection(cogs, 180, 0, 0, 0); + scene.world.moveSection(cogs, util.vector.of(0, -1, 0), 5); + scene.idle(5); + + scene.world.setKineticSpeed(util.select.fromTo(lowerCog, lowerShaftEnd), 32); + scene.world.setKineticSpeed(util.select.fromTo(upperCog, upperShaftEnd), -16); + + scene.overlay.showText(80) + .text("Shifting the opposite way, the conveyed speed will be halved") + .colored(PonderPalette.RED) + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(1, 2, 3), Direction.NORTH)); + scene.idle(10); + scene.effects.rotationSpeedIndicator(upperCog); + scene.idle(80); + + scene.overlay.showText(60) + .sharedText("rpm8") + .colored(PonderPalette.SLOW) + .placeNearTarget() + .pointAt(util.vector.blockSurface(upperShaftEnd, Direction.WEST)); + scene.idle(5); + scene.overlay.showText(60) + .sharedText("rpm16") + .colored(PonderPalette.MEDIUM) + .placeNearTarget() + .pointAt(util.vector.blockSurface(lowerShaftEnd, Direction.WEST)); + scene.idle(40); + } + + public static void gearbox(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("gearbox", "Relaying rotational force using Gearboxes"); + scene.configureBasePlate(1, 1, 5); + scene.setSceneOffsetY(-1); + + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.world.showSection(util.select.fromTo(4, 1, 6, 3, 2, 5), Direction.UP); + scene.idle(10); + + BlockPos largeCogBack = util.grid.at(3, 2, 4); + BlockPos largeCogLeft = util.grid.at(4, 2, 3); + BlockPos largeCogFront = util.grid.at(3, 2, 2); + BlockPos largeCogRight = util.grid.at(2, 2, 3); + + scene.world.showSection(util.select.position(largeCogBack), Direction.SOUTH); + scene.idle(5); + scene.world.showSection(util.select.position(largeCogLeft), Direction.WEST); + scene.world.showSection(util.select.position(largeCogLeft.east()), Direction.WEST); + scene.world.showSection(util.select.position(largeCogRight), Direction.EAST); + scene.world.showSection(util.select.position(largeCogRight.west()), Direction.EAST); + scene.idle(5); + scene.world.showSection(util.select.position(largeCogFront), Direction.SOUTH); + scene.world.showSection(util.select.position(largeCogFront.north()), Direction.SOUTH); + + scene.idle(10); + + scene.overlay.showText(80) + .colored(PonderPalette.RED) + .pointAt(util.vector.blockSurface(largeCogRight.west(), Direction.WEST)) + .placeNearTarget() + .text("Jumping between axes of rotation can get bulky quickly"); + scene.idle(80); + Selection gearbox = util.select.position(3, 2, 3); + scene.world.hideSection(util.select.fromTo(4, 2, 2, 2, 2, 4) + .substract(gearbox), Direction.UP); + scene.idle(20); + + BlockState defaultState = AllBlocks.SHAFT.getDefaultState(); + BlockState cogState = AllBlocks.COGWHEEL.getDefaultState(); + scene.world.setBlock(largeCogBack, defaultState.with(CogWheelBlock.AXIS, Axis.Z), false); + scene.world.setBlock(largeCogFront, defaultState.with(CogWheelBlock.AXIS, Axis.Z), false); + scene.world.setBlock(largeCogRight, defaultState.with(CogWheelBlock.AXIS, Axis.X), false); + scene.world.setBlock(largeCogLeft, defaultState.with(CogWheelBlock.AXIS, Axis.X), false); + scene.world.showSection(util.select.fromTo(4, 2, 2, 2, 2, 4), Direction.DOWN); + + scene.idle(20); + scene.overlay.showText(80) + .colored(PonderPalette.GREEN) + .pointAt(util.vector.topOf(3, 2, 3)) + .placeNearTarget() + .text("A gearbox is the more compact equivalent of this setup"); + + scene.idle(90); + scene.world.setBlock(largeCogFront.north(), cogState.with(CogWheelBlock.AXIS, Axis.Z), true); + scene.world.setBlock(largeCogRight.west(), cogState.with(CogWheelBlock.AXIS, Axis.X), true); + scene.idle(10); + scene.effects.rotationDirectionIndicator(largeCogFront.north()); + scene.effects.rotationDirectionIndicator(largeCogRight.west()); + scene.idle(15); + scene.overlay.showText(60) + .pointAt(util.vector.of(3, 2.5, 3)) + .placeNearTarget() + .text("Shafts around corners rotate in mirrored directions"); + + scene.idle(70); + + scene.world.hideSection(util.select.fromTo(1, 2, 3, 2, 2, 3), Direction.WEST); + scene.world.hideSection(util.select.fromTo(4, 2, 3, 5, 2, 3), Direction.EAST); + scene.world.setBlock(largeCogBack.south(), cogState.with(CogWheelBlock.AXIS, Axis.Z), true); + scene.idle(10); + + scene.effects.rotationDirectionIndicator(largeCogFront.north()); + scene.effects.rotationDirectionIndicator(largeCogBack.south()); + scene.idle(15); + scene.overlay.showText(60) + .pointAt(util.vector.centerOf(3, 2, 5)) + .placeNearTarget() + .text("Straight connections will be reversed"); + + } + + public static void clutch(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("clutch", "Controlling rotational force using a Clutch"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + BlockPos leverPos = util.grid.at(3, 1, 0); + scene.world.showSection(util.select.fromTo(leverPos, leverPos.south()), Direction.UP); + + BlockPos gaugePos = util.grid.at(0, 1, 2); + Selection gauge = util.select.position(gaugePos); + scene.world.showSection(gauge, Direction.UP); + scene.world.setKineticSpeed(gauge, 0); + + scene.idle(5); + scene.world.showSection(util.select.position(5, 1, 2), Direction.DOWN); + scene.idle(10); + + for (int i = 4; i >= 1; i--) { + scene.idle(5); + scene.world.showSection(util.select.position(i, 1, 2), Direction.DOWN); + } + + BlockPos clutch = util.grid.at(3, 1, 2); + + scene.world.setKineticSpeed(gauge, 32); + scene.effects.indicateSuccess(gaugePos); + scene.idle(10); + scene.overlay.showText(50) + .text("Clutches will relay rotation in a straight line") + .placeNearTarget() + .pointAt(util.vector.topOf(clutch)); + + scene.idle(60); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.south(2))); + scene.effects.indicateRedstone(leverPos); + scene.world.setKineticSpeed(util.select.fromTo(0, 1, 2, 2, 1, 2), 0); + scene.idle(10); + + scene.idle(10); + scene.overlay.showText(50) + .colored(PonderPalette.RED) + .text("When powered by Redstone, it breaks the connection") + .placeNearTarget() + .pointAt(util.vector.topOf(clutch)); + + scene.idle(70); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.south(2))); + scene.effects.indicateRedstone(leverPos); + scene.world.setKineticSpeed(util.select.fromTo(0, 1, 2, 2, 1, 2), 32); + scene.effects.indicateSuccess(gaugePos); + } + + public static void gearshift(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("gearshift", "Controlling rotational force using a Gearshift"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + BlockPos leverPos = util.grid.at(3, 1, 0); + scene.world.showSection(util.select.fromTo(leverPos, leverPos.south()), Direction.UP); + + scene.idle(5); + scene.world.showSection(util.select.position(5, 1, 2), Direction.DOWN); + scene.idle(10); + + for (int i = 4; i >= 1; i--) { + scene.idle(5); + scene.world.showSection(util.select.position(i, 1, 2), Direction.DOWN); + } + + BlockPos gearshift = util.grid.at(3, 1, 2); + scene.idle(10); + scene.overlay.showText(50) + .placeNearTarget() + .text("Gearshifts will relay rotation in a straight line") + .pointAt(util.vector.topOf(gearshift)); + + scene.idle(60); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.south(2))); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(util.select.fromTo(0, 1, 2, 2, 2, 2), f -> -f); + scene.effects.rotationDirectionIndicator(gearshift.east(2)); + scene.effects.rotationDirectionIndicator(gearshift.west(2)); + scene.idle(30); + + scene.overlay.showText(50) + .colored(PonderPalette.RED) + .placeNearTarget() + .text("When powered by Redstone, it reverses the transmission") + .pointAt(util.vector.topOf(gearshift)); + + for (int i = 0; i < 3; i++) { + scene.idle(60); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.south(2))); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(util.select.fromTo(0, 1, 2, 2, 2, 2), f -> -f); + scene.effects.rotationDirectionIndicator(gearshift.east(2)); + scene.effects.rotationDirectionIndicator(gearshift.west(2)); + } + } + + public static void creativeMotor(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("creative_motor", "Generating Rotational Force using Creative Motors"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos motor = util.grid.at(3, 1, 2); + + for (int i = 0; i < 3; i++) { + scene.idle(5); + scene.world.showSection(util.select.position(1 + i, 1, 2), Direction.DOWN); + } + + scene.idle(10); + scene.effects.rotationSpeedIndicator(motor); + scene.overlay.showText(50) + .text("Creative motors are a compact and configurable source of Rotational Force") + .placeNearTarget() + .pointAt(util.vector.topOf(motor)); + scene.idle(50); + + scene.rotateCameraY(90); + scene.idle(20); + + Vector3d blockSurface = util.vector.blockSurface(motor, Direction.EAST); + AxisAlignedBB point = new AxisAlignedBB(blockSurface, blockSurface); + AxisAlignedBB expanded = point.grow(1 / 16f, 1 / 5f, 1 / 5f); + + scene.overlay.chaseBoundingBoxOutline(PonderPalette.WHITE, blockSurface, point, 1); + scene.idle(1); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.WHITE, blockSurface, expanded, 60); + scene.overlay.showControls(new InputWindowElement(blockSurface, Pointing.DOWN).scroll(), 60); + scene.idle(20); + + scene.overlay.showText(50) + .text("Scrolling on the back panel changes the RPM of the motors' rotational output") + .placeNearTarget() + .pointAt(blockSurface); + scene.idle(10); + scene.world.modifyKineticSpeed(util.select.fromTo(1, 1, 2, 3, 1, 2), f -> 4 * f); + scene.idle(50); + + scene.effects.rotationSpeedIndicator(motor); + scene.rotateCameraY(-90); + } + + public static void waterWheel(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("water_wheel", "Generating Rotational Force using Water Wheels"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(4, 1, 1, 4, 3, 3) + .add(util.select.fromTo(3, 1, 3, 3, 2, 3)), Direction.DOWN); + scene.world.setKineticSpeed(util.select.everywhere(), 0); + + BlockPos gaugePos = util.grid.at(0, 2, 2); + + for (int i = 0; i < 4; i++) { + scene.idle(5); + scene.world.showSection(util.select.fromTo(gaugePos.east(i) + .down(), gaugePos.east(i)), Direction.DOWN); + } + + scene.idle(10); + + for (int i = 0; i < 3; i++) { + scene.idle(5); + scene.world.showSection(util.select.position(3, 3, 3 - i), Direction.DOWN); + } + scene.world.setKineticSpeed(util.select.everywhere(), -12); + scene.effects.indicateSuccess(gaugePos); + for (int i = 0; i < 2; i++) { + scene.idle(5); + scene.world.showSection(util.select.position(3, 2 - i, 1), Direction.DOWN); + } + + BlockPos wheel = util.grid.at(3, 2, 2); + scene.effects.rotationSpeedIndicator(wheel); + scene.overlay.showText(50) + .text("Water Wheels draw force from adjacent Water Currents") + .placeNearTarget() + .pointAt(util.vector.topOf(wheel)); + scene.idle(50); + + AxisAlignedBB bb = new AxisAlignedBB(wheel).grow(.125f, 0, 0); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.MEDIUM, new Object(), bb.offset(0, 1.2, 0) + .contract(0, .75, 0), 80); + scene.idle(5); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.MEDIUM, new Object(), bb.offset(0, 0, 1.2) + .contract(0, 0, .75), 80); + scene.idle(5); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.MEDIUM, new Object(), bb.offset(0, -1.2, 0) + .contract(0, -.75, 0), 80); + scene.idle(5); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.MEDIUM, new Object(), bb.offset(0, 0, -1.2) + .contract(0, 0, -.75), 80); + scene.idle(5); + scene.overlay.showText(50) + .text("The more faces are powered, the faster the Water Wheel will rotate") + .colored(PonderPalette.MEDIUM) + .placeNearTarget() + .pointAt(util.vector.topOf(wheel)); + + scene.idle(80); + scene.rotateCameraY(-30); + scene.overlay.showText(70) + .text("The Wheels' blades should be oriented against the flow") + .placeNearTarget() + .pointAt(util.vector.topOf(wheel)); + scene.idle(80); + + ElementLink water = scene.world.makeSectionIndependent(util.select.fromTo(3, 1, 1, 3, 3, 1) + .add(util.select.fromTo(3, 3, 2, 3, 3, 3))); + ElementLink wheelElement = scene.world.makeSectionIndependent(util.select.position(wheel)); + + scene.world.setKineticSpeed(util.select.everywhere(), 0); + scene.world.moveSection(water, util.vector.of(0, 2, -2), 10); + scene.world.moveSection(wheelElement, util.vector.of(0, 1, -1), 10); + scene.idle(10); + scene.world.rotateSection(wheelElement, 0, 180, 0, 5); + scene.idle(10); + scene.world.modifyBlock(wheel, s -> s.with(WaterWheelBlock.HORIZONTAL_FACING, Direction.WEST), false); + scene.world.rotateSection(wheelElement, 0, -180, 0, 0); + scene.idle(1); + scene.world.moveSection(water, util.vector.of(0, -2, 2), 10); + scene.world.moveSection(wheelElement, util.vector.of(0, -1, 1), 10); + scene.idle(10); + scene.world.setKineticSpeed(util.select.everywhere(), -8); + + scene.overlay.showText(70) + .colored(PonderPalette.RED) + .text("Facing the opposite way, they will not be as effective") + .placeNearTarget() + .pointAt(util.vector.topOf(wheel)); + scene.idle(80); + + scene.world.setKineticSpeed(util.select.everywhere(), 0); + scene.world.moveSection(water, util.vector.of(0, 2, -2), 10); + scene.world.moveSection(wheelElement, util.vector.of(0, 1, -1), 10); + scene.idle(10); + scene.rotateCameraY(30); + scene.world.rotateSection(wheelElement, 0, 180, 0, 5); + scene.idle(10); + scene.world.modifyBlock(wheel, s -> s.with(WaterWheelBlock.HORIZONTAL_FACING, Direction.EAST), false); + scene.world.rotateSection(wheelElement, 0, -180, 0, 0); + scene.idle(1); + scene.world.moveSection(water, util.vector.of(0, -2, 2), 10); + scene.world.moveSection(wheelElement, util.vector.of(0, -1, 1), 10); + scene.idle(10); + scene.world.setKineticSpeed(util.select.everywhere(), -12); + scene.effects.indicateSuccess(gaugePos); + } + + public static void handCrank(SceneBuilder scene, SceneBuildingUtil util) { + manualSource(scene, util, true); + } + + public static void valveHandle(SceneBuilder scene, SceneBuildingUtil util) { + manualSource(scene, util, false); + scene.world.setKineticSpeed(util.select.everywhere(), 0); + scene.idle(20); + Vector3d centerOf = util.vector.centerOf(2, 2, 2); + scene.overlay.showControls(new InputWindowElement(centerOf, Pointing.DOWN).rightClick() + .withItem(new ItemStack(Items.BLUE_DYE)), 40); + scene.idle(7); + scene.world.modifyBlock(util.grid.at(2, 2, 2), s -> AllBlocks.DYED_VALVE_HANDLES[11].getDefaultState() + .with(ValveHandleBlock.FACING, Direction.UP), true); + scene.idle(10); + scene.overlay.showText(70) + .text("Valve handles can be dyed for aesthetic purposes") + .placeNearTarget() + .pointAt(centerOf); + } + + private static void manualSource(SceneBuilder scene, SceneBuildingUtil util, boolean handCrank) { + String name = handCrank ? "Hand Cranks" : "Valve Handles"; + scene.title(handCrank ? "hand_crank" : "valve_handle", "Generating Rotational Force using " + name); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + BlockPos gaugePos = util.grid.at(1, 3, 3); + BlockPos handlePos = util.grid.at(2, 2, 2); + Selection handleSelect = util.select.position(handlePos); + + scene.world.showSection(util.select.layersFrom(1) + .substract(handleSelect), Direction.DOWN); + scene.idle(10); + scene.world.showSection(handleSelect, Direction.DOWN); + scene.idle(20); + + Vector3d centerOf = util.vector.centerOf(handlePos); + scene.overlay.showText(70) + .text(name + " can be used by players to apply rotational force manually") + .placeNearTarget() + .pointAt(centerOf); + scene.idle(80); + + scene.overlay.showControls(new InputWindowElement(centerOf, Pointing.DOWN).rightClick(), 40); + scene.idle(7); + scene.world.setKineticSpeed(util.select.everywhere(), handCrank ? 32 : 16); + scene.world.modifyKineticSpeed(util.select.column(1, 3), f -> f * -2); + scene.effects.rotationDirectionIndicator(handlePos); + scene.effects.indicateSuccess(gaugePos); + scene.idle(10); + scene.overlay.showText(50) + .text("Hold Right-Click to rotate it Counter-Clockwise") + .placeNearTarget() + .pointAt(centerOf); + scene.idle(70); + scene.overlay.showText(50) + .colored(handCrank ? PonderPalette.MEDIUM : PonderPalette.SLOW) + .text("Its conveyed speed is " + (handCrank ? "relatively high" : "slow and precise")) + .placeNearTarget() + .pointAt(centerOf); + scene.idle(70); + + scene.world.setKineticSpeed(util.select.everywhere(), 0); + scene.idle(10); + + scene.overlay.showControls(new InputWindowElement(centerOf, Pointing.DOWN).rightClick() + .whileSneaking(), 40); + scene.idle(7); + scene.world.setKineticSpeed(util.select.everywhere(), handCrank ? -32 : -16); + scene.world.modifyKineticSpeed(util.select.column(1, 3), f -> f * -2); + scene.effects.rotationDirectionIndicator(handlePos); + scene.effects.indicateSuccess(gaugePos); + scene.idle(10); + scene.overlay.showText(90) + .text("Sneak and Hold Right-Click to rotate it Clockwise") + .placeNearTarget() + .pointAt(centerOf); + scene.idle(90); + } + + public static void sequencedGearshift(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("sequenced_gearshift", "Controlling Rotational Speed using Sequenced Gearshifts"); + scene.configureBasePlate(1, 0, 5); + scene.showBasePlate(); + + Selection redstone = util.select.fromTo(3, 1, 0, 3, 1, 1); + + scene.world.showSection(util.select.position(6, 0, 3) + .add(redstone), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(6, 1, 2, 4, 1, 2), Direction.DOWN); + + BlockPos gearshiftPos = util.grid.at(3, 1, 2); + Selection gearshiftSelection = util.select.position(gearshiftPos); + BlockPos bearingPos = util.grid.at(1, 1, 2); + BlockPos buttonPos = util.grid.at(3, 1, 0); + Selection outputKinetics = util.select.fromTo(3, 1, 2, 1, 1, 2); + + scene.world.setKineticSpeed(gearshiftSelection, 0); + scene.idle(10); + + scene.world.showSection(gearshiftSelection, Direction.DOWN); + scene.idle(10); + + scene.world.showSection(util.select.fromTo(2, 1, 2, 1, 1, 2), Direction.EAST); + scene.idle(10); + + Vector3d top = util.vector.topOf(gearshiftPos); + scene.overlay.showText(60) + .text("Seq. Gearshifts relay rotation by following a timed list of instructions") + .attachKeyFrame() + .pointAt(top) + .placeNearTarget(); + scene.idle(80); + + scene.overlay.showControls(new InputWindowElement(top, Pointing.DOWN).rightClick(), 40); + scene.idle(7); + scene.overlay.showSelectionWithText(gearshiftSelection, 50) + .colored(PonderPalette.BLUE) + .text("Right-click it to open the Configuration UI") + .pointAt(top) + .placeNearTarget(); + scene.idle(60); + + ElementLink contraption = + scene.world.showIndependentSection(util.select.fromTo(0, 3, 2, 0, 0, 2), Direction.EAST); + scene.world.configureCenterOfRotation(contraption, util.vector.centerOf(bearingPos)); + + scene.idle(20); + scene.world.toggleRedstonePower(redstone); + scene.effects.indicateRedstone(buttonPos); + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.setKineticSpeed(outputKinetics, 16); + scene.world.rotateBearing(bearingPos, 90, 40); + scene.world.rotateSection(contraption, 90, 0, 0, 40); + scene.effects.rotationDirectionIndicator(gearshiftPos.west()); + scene.idle(20); + scene.world.toggleRedstonePower(redstone); + scene.idle(20); + + scene.overlay.showText(80) + .text("Upon receiving a Redstone Signal, it will start running its configured sequence") + .attachKeyFrame() + .pointAt(top); + + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.setKineticSpeed(outputKinetics, -32); + scene.world.rotateBearing(bearingPos, -180, 40); + scene.world.rotateSection(contraption, -180, 0, 0, 40); + scene.effects.rotationDirectionIndicator(gearshiftPos.west()); + scene.idle(40); + + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.setKineticSpeed(outputKinetics, 0); + scene.idle(20); + + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.setKineticSpeed(outputKinetics, 16); + scene.world.rotateBearing(bearingPos, 90, 40); + scene.world.rotateSection(contraption, 90, 0, 0, 40); + scene.effects.rotationDirectionIndicator(gearshiftPos.west()); + scene.idle(40); + + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.setKineticSpeed(outputKinetics, 0); + + scene.idle(20); + scene.overlay.showText(70) + .text("Once finished, it waits for the next Redstone Signal and starts over") + .pointAt(util.vector.topOf(util.grid.at(3, 0, 1))); + scene.idle(80); + + scene.idle(20); + scene.world.toggleRedstonePower(redstone); + scene.effects.indicateRedstone(buttonPos); + + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.setKineticSpeed(outputKinetics, 16); + scene.world.rotateBearing(bearingPos, 90, 40); + scene.world.rotateSection(contraption, 90, 0, 0, 40); + scene.effects.rotationDirectionIndicator(gearshiftPos.west()); + scene.idle(20); + + scene.overlay.showText(60) + .text("A redstone comparator can be used to read the current progress") + .attachKeyFrame() + .pointAt(util.vector.topOf(util.grid.at(3, 0, 1))); + + scene.world.hideSection(redstone, Direction.NORTH); + scene.idle(15); + + BlockPos wire = util.grid.at(5, 1, 0); + Selection nixie = util.select.position(4, 1, 0); + ElementLink comparator = + scene.world.showIndependentSection(util.select.fromTo(5, 1, 1, 4, 1, 0), Direction.SOUTH); + scene.world.moveSection(comparator, util.vector.of(-2, 0, 0), 0); + scene.world.toggleRedstonePower(util.select.position(5, 1, 1)); + scene.world.cycleBlockProperty(wire, RedstoneWireBlock.POWER); + scene.world.modifyTileNBT(nixie, NixieTubeTileEntity.class, nbt -> nbt.putInt("RedstoneStrength", 1)); + + scene.idle(5); + + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.setKineticSpeed(outputKinetics, -32); + scene.world.rotateBearing(bearingPos, -180, 40); + scene.world.rotateSection(contraption, -180, 0, 0, 40); + scene.effects.rotationDirectionIndicator(gearshiftPos.west()); + scene.world.cycleBlockProperty(wire, RedstoneWireBlock.POWER); + scene.world.modifyTileNBT(nixie, NixieTubeTileEntity.class, nbt -> nbt.putInt("RedstoneStrength", 2)); + scene.idle(40); + + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.setKineticSpeed(outputKinetics, 0); + scene.world.cycleBlockProperty(wire, RedstoneWireBlock.POWER); + scene.world.modifyTileNBT(nixie, NixieTubeTileEntity.class, nbt -> nbt.putInt("RedstoneStrength", 3)); + scene.idle(20); + + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.setKineticSpeed(outputKinetics, 16); + scene.world.rotateBearing(bearingPos, 90, 40); + scene.world.rotateSection(contraption, 90, 0, 0, 40); + scene.effects.rotationDirectionIndicator(gearshiftPos.west()); + scene.world.cycleBlockProperty(wire, RedstoneWireBlock.POWER); + scene.world.modifyTileNBT(nixie, NixieTubeTileEntity.class, nbt -> nbt.putInt("RedstoneStrength", 4)); + scene.idle(40); + + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.cycleBlockProperty(gearshiftPos, SequencedGearshiftBlock.STATE); + scene.world.modifyBlock(wire, s -> s.with(RedstoneWireBlock.POWER, 0), false); + scene.world.toggleRedstonePower(util.select.position(5, 1, 1)); + scene.world.modifyTileNBT(nixie, NixieTubeTileEntity.class, nbt -> nbt.putInt("RedstoneStrength", 0)); + scene.world.setKineticSpeed(outputKinetics, 0); + } + + public static void furnaceEngine(SceneBuilder scene, SceneBuildingUtil util) { + furnaceEngine(scene, util, false); + } + + public static void flywheel(SceneBuilder scene, SceneBuildingUtil util) { + furnaceEngine(scene, util, true); + } + + private static void furnaceEngine(SceneBuilder scene, SceneBuildingUtil util, boolean flywheel) { + scene.title(flywheel ? "flywheel" : "furnace_engine", + "Generating Rotational Force using the " + (flywheel ? "Flywheel" : "Furnace Engine")); + scene.configureBasePlate(0, 0, 6); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos furnacePos = util.grid.at(4, 1, 3); + BlockPos cogPos = util.grid.at(1, 1, 2); + BlockPos gaugePos = util.grid.at(1, 1, 1); + + scene.idle(5); + Selection furnaceSelect = util.select.position(furnacePos); + scene.world.showSection(furnaceSelect, Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.position(furnacePos.west()), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.position(furnacePos.west(3)), Direction.EAST); + scene.idle(10); + + String text = flywheel ? "Flywheels are required for generating rotational force with the Furnace Engine" + : "Furnace Engines generate Rotational Force while their attached Furnace is running"; + scene.overlay.showText(80) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.topOf(furnacePos.west(flywheel ? 3 : 1))) + .text(text); + scene.idle(90); + + scene.overlay.showControls( + new InputWindowElement(util.vector.topOf(furnacePos), Pointing.DOWN).withItem(new ItemStack(Items.OAK_LOG)), + 30); + scene.idle(5); + scene.overlay + .showControls(new InputWindowElement(util.vector.blockSurface(furnacePos, Direction.NORTH), Pointing.RIGHT) + .withItem(new ItemStack(Items.COAL)), 30); + scene.idle(7); + scene.world.cycleBlockProperty(furnacePos, FurnaceBlock.LIT); + scene.effects.emitParticles(util.vector.of(4.5, 1.2, 2.9), Emitter.simple(ParticleTypes.LAVA, Vector3d.ZERO), 4, + 1); + scene.world.setKineticSpeed(util.select.fromTo(1, 1, 3, 1, 1, 1), 16); + scene.idle(40); + + scene.world.showSection(util.select.position(cogPos), Direction.SOUTH); + scene.idle(15); + scene.effects.rotationSpeedIndicator(cogPos); + scene.world.showSection(util.select.position(gaugePos), Direction.SOUTH); + scene.idle(15); + + scene.overlay.showText(80) + .attachKeyFrame() + .placeNearTarget() + .colored(PonderPalette.GREEN) + .pointAt(util.vector.blockSurface(gaugePos, Direction.WEST)) + .text("The provided Rotational Force has a very large stress capacity"); + scene.idle(90); + + ElementLink engine = + scene.world.makeSectionIndependent(util.select.fromTo(3, 1, 3, 1, 1, 1)); + scene.world.moveSection(engine, util.vector.of(0, 1, 0), 15); + scene.idle(10); + scene.world.hideSection(furnaceSelect, Direction.NORTH); + scene.idle(15); + scene.world.setBlock(furnacePos, Blocks.BLAST_FURNACE.getDefaultState() + .with(FurnaceBlock.FACING, Direction.NORTH) + .with(FurnaceBlock.LIT, true), false); + scene.world.showSection(furnaceSelect, Direction.NORTH); + scene.idle(10); + scene.world.moveSection(engine, util.vector.of(0, -1, 0), 15); + scene.idle(10); + scene.world.setKineticSpeed(util.select.fromTo(1, 1, 3, 1, 1, 1), 32); + scene.idle(5); + scene.effects.rotationSpeedIndicator(cogPos); + + scene.overlay.showText(80) + .placeNearTarget() + .colored(PonderPalette.MEDIUM) + .pointAt(util.vector.topOf(furnacePos.west())) + .text("Using a Blast Furnace will double the efficiency of the Engine"); + + } + + public static void speedController(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("rotation_speed_controller", "Using the Rotational Speed Controller"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + BlockPos cogPos = util.grid.at(1, 2, 1); + Selection gaugeSelect = util.select.position(1, 2, 3); + + scene.world.multiplyKineticSpeed(util.select.everywhere(), 0.5f); + scene.world.setKineticSpeed(gaugeSelect, 0); + scene.world.showSection(util.select.fromTo(5, 1, 1, 2, 1, 1), Direction.DOWN); + scene.world.showSection(util.select.fromTo(1, 1, 3, 1, 2, 3), Direction.DOWN); + scene.idle(10); + ElementLink rsc = + scene.world.showIndependentSection(util.select.position(0, 1, 1), Direction.DOWN); + scene.world.moveSection(rsc, util.vector.of(1, 0, 0), 0); + ElementLink rsc2 = + scene.world.showIndependentSection(util.select.position(1, 1, 1), Direction.DOWN); + scene.world.moveSection(rsc2, util.vector.of(0, -100, 0), 0); + scene.idle(10); + scene.world.showSection(util.select.position(1, 2, 1), Direction.DOWN); + scene.idle(15); + scene.effects.indicateSuccess(cogPos); + scene.world.moveSection(rsc2, util.vector.of(0, 100, 0), 0); + scene.world.moveSection(rsc, util.vector.of(0, -100, 0), 0); + scene.idle(5); + scene.world.showSection(util.select.position(1, 2, 2), Direction.DOWN); + scene.idle(10); + scene.world.setKineticSpeed(gaugeSelect, 8); + scene.effects.indicateSuccess(util.grid.at(1, 2, 3)); + + scene.overlay.showText(90) + .placeNearTarget() + .attachKeyFrame() + .pointAt(util.vector.blockSurface(cogPos, Direction.NORTH)) + .text("Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them"); + scene.idle(100); + + Vector3d inputVec = util.vector.of(1.5, 1.75, 1); + scene.overlay.showFilterSlotInput(inputVec, 60); + + scene.overlay.showText(70) + .placeNearTarget() + .attachKeyFrame() + .pointAt(inputVec) + .text("Using the scroll input on its side, the conveyed speed can be configured"); + scene.idle(80); + + InputWindowElement input = new InputWindowElement(inputVec, Pointing.UP).scroll(); + scene.overlay.showControls(input, 40); + scene.idle(15); + scene.world.multiplyKineticSpeed(util.select.fromTo(1, 2, 1, 1, 2, 3), 4); + scene.effects.rotationSpeedIndicator(cogPos); + scene.idle(55); + scene.markAsFinished(); + + scene.overlay.showControls(input, 30); + scene.idle(15); + scene.world.multiplyKineticSpeed(util.select.fromTo(1, 2, 1, 1, 2, 3), 4); + scene.effects.rotationSpeedIndicator(cogPos); + scene.idle(55); + + scene.overlay.showControls(input, 30); + scene.idle(15); + scene.world.multiplyKineticSpeed(util.select.fromTo(1, 2, 1, 1, 2, 3), -.05f); + scene.effects.rotationSpeedIndicator(cogPos); + scene.idle(35); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/MechanicalDrillScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/MechanicalDrillScenes.java new file mode 100644 index 000000000..ea3e48654 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/MechanicalDrillScenes.java @@ -0,0 +1,203 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class MechanicalDrillScenes { + + public static void breaker(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_drill", "Breaking Blocks with the Mechanical Drill"); + scene.configureBasePlate(0, 0, 5); + + scene.world.setKineticSpeed(util.select.layer(0), -8); + scene.world.setKineticSpeed(util.select.layer(1), 16); + + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(4, 1, 2, 5, 1, 2), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.position(3, 1, 2), Direction.EAST); + scene.idle(20); + + BlockPos breakingPos = util.grid.at(2, 1, 2); + + scene.world.showSection(util.select.position(2, 1, 2), Direction.DOWN); + scene.idle(5); + for (int i = 0; i < 10; i++) { + scene.idle(10); + scene.world.incrementBlockBreakingProgress(breakingPos); + if (i == 1) { + scene.overlay.showText(80) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.topOf(breakingPos)) + .text("When given Rotational Force, a Mechanical Drill will break blocks directly in front of it"); + } + } + + scene.world.hideSection(util.select.position(breakingPos), Direction.UP); + ElementLink plankEntity = scene.world.createItemEntity(util.vector.centerOf(breakingPos), + util.vector.of(0, .1f, 0), new ItemStack(Items.OAK_PLANKS)); + scene.idle(20); + scene.idle(15); + + scene.world.modifyEntity(plankEntity, Entity::remove); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> 4 * f); + scene.effects.rotationSpeedIndicator(breakingPos.east(3)); + scene.idle(5); + scene.world.setBlock(breakingPos, Blocks.OAK_PLANKS.getDefaultState(), false); + scene.world.showSection(util.select.position(breakingPos), Direction.DOWN); + + scene.idle(5); + for (int i = 0; i < 10; i++) { + scene.idle(3); + scene.world.incrementBlockBreakingProgress(breakingPos); + if (i == 2) { + scene.overlay.showText(80) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.topOf(breakingPos.east())) + .text("Its mining speed depends on the Rotational Input"); + } + } + + scene.world.createItemEntity(util.vector.centerOf(breakingPos), util.vector.of(0, .1f, 0), + new ItemStack(Items.OAK_PLANKS)); + } + + public static void contraption(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_drill_contraption", "Using Mechanical Drills on Contraptions"); + scene.configureBasePlate(0, 0, 6); + scene.world.showSection(util.select.layer(0), Direction.UP); + + Selection kinetics = util.select.fromTo(5, 1, 2, 5, 1, 6); + + scene.idle(5); + ElementLink pistonHead = + scene.world.showIndependentSection(util.select.fromTo(5, 1, 1, 7, 1, 1), Direction.DOWN); + scene.world.moveSection(pistonHead, util.vector.of(0, 0, 1), 0); + scene.world.showSection(kinetics, Direction.DOWN); + scene.idle(5); + ElementLink contraption = + scene.world.showIndependentSection(util.select.fromTo(4, 2, 3, 4, 1, 2), Direction.DOWN); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(3, 1, 3), Direction.EAST, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(3, 1, 2), Direction.EAST, contraption); + scene.world.showSectionAndMerge(util.select.position(3, 2, 3), Direction.EAST, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(3, 2, 2), Direction.EAST, contraption); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.topOf(util.grid.at(3, 2, 3))) + .text("Whenever Drills are moved as part of an animated Contraption..."); + scene.idle(70); + + Selection drills = util.select.fromTo(3, 1, 2, 3, 2, 3); + + Selection planks = util.select.fromTo(1, 1, 2, 1, 2, 3); + scene.world.showSection(planks, Direction.DOWN); + scene.world.setKineticSpeed(util.select.position(4, 0, 6), -8); + scene.world.setKineticSpeed(kinetics, 16); + scene.world.setKineticSpeed(drills, 16); + scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20); + scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20); + scene.idle(20); + scene.world.setKineticSpeed(drills, 64); + + BlockPos p1 = util.grid.at(1, 1, 2); + BlockPos p2 = util.grid.at(1, 1, 3); + BlockPos p3 = util.grid.at(1, 2, 2); + BlockPos p4 = util.grid.at(1, 2, 3); + + for (int i = 0; i < 10; i++) { + scene.idle(3); + scene.world.incrementBlockBreakingProgress(p1); + scene.world.incrementBlockBreakingProgress(p2); + scene.world.incrementBlockBreakingProgress(p3); + scene.world.incrementBlockBreakingProgress(p4); + if (i == 2) { + scene.overlay.showText(80) + .placeNearTarget() + .pointAt(util.vector.topOf(p3)) + .text("...they will break blocks the contraption runs them into"); + } + } + + Vector3d m = util.vector.of(-.1, 0, 0); + ItemStack item = new ItemStack(Items.OAK_PLANKS); + scene.world.createItemEntity(util.vector.centerOf(p1), m, item); + scene.world.createItemEntity(util.vector.centerOf(p2), m, item); + scene.world.createItemEntity(util.vector.centerOf(p3), m, item); + scene.world.createItemEntity(util.vector.centerOf(p4), m, item); + + scene.world.setKineticSpeed(drills, 16); + scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20); + scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20); + scene.idle(20); + scene.world.setKineticSpeed(drills, 0); + scene.idle(20); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.moveSection(pistonHead, util.vector.of(2, 0, 0), 40); + scene.world.moveSection(contraption, util.vector.of(2, 0, 0), 40); + scene.world.hideSection(planks, Direction.UP); + scene.idle(40); + + scene.world.setBlocks(planks, Blocks.OAK_PLANKS.getDefaultState(), false); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.world.glueBlockOnto(util.grid.at(4, 3, 2), Direction.DOWN, contraption); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(4, 3, 2), Direction.WEST)) + .sharedText("storage_on_contraption"); + scene.idle(70); + + scene.world.showSection(planks, Direction.DOWN); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.setKineticSpeed(drills, 16); + scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20); + scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20); + + scene.idle(20); + scene.world.setKineticSpeed(drills, 64); + + for (int i = 0; i < 10; i++) { + scene.idle(3); + scene.world.incrementBlockBreakingProgress(p1); + scene.world.incrementBlockBreakingProgress(p2); + scene.world.incrementBlockBreakingProgress(p3); + scene.world.incrementBlockBreakingProgress(p4); + } + + scene.world.setKineticSpeed(drills, 16); + scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20); + scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20); + scene.idle(20); + scene.world.setKineticSpeed(drills, 0); + scene.idle(10); + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(2, 3, 2), Pointing.DOWN) + .withItem(new ItemStack(Blocks.OAK_PLANKS)), 60); + scene.idle(20); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/MechanicalSawScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/MechanicalSawScenes.java new file mode 100644 index 000000000..136722b35 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/MechanicalSawScenes.java @@ -0,0 +1,396 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; +import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class MechanicalSawScenes { + + public static void processing(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_saw_processing", "Processing Items on the Mechanical Saw"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos shaftPos = util.grid.at(2, 1, 3); + scene.world.setBlock(shaftPos, AllBlocks.SHAFT.getDefaultState() + .with(ShaftBlock.AXIS, Axis.Z), false); + + BlockPos sawPos = util.grid.at(2, 1, 2); + Selection sawSelect = util.select.position(sawPos); + scene.world.modifyTileNBT(sawSelect, SawTileEntity.class, nbt -> nbt.putInt("RecipeIndex", 0)); + + scene.idle(5); + scene.world.showSection(util.select.fromTo(2, 1, 3, 2, 1, 5), Direction.DOWN); + scene.idle(10); + scene.effects.rotationDirectionIndicator(shaftPos); + scene.world.showSection(sawSelect, Direction.DOWN); + scene.idle(10); + scene.overlay.showText(50) + .attachKeyFrame() + .text("Upward facing Mechanical Saws can process a variety of items") + .pointAt(util.vector.blockSurface(sawPos, Direction.WEST)) + .placeNearTarget(); + scene.idle(45); + + ItemStack log = new ItemStack(Items.OAK_LOG); + ItemStack strippedLog = new ItemStack(Items.STRIPPED_OAK_LOG); + ItemStack planks = new ItemStack(Items.OAK_PLANKS); + + Vector3d itemSpawn = util.vector.centerOf(sawPos.up() + .west()); + ElementLink logItem = scene.world.createItemEntity(itemSpawn, util.vector.of(0, 0, 0), log); + scene.idle(12); + + scene.overlay.showControls(new InputWindowElement(itemSpawn, Pointing.DOWN).withItem(log), 20); + scene.idle(10); + + scene.world.modifyEntity(logItem, e -> e.setMotion(util.vector.of(0.05, 0.2, 0))); + scene.idle(12); + + scene.world.modifyEntity(logItem, Entity::remove); + scene.world.createItemOnBeltLike(sawPos, Direction.WEST, log); + scene.idle(30); + + logItem = scene.world.createItemEntity(util.vector.topOf(sawPos) + .add(0.5, -.1, 0), util.vector.of(0.05, 0.18, 0), strippedLog); + scene.idle(12); + scene.overlay.showControls(new InputWindowElement(itemSpawn.add(2, 0, 0), Pointing.DOWN).withItem(strippedLog), + 20); + scene.idle(30); + + scene.overlay.showText(60) + .attachKeyFrame() + .text("The processed item always moves against the rotational input to the saw") + .pointAt(util.vector.blockSurface(sawPos, Direction.UP)) + .placeNearTarget(); + scene.idle(70); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -2 * f); + scene.effects.rotationDirectionIndicator(shaftPos); + scene.world.modifyEntity(logItem, e -> e.setMotion(util.vector.of(-0.05, 0.2, 0))); + scene.idle(12); + + scene.world.modifyEntity(logItem, Entity::remove); + scene.world.createItemOnBeltLike(sawPos, Direction.EAST, strippedLog); + scene.idle(40); + + logItem = scene.world.createItemEntity(util.vector.topOf(sawPos) + .add(-0.5, -.1, 0), util.vector.of(-0.05, 0.18, 0), planks); + scene.idle(22); + + Selection otherBelt = util.select.fromTo(3, 1, 3, 4, 1, 2); + Selection belt = util.select.fromTo(0, 1, 2, 1, 1, 3); + + scene.world.setKineticSpeed(otherBelt, 0); + scene.world.setKineticSpeed(belt, 0); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.modifyEntity(logItem, Entity::remove); + scene.world.setBlock(shaftPos, AllBlocks.COGWHEEL.getDefaultState() + .with(ShaftBlock.AXIS, Axis.Z), true); + scene.idle(3); + scene.addKeyframe(); + + ElementLink beltSection = scene.world.showIndependentSection(belt, Direction.EAST); + scene.world.moveSection(beltSection, util.vector.of(0, 100, 0), 0); + scene.idle(1); + scene.world.removeItemsFromBelt(util.grid.at(1, 1, 2)); + scene.idle(1); + scene.world.setKineticSpeed(belt, -64); + scene.idle(1); + scene.world.moveSection(beltSection, util.vector.of(0, -100, 0), 0); + scene.idle(3); + + ElementLink otherBeltSection = + scene.world.showIndependentSection(otherBelt, Direction.WEST); + scene.world.moveSection(otherBeltSection, util.vector.of(0, 100, 0), 0); + scene.idle(1); + scene.world.removeItemsFromBelt(util.grid.at(3, 1, 2)); + scene.idle(1); + scene.world.setKineticSpeed(otherBelt, -64); + scene.idle(1); + scene.world.moveSection(otherBeltSection, util.vector.of(0, -100, 0), 0); + scene.idle(3); + + ItemStack stone = new ItemStack(Blocks.STONE); + BlockPos firstBelt = util.grid.at(0, 1, 2); + scene.world.createItemOnBelt(firstBelt, Direction.WEST, stone); + scene.overlay.showText(60) + .text("Saws can work in-line with Mechanical Belts") + .pointAt(util.vector.blockSurface(firstBelt, Direction.WEST)) + .placeNearTarget(); + scene.idle(60); + scene.rotateCameraY(-90); + scene.idle(20); + + Vector3d filter = util.vector.of(2.5, 1 + 13 / 16f, 2.75); + scene.overlay.showFilterSlotInput(filter, 80); + ItemStack bricks = new ItemStack(Blocks.STONE_BRICKS); + scene.overlay.showControls(new InputWindowElement(filter, Pointing.DOWN).withItem(bricks), 80); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.idle(7); + scene.world.setFilterData(util.select.position(sawPos), SawTileEntity.class, bricks); + scene.idle(10); + + scene.overlay.showText(80) + .attachKeyFrame() + .text("When an ingredient has multiple possible outcomes, the filter slot can specify it") + .pointAt(filter) + .placeNearTarget(); + scene.idle(90); + + scene.rotateCameraY(90); + scene.world.createItemOnBelt(firstBelt, Direction.WEST, stone); + scene.idle(20); + + scene.markAsFinished(); + scene.overlay.showText(100) + .text("Without filter, the Saw would cycle through all outcomes instead") + .colored(PonderPalette.RED) + .pointAt(filter) + .placeNearTarget(); + scene.idle(65); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + } + + public static void treeCutting(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_saw_breaker", "Cutting Trees with the Mechanical Saw"); + scene.configureBasePlate(0, 0, 5); + scene.scaleSceneView(.9f); + scene.world.setBlock(util.grid.at(2, 0, 2), Blocks.GRASS_BLOCK.getDefaultState(), false); + scene.world.showSection(util.select.layer(0) + .add(util.select.position(3, 1, 1)) + .add(util.select.position(1, 1, 2)), Direction.UP); + + scene.world.setKineticSpeed(util.select.position(5, 0, 1), -8); + scene.world.setKineticSpeed(util.select.fromTo(3, 1, 2, 5, 1, 2), 16); + + scene.idle(5); + scene.world.showSection(util.select.fromTo(4, 1, 2, 5, 1, 2), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.position(3, 1, 2), Direction.DOWN); + + scene.idle(20); + scene.world.showSection(util.select.fromTo(2, 1, 2, 2, 3, 2), Direction.UP); + scene.world.showSection(util.select.layersFrom(4), Direction.UP); + + BlockPos breakingPos = util.grid.at(2, 1, 2); + scene.idle(5); + for (int i = 0; i < 10; i++) { + scene.idle(10); + scene.world.incrementBlockBreakingProgress(breakingPos); + if (i == 1) { + scene.overlay.showText(80) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.blockSurface(breakingPos, Direction.WEST)) + .text("When given Rotational Force, a Mechanical Saw will cut trees directly in front of it"); + } + } + + scene.world.replaceBlocks(util.select.fromTo(2, 2, 2, 2, 6, 2), Blocks.AIR.getDefaultState(), true); + + scene.world.destroyBlock(util.grid.at(3, 5, 0)); + scene.world.destroyBlock(util.grid.at(0, 4, 1)); + scene.world.destroyBlock(util.grid.at(2, 6, 1)); + scene.world.destroyBlock(util.grid.at(1, 4, 0)); + scene.world.destroyBlock(util.grid.at(1, 6, 2)); + scene.world.destroyBlock(util.grid.at(1, 5, 3)); + scene.world.destroyBlock(util.grid.at(0, 4, 3)); + + scene.world.replaceBlocks(util.select.layersFrom(4), Blocks.AIR.getDefaultState(), false); + + for (int i = 0; i < 5; i++) { + Vector3d dropPos = util.vector.centerOf(breakingPos.up(i)); + float distance = (float) dropPos.distanceTo(util.vector.centerOf(breakingPos)); + scene.world.createItemEntity(dropPos, util.vector.of(-distance / 20, 0, 0), new ItemStack(Items.OAK_LOG)); + } + + scene.idle(35); + scene.world.destroyBlock(util.grid.at(1, 1, 2)); + scene.world.hideSection(util.select.layersFrom(2) + .add(util.select.fromTo(2, 1, 2, 1, 1, 3)), Direction.UP); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.idle(15); + scene.world.setBlocks(util.select.fromTo(2, 1, 2, 1, 20, 3), Blocks.JUNGLE_LOG.getDefaultState(), false); + scene.world.showSection(util.select.layersFrom(2) + .add(util.select.fromTo(2, 1, 2, 1, 1, 3)), Direction.UP); + scene.idle(15); + + scene.world.hideSection(util.select.fromTo(2, 1, 2, 1, 1, 3) + .substract(util.select.position(breakingPos)), Direction.WEST); + scene.idle(10); + scene.overlay.showSelectionWithText(util.select.position(breakingPos), 90) + .attachKeyFrame() + .colored(PonderPalette.GREEN) + .placeNearTarget() + .text("In order to cut the tree fully, the Saw has to break the last block connecting it to the ground"); + + scene.idle(25); + for (int i = 0; i < 10; i++) { + scene.idle(10); + scene.world.incrementBlockBreakingProgress(breakingPos); + } + + for (int i = 0; i < 30; i++) { + scene.world.replaceBlocks(util.select.fromTo(2, i + 1, 2, 1, i + 1, 3), Blocks.AIR.getDefaultState(), true); + for (int x = 1; x <= 2; x++) { + for (int z = 2; z <= 3; z++) { + Vector3d dropPos = util.vector.centerOf(x, i + 1, z); + float distance = (float) dropPos.distanceTo(util.vector.centerOf(breakingPos)); + scene.world.createItemEntity(dropPos, util.vector.of(-distance / 20, 0, 0), + new ItemStack(Items.JUNGLE_LOG)); + } + } + scene.idle(1); + } + } + + public static void contraption(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_saw_contraption", "Using Mechanical Saws on Contraptions"); + scene.configureBasePlate(1, 0, 6); + scene.scaleSceneView(.9f); + scene.world.setBlock(util.grid.at(2, 0, 3), Blocks.GRASS_BLOCK.getDefaultState(), false); + scene.world.showSection(util.select.layer(0) + .add(util.select.position(3, 1, 1)) + .add(util.select.position(1, 1, 2)) + .add(util.select.position(2, 1, 4)), Direction.UP); + + Selection kinetics = util.select.fromTo(6, 1, 2, 6, 1, 6); + + scene.idle(5); + ElementLink pistonHead = + scene.world.showIndependentSection(util.select.fromTo(6, 1, 1, 8, 1, 1), Direction.DOWN); + scene.world.moveSection(pistonHead, util.vector.of(0, 0, 1), 0); + scene.world.showSection(kinetics, Direction.DOWN); + scene.idle(5); + ElementLink contraption = + scene.world.showIndependentSection(util.select.fromTo(5, 1, 3, 5, 1, 2), Direction.DOWN); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(4, 1, 3), Direction.EAST, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(4, 1, 2), Direction.EAST, contraption); + scene.idle(5); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.topOf(util.grid.at(4, 1, 3))) + .text("Whenever Saws are moved as part of an animated Contraption..."); + scene.idle(70); + + Selection saws = util.select.fromTo(4, 1, 2, 4, 1, 3); + + Selection tree = util.select.fromTo(2, 1, 3, 2, 7, 3) + .add(util.select.layersFrom(3)); + scene.world.showSection(tree, Direction.UP); + scene.world.setKineticSpeed(util.select.position(5, 0, 6), -8); + scene.world.setKineticSpeed(kinetics, 16); + scene.world.setKineticSpeed(saws, 16); + scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20); + scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20); + scene.idle(20); + + BlockPos breakingPos = util.grid.at(2, 1, 3); + + for (int i = 0; i < 10; i++) { + scene.idle(3); + scene.world.incrementBlockBreakingProgress(breakingPos); + if (i == 2) { + scene.overlay.showText(80) + .placeNearTarget() + .pointAt(util.vector.blockSurface(breakingPos, Direction.WEST)) + .text("...they will cut any trees the contraption runs them into"); + } + } + + scene.world.replaceBlocks(util.select.fromTo(2, 2, 3, 2, 6, 3), Blocks.AIR.getDefaultState(), true); + scene.world.destroyBlock(util.grid.at(4, 5, 1)); + scene.world.destroyBlock(util.grid.at(1, 4, 2)); + scene.world.destroyBlock(util.grid.at(3, 6, 2)); + scene.world.destroyBlock(util.grid.at(2, 4, 1)); + scene.world.destroyBlock(util.grid.at(2, 6, 3)); + scene.world.destroyBlock(util.grid.at(2, 5, 2)); + scene.world.destroyBlock(util.grid.at(1, 4, 2)); + scene.world.replaceBlocks(util.select.layersFrom(4), Blocks.AIR.getDefaultState(), false); + + for (int i = 0; i < 5; i++) { + Vector3d dropPos = util.vector.centerOf(breakingPos.up(i)); + float distance = (float) dropPos.distanceTo(util.vector.centerOf(breakingPos)); + scene.world.createItemEntity(dropPos, util.vector.of(-distance / 20, 0, 0), new ItemStack(Items.OAK_LOG)); + } + + scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20); + scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20); + scene.idle(20); + scene.world.setKineticSpeed(saws, 0); + scene.idle(20); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.moveSection(pistonHead, util.vector.of(2, 0, 0), 40); + scene.world.moveSection(contraption, util.vector.of(2, 0, 0), 40); + scene.world.hideSection(tree, Direction.UP); + scene.idle(40); + + scene.world.restoreBlocks(tree); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.world.glueBlockOnto(util.grid.at(5, 2, 2), Direction.DOWN, contraption); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(5, 2, 2), Direction.WEST)) + .sharedText("storage_on_contraption"); + scene.idle(70); + + scene.world.showSection(tree, Direction.DOWN); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.setKineticSpeed(saws, 16); + scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20); + scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20); + scene.idle(20); + + for (int i = 0; i < 10; i++) { + scene.idle(3); + scene.world.incrementBlockBreakingProgress(breakingPos); + } + + scene.world.replaceBlocks(util.select.fromTo(2, 2, 3, 2, 6, 3), Blocks.AIR.getDefaultState(), true); + scene.world.destroyBlock(util.grid.at(4, 5, 1)); + scene.world.destroyBlock(util.grid.at(1, 4, 2)); + scene.world.destroyBlock(util.grid.at(3, 6, 2)); + scene.world.destroyBlock(util.grid.at(2, 4, 1)); + scene.world.destroyBlock(util.grid.at(2, 6, 3)); + scene.world.destroyBlock(util.grid.at(2, 5, 2)); + scene.world.destroyBlock(util.grid.at(1, 4, 2)); + scene.world.replaceBlocks(util.select.layersFrom(4), Blocks.AIR.getDefaultState(), false); + + scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20); + scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20); + scene.idle(20); + scene.world.setKineticSpeed(saws, 0); + scene.idle(10); + scene.overlay.showControls( + new InputWindowElement(util.vector.topOf(3, 2, 2), Pointing.DOWN).withItem(new ItemStack(Blocks.OAK_LOG)), + 60); + scene.idle(20); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/MovementActorScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/MovementActorScenes.java new file mode 100644 index 000000000..cecbcfeef --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/MovementActorScenes.java @@ -0,0 +1,509 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.components.actors.HarvesterTileEntity; +import com.simibubi.create.content.contraptions.components.actors.PortableItemInterfaceTileEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.LinearChassisBlock; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement.FlappyPose; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.CropsBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class MovementActorScenes { + + public static void psiTransfer(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("portable_storage_interface", "Contraption Storage Exchange"); + scene.configureBasePlate(0, 0, 6); + scene.scaleSceneView(0.95f); + scene.setSceneOffsetY(-1); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + BlockPos bearing = util.grid.at(5, 1, 2); + scene.world.showSection(util.select.position(bearing), Direction.DOWN); + scene.idle(5); + ElementLink contraption = + scene.world.showIndependentSection(util.select.fromTo(5, 2, 2, 6, 3, 2), Direction.DOWN); + scene.world.configureCenterOfRotation(contraption, util.vector.centerOf(bearing)); + scene.idle(10); + scene.world.rotateBearing(bearing, 360, 70); + scene.world.rotateSection(contraption, 0, 360, 0, 70); + scene.overlay.showText(60) + .pointAt(util.vector.topOf(bearing.up(2))) + .colored(PonderPalette.RED) + .placeNearTarget() + .text("Inventories on moving contraptions cannot be accessed by players."); + + scene.idle(70); + BlockPos psi = util.grid.at(4, 2, 2); + scene.world.showSectionAndMerge(util.select.position(psi), Direction.EAST, contraption); + scene.idle(13); + scene.effects.superGlue(psi, Direction.EAST, true); + + scene.overlay.showText(80) + .pointAt(util.vector.topOf(psi)) + .colored(PonderPalette.GREEN) + .placeNearTarget() + .text("This component can interact with storage without the need to stop the contraption."); + scene.idle(90); + + BlockPos psi2 = psi.west(2); + scene.world.showSection(util.select.position(psi2), Direction.DOWN); + scene.overlay.showSelectionWithText(util.select.position(psi.west()), 50) + .colored(PonderPalette.RED) + .placeNearTarget() + .text("Place a second one with a gap of 1 or 2 blocks inbetween"); + scene.idle(55); + + scene.world.rotateBearing(bearing, 360, 60); + scene.world.rotateSection(contraption, 0, 360, 0, 60); + scene.idle(20); + + scene.overlay.showText(40) + .placeNearTarget() + .pointAt(util.vector.of(3, 3, 2.5)) + .text("Whenever they pass by each other, they will engage in a connection"); + scene.idle(35); + + Selection both = util.select.fromTo(2, 2, 2, 4, 2, 2); + Class psiClass = PortableItemInterfaceTileEntity.class; + + scene.world.modifyTileNBT(both, psiClass, nbt -> { + nbt.putFloat("Distance", 1); + nbt.putFloat("Timer", 40); + }); + + scene.idle(20); + scene.overlay.showOutline(PonderPalette.GREEN, psi, util.select.fromTo(5, 3, 2, 6, 3, 2), 80); + scene.idle(10); + + scene.overlay.showSelectionWithText(util.select.position(psi2), 70) + .placeNearTarget() + .colored(PonderPalette.GREEN) + .text("While engaged, the stationary interface will represent ALL inventories on the contraption"); + + scene.idle(80); + + BlockPos hopper = util.grid.at(2, 3, 2); + scene.world.showSection(util.select.position(hopper), Direction.DOWN); + scene.overlay.showText(70) + .placeNearTarget() + .pointAt(util.vector.topOf(hopper)) + .text("Items can now be inserted..."); + + ItemStack itemStack = AllItems.COPPER_INGOT.asStack(); + Vector3d entitySpawn = util.vector.topOf(hopper.up(3)); + + ElementLink entity1 = + scene.world.createItemEntity(entitySpawn, util.vector.of(0, 0.2, 0), itemStack); + scene.idle(10); + ElementLink entity2 = + scene.world.createItemEntity(entitySpawn, util.vector.of(0, 0.2, 0), itemStack); + scene.idle(10); + scene.world.modifyEntity(entity1, Entity::remove); + scene.idle(10); + scene.world.modifyEntity(entity2, Entity::remove); + + scene.overlay + .showControls(new InputWindowElement(util.vector.topOf(5, 3, 2), Pointing.DOWN).withItem(itemStack), 40); + + scene.idle(30); + scene.world.hideSection(util.select.position(hopper), Direction.UP); + scene.idle(15); + + BlockPos beltPos = util.grid.at(1, 1, 2); + scene.world.showSection(util.select.fromTo(0, 1, 0, 1, 2, 6), Direction.DOWN); + scene.idle(10); + scene.world.createItemOnBelt(beltPos, Direction.EAST, itemStack.copy()); + scene.overlay.showText(40) + .placeNearTarget() + .pointAt(util.vector.topOf(beltPos.up())) + .text("...or extracted from the contraption"); + scene.idle(15); + scene.world.createItemOnBelt(beltPos, Direction.EAST, itemStack); + + scene.idle(20); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.idle(15); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + + scene.overlay.showText(120) + .placeNearTarget() + .pointAt(util.vector.topOf(psi2)) + .text("After no items have been exchanged for a while, the contraption will continue on its way"); + scene.world.modifyTileNBT(both, psiClass, nbt -> nbt.putFloat("Timer", 9)); + + scene.idle(15); + scene.markAsFinished(); + scene.world.rotateBearing(bearing, 270, 120); + scene.world.rotateSection(contraption, 0, 270, 0, 120); + } + + public static void psiRedstone(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("portable_storage_interface_redstone", "Redstone Control"); + scene.configureBasePlate(0, 0, 5); + scene.setSceneOffsetY(-1); + + Class psiClass = PortableItemInterfaceTileEntity.class; + Selection psis = util.select.fromTo(1, 1, 3, 1, 3, 3); + scene.world.modifyTileNBT(psis, psiClass, nbt -> { + nbt.putFloat("Distance", 1); + nbt.putFloat("Timer", 40); + }); + + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(5); + + ElementLink contraption = + scene.world.showIndependentSection(util.select.layersFrom(2), Direction.DOWN); + BlockPos bearing = util.grid.at(3, 1, 3); + scene.world.configureCenterOfRotation(contraption, util.vector.topOf(bearing)); + scene.idle(20); + scene.world.modifyTileNBT(psis, psiClass, nbt -> nbt.putFloat("Timer", 9)); + scene.idle(20); + scene.world.rotateBearing(bearing, 360 * 3 + 270, 240 + 60); + scene.world.rotateSection(contraption, 0, 360 * 3 + 270, 0, 240 + 60); + scene.idle(20); + + scene.world.toggleRedstonePower(util.select.fromTo(1, 1, 1, 1, 1, 2)); + scene.effects.indicateRedstone(util.grid.at(1, 1, 1)); + + scene.idle(10); + + scene.overlay.showSelectionWithText(util.select.position(1, 1, 3), 120) + .colored(PonderPalette.RED) + .text("Redstone power will prevent the stationary interface from engaging"); + + scene.idle(20); + scene.markAsFinished(); + } + + public static void harvester(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_harvester", "Using Mechanical Harvesters on Contraptions"); + scene.configureBasePlate(0, 0, 6); + scene.scaleSceneView(0.9f); + + Selection crops = util.select.fromTo(4, 1, 2, 3, 1, 2) + .add(util.select.fromTo(3, 1, 1, 2, 1, 1) + .add(util.select.position(2, 1, 3)) + .add(util.select.position(1, 1, 2))); + + scene.world.setBlocks(crops, Blocks.WHEAT.getDefaultState() + .with(CropsBlock.AGE, 7), false); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos bearingPos = util.grid.at(4, 1, 4); + + scene.idle(5); + scene.world.showSection(crops, Direction.UP); + scene.world.showSection(util.select.position(bearingPos), Direction.DOWN); + scene.idle(5); + ElementLink contraption = + scene.world.showIndependentSection(util.select.fromTo(4, 2, 4, 2, 2, 5) + .add(util.select.fromTo(2, 1, 5, 0, 1, 5)), Direction.DOWN); + scene.world.configureCenterOfRotation(contraption, util.vector.centerOf(bearingPos)); + scene.idle(10); + + for (int i = 0; i < 3; i++) { + scene.world.showSectionAndMerge(util.select.position(i, 1, 4), Direction.SOUTH, contraption); + scene.idle(5); + } + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(1, 1, 4), Direction.SOUTH)) + .text("Whenever Harvesters are moved as part of an animated Contraption..."); + scene.idle(70); + + for (int i = 0; i < 3; i++) + scene.world.modifyTileEntity(util.grid.at(i, 1, 4), HarvesterTileEntity.class, + hte -> hte.setAnimatedSpeed(-150)); + scene.world.rotateBearing(bearingPos, -360, 140); + scene.world.rotateSection(contraption, 0, -360, 0, 140); + + BlockState harvested = Blocks.WHEAT.getDefaultState(); + ItemStack wheatItem = new ItemStack(Items.WHEAT); + + scene.idle(5); + BlockPos current = util.grid.at(2, 1, 3); + scene.world.setBlock(current, harvested, true); + scene.world.createItemEntity(util.vector.centerOf(current), util.vector.of(0, 0.3, -.2), wheatItem); + scene.idle(5); + current = util.grid.at(1, 1, 2); + scene.world.setBlock(current, harvested, true); + scene.world.createItemEntity(util.vector.centerOf(current), util.vector.of(0, 0.3, -.2), wheatItem); + scene.idle(5); + current = util.grid.at(3, 1, 2); + scene.world.setBlock(current, harvested, true); + scene.world.createItemEntity(util.vector.centerOf(current), util.vector.of(.1, 0.3, -.1), wheatItem); + current = util.grid.at(2, 1, 1); + scene.world.setBlock(current, harvested, true); + scene.world.createItemEntity(util.vector.centerOf(current), util.vector.of(.1, 0.3, -.1), wheatItem); + scene.idle(5); + current = util.grid.at(3, 1, 1); + scene.world.setBlock(current, harvested, true); + scene.world.createItemEntity(util.vector.centerOf(current), util.vector.of(.1, 0.3, -.1), wheatItem); + scene.idle(5); + current = util.grid.at(4, 1, 2); + scene.world.setBlock(current, harvested, true); + scene.world.createItemEntity(util.vector.centerOf(current), util.vector.of(.2, 0.3, 0), wheatItem); + + scene.overlay.showText(80) + .pointAt(util.vector.topOf(1, 0, 2)) + .text("They will harvest and reset any mature crops on their way") + .placeNearTarget(); + + scene.idle(101); + scene.world.hideSection(crops, Direction.DOWN); + scene.idle(15); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.world.setBlocks(crops, Blocks.WHEAT.getDefaultState() + .with(CropsBlock.AGE, 7), false); + scene.world.showSection(crops, Direction.UP); + + for (int i = 0; i < 3; i++) + scene.world.modifyTileEntity(util.grid.at(i, 1, 4), HarvesterTileEntity.class, + hte -> hte.setAnimatedSpeed(0)); + scene.idle(10); + + scene.world.cycleBlockProperty(util.grid.at(1, 1, 5), LinearChassisBlock.STICKY_TOP); + scene.world.glueBlockOnto(util.grid.at(1, 2, 5), Direction.DOWN, contraption); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(1, 2, 5), Direction.WEST)) + .sharedText("storage_on_contraption"); + scene.idle(70); + + for (int i = 0; i < 3; i++) + scene.world.modifyTileEntity(util.grid.at(i, 1, 4), HarvesterTileEntity.class, + hte -> hte.setAnimatedSpeed(-150)); + scene.world.rotateBearing(bearingPos, -360, 140); + scene.world.rotateSection(contraption, 0, -360, 0, 140); + + scene.idle(5); + current = util.grid.at(2, 1, 3); + scene.world.setBlock(current, harvested, true); + scene.idle(5); + current = util.grid.at(1, 1, 2); + scene.world.setBlock(current, harvested, true); + scene.idle(5); + current = util.grid.at(3, 1, 2); + scene.world.setBlock(current, harvested, true); + current = util.grid.at(2, 1, 1); + scene.world.setBlock(current, harvested, true); + scene.idle(5); + current = util.grid.at(3, 1, 1); + scene.world.setBlock(current, harvested, true); + scene.idle(5); + current = util.grid.at(4, 1, 2); + scene.world.setBlock(current, harvested, true); + + scene.idle(116); + scene.overlay + .showControls(new InputWindowElement(util.vector.topOf(1, 2, 5), Pointing.DOWN).withItem(wheatItem), 50); + for (int i = 0; i < 3; i++) + scene.world.modifyTileEntity(util.grid.at(i, 1, 4), HarvesterTileEntity.class, + hte -> hte.setAnimatedSpeed(0)); + } + + public static void plough(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_plough", "Using Mechanical Ploughs on Contraptions"); + scene.configureBasePlate(0, 0, 6); + scene.scaleSceneView(0.9f); + + Selection garbage = util.select.fromTo(2, 1, 3, 1, 1, 2); + Selection kinetics = util.select.fromTo(5, 1, 6, 5, 1, 2); + Selection dynamic = util.select.fromTo(4, 0, 6, 5, 1, 6); + + scene.showBasePlate(); + ElementLink cogs = + scene.world.showIndependentSection(util.select.fromTo(4, 0, 6, 5, 1, 6), Direction.UP); + scene.idle(5); + scene.world.showSection(kinetics.substract(dynamic), Direction.DOWN); + ElementLink pistonHead = + scene.world.showIndependentSection(util.select.fromTo(5, 1, 1, 7, 1, 1), Direction.DOWN); + scene.world.moveSection(pistonHead, util.vector.of(0, 0, 1), 0); + scene.idle(5); + ElementLink contraption = + scene.world.showIndependentSection(util.select.fromTo(4, 1, 3, 4, 1, 2), Direction.DOWN); + scene.idle(10); + scene.world.showSectionAndMerge(util.select.position(3, 1, 3), Direction.EAST, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(3, 1, 2), Direction.EAST, contraption); + scene.idle(20); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(3, 1, 3), Direction.EAST)) + .text("Whenever Ploughs are moved as part of an animated Contraption..."); + scene.idle(50); + scene.world.showSection(garbage, Direction.EAST); + scene.idle(20); + + scene.world.setKineticSpeed(util.select.position(4, 0, 6), -8); + scene.world.setKineticSpeed(kinetics, 16); + scene.world.moveSection(pistonHead, util.vector.of(-2, 0, 0), 60); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 60); + scene.idle(15); + + Vector3d m = util.vector.of(-0.1, .2, 0); + scene.world.destroyBlock(util.grid.at(2, 1, 3)); + scene.world.createItemEntity(util.vector.centerOf(2, 1, 3), m, new ItemStack(Items.LEVER)); + scene.world.destroyBlock(util.grid.at(2, 1, 2)); + scene.world.createItemEntity(util.vector.centerOf(2, 1, 2), m, new ItemStack(Items.TORCH)); + + scene.idle(30); + + scene.world.destroyBlock(util.grid.at(1, 1, 3)); + scene.world.createItemEntity(util.vector.centerOf(1, 1, 3), m, new ItemStack(Items.RAIL)); + scene.world.destroyBlock(util.grid.at(1, 1, 2)); + scene.world.createItemEntity(util.vector.centerOf(1, 1, 2), m, new ItemStack(Items.REDSTONE)); + + scene.overlay.showText(60) + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(1, 1, 3), Direction.EAST)) + .text("...they will break blocks without a solid collision hitbox"); + scene.idle(50); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.moveSection(pistonHead, util.vector.of(2, 0, 0), 40); + scene.world.moveSection(contraption, util.vector.of(2, 0, 0), 40); + scene.world.hideSection(garbage, Direction.UP); + scene.idle(40); + scene.world.setBlocks(garbage, Blocks.SNOW.getDefaultState(), false); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + ElementLink chest = + scene.world.showIndependentSection(util.select.position(4, 2, 2), Direction.DOWN); + + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(4, 2, 2), Direction.WEST)) + .sharedText("storage_on_contraption"); + scene.idle(15); + scene.effects.superGlue(util.grid.at(4, 2, 2), Direction.DOWN, true); + scene.idle(45); + scene.world.showSection(garbage, Direction.EAST); + scene.idle(20); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.moveSection(pistonHead, util.vector.of(-2, 0, 0), 60); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 60); + scene.world.moveSection(chest, util.vector.of(-2, 0, 0), 60); + scene.idle(15); + scene.world.destroyBlock(util.grid.at(2, 1, 3)); + scene.world.destroyBlock(util.grid.at(2, 1, 2)); + scene.idle(30); + scene.world.destroyBlock(util.grid.at(1, 1, 3)); + scene.world.destroyBlock(util.grid.at(1, 1, 2)); + scene.idle(15); + + scene.overlay.showControls( + new InputWindowElement(util.vector.topOf(2, 2, 2), Pointing.DOWN).withItem(new ItemStack(Items.SNOWBALL)), + 40); + scene.idle(40); + scene.world.hideIndependentSection(chest, Direction.UP); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.moveSection(pistonHead, util.vector.of(2, 0, 0), 40); + scene.world.moveSection(contraption, util.vector.of(2, 0, 0), 40); + scene.idle(40); + + Selection dirt = util.select.fromTo(2, 0, 3, 1, 0, 2); + scene.world.hideSection(dirt, Direction.DOWN); + scene.idle(15); + scene.world.setBlocks(dirt, Blocks.GRASS_BLOCK.getDefaultState(), false); + scene.world.showSection(dirt, Direction.UP); + scene.overlay.showText(60) + .placeNearTarget() + .attachKeyFrame() + .pointAt(util.vector.blockSurface(util.grid.at(3, 1, 3), Direction.EAST)) + .text("Additionally, ploughs can create farmland"); + scene.idle(30); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.moveSection(pistonHead, util.vector.of(-2, 0, 0), 60); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 60); + scene.world.moveSection(chest, util.vector.of(-2, 0, 0), 60); + scene.idle(15); + scene.world.setBlocks(util.select.fromTo(2, 0, 2, 2, 0, 3), Blocks.FARMLAND.getDefaultState(), true); + scene.idle(30); + scene.world.setBlocks(util.select.fromTo(1, 0, 2, 1, 0, 3), Blocks.FARMLAND.getDefaultState(), true); + scene.idle(20); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.world.moveSection(pistonHead, util.vector.of(2, 0, 0), 40); + scene.world.moveSection(contraption, util.vector.of(2, 0, 0), 40); + + scene.idle(50); + scene.world.setKineticSpeed(util.select.everywhere(), 0); + scene.world.hideSection(kinetics.substract(dynamic), Direction.EAST); + scene.world.hideSection(dirt, Direction.DOWN); + scene.world.hideIndependentSection(pistonHead, Direction.EAST); + scene.world.moveSection(cogs, util.vector.of(-1, 0, 0), 15); + scene.idle(15); + scene.world.restoreBlocks(dirt); + scene.world.showSection(dirt, Direction.UP); + scene.world.showSection(util.select.fromTo(4, 1, 6, 4, 3, 4), Direction.NORTH); + scene.idle(15); + scene.world.showSectionAndMerge(util.select.fromTo(4, 3, 3, 4, 2, 3), Direction.DOWN, contraption); + scene.idle(15); + + BlockPos bearingPos = util.grid.at(4, 3, 4); + scene.addKeyframe(); + + scene.world.setKineticSpeed(util.select.position(4, 0, 6), 8); + scene.world.setKineticSpeed(util.select.position(5, 1, 6), -16); + scene.world.setKineticSpeed(util.select.position(4, 3, 5), -16); + scene.world.setKineticSpeed(util.select.position(4, 1, 5), -16); + scene.world.setKineticSpeed(util.select.position(4, 2, 5), 16); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -2 * f); + scene.world.configureCenterOfRotation(contraption, util.vector.centerOf(bearingPos)); + scene.world.rotateSection(contraption, 0, 0, 90, 20); + scene.world.rotateBearing(bearingPos, 90, 20); + + scene.idle(10); + ElementLink birb = scene.special.createBirb(util.vector.topOf(3, 0, 2) + .add(0, 0, 0.5), FlappyPose::new); + scene.idle(11); + + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -2 * f); + scene.world.rotateSection(contraption, 0, 0, -135, 10); + scene.world.rotateBearing(bearingPos, -135, 10); + scene.idle(7); + scene.special.moveParrot(birb, util.vector.of(-20, 15, 0), 20); + scene.special.rotateParrot(birb, 0, 360, 0, 20); + scene.idle(3); + scene.world.setKineticSpeed(util.select.everywhere(), 0); + scene.idle(20); + + scene.overlay.showText(60) + .placeNearTarget() + .pointAt(util.vector.centerOf(util.grid.at(1, 3, 2))) + .text("...they can also launch entities without hurting them"); + scene.idle(30); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PistonScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PistonScenes.java new file mode 100644 index 000000000..28706d1fa --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PistonScenes.java @@ -0,0 +1,279 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonHeadBlock; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement.FaceCursorPose; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.Blocks; +import net.minecraft.block.DoublePlantBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.state.properties.DoubleBlockHalf; +import net.minecraft.state.properties.PistonType; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; + +public class PistonScenes { + + public static void movement(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_piston", "Moving Structures using Mechanical Pistons"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0) + .add(util.select.position(0, 1, 2)), Direction.UP); + + Selection kinetics = util.select.fromTo(3, 1, 3, 3, 1, 2); + BlockPos piston = util.grid.at(3, 1, 2); + BlockPos leverPos = util.grid.at(3, 2, 4); + BlockPos shaft = util.grid.at(3, 1, 3); + + scene.idle(5); + scene.world.showSection(util.select.fromTo(3, 1, 3, 3, 2, 5), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.position(piston), Direction.DOWN); + ElementLink contraption = + scene.world.showIndependentSection(util.select.position(3, 1, 1), Direction.DOWN); + scene.world.moveSection(contraption, util.vector.of(0, 0, 1), 0); + scene.idle(20); + scene.world.showSectionAndMerge(util.select.position(piston.north() + .east()), Direction.DOWN, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(piston.north() + .east(2)), Direction.DOWN, contraption); + scene.world.showSectionAndMerge(util.select.position(piston.north() + .west()), Direction.DOWN, contraption); + scene.idle(15); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.modifyKineticSpeed(kinetics, f -> -f); + scene.effects.rotationDirectionIndicator(shaft); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 40); + scene.overlay.showText(55) + .pointAt(util.vector.topOf(piston)) + .placeNearTarget() + .text("Mechanical Pistons can move blocks in front of them"); + scene.idle(65); + + scene.overlay.showText(45) + .pointAt(util.vector.blockSurface(shaft, Direction.SOUTH)) + .placeNearTarget() + .text("Speed and direction of movement depend on the Rotational Input"); + scene.world.setBlock(util.grid.at(2, 1, 1), Blocks.AIR.getDefaultState(), false); + scene.world.setBlock(util.grid.at(0, 1, 2), Blocks.OAK_PLANKS.getDefaultState(), false); + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.modifyKineticSpeed(kinetics, f -> -f); + scene.effects.rotationDirectionIndicator(shaft); + scene.world.moveSection(contraption, util.vector.of(2, 0, 0), 40); + scene.idle(60); + + scene.overlay.showControls( + new InputWindowElement(util.vector.blockSurface(piston, Direction.WEST), Pointing.DOWN).rightClick() + .withItem(new ItemStack(Items.SLIME_BALL)), + 30); + scene.idle(7); + scene.world.modifyBlock(piston.north(), s -> s.with(MechanicalPistonHeadBlock.TYPE, PistonType.STICKY), false); + scene.effects.superGlue(piston, Direction.WEST, true); + + scene.idle(33); + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.modifyKineticSpeed(kinetics, f -> -f); + scene.effects.rotationDirectionIndicator(shaft); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 40); + + scene.idle(25); + scene.overlay.showText(60) + .pointAt(util.vector.topOf(piston)) + .placeNearTarget() + .text("Sticky Mechanical Pistons can pull the attached blocks back"); + scene.idle(20); + scene.world.setBlock(util.grid.at(2, 1, 1), Blocks.OAK_PLANKS.getDefaultState(), false); + scene.world.setBlock(util.grid.at(0, 1, 2), Blocks.AIR.getDefaultState(), false); + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.modifyKineticSpeed(kinetics, f -> -f); + scene.effects.rotationDirectionIndicator(shaft); + scene.world.moveSection(contraption, util.vector.of(2, 0, 0), 40); + + scene.idle(50); + scene.world.setBlock(util.grid.at(2, 1, 1), Blocks.AIR.getDefaultState(), false); + ElementLink chassis = + scene.world.showIndependentSection(util.select.fromTo(2, 2, 0, 2, 3, 2), Direction.DOWN); + scene.world.moveSection(chassis, util.vector.of(0, -1, 1), 0); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(1, 2, 0), Direction.EAST, chassis); + scene.idle(15); + scene.effects.superGlue(piston.west() + .north(), Direction.WEST, true); + scene.overlay.showText(80) + .pointAt(util.vector.topOf(piston.west())) + .placeNearTarget() + .sharedText("movement_anchors"); + + scene.idle(90); + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.modifyKineticSpeed(kinetics, f -> -f); + scene.effects.rotationDirectionIndicator(shaft); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 40); + scene.world.moveSection(chassis, util.vector.of(-2, 0, 0), 40); + } + + public static void poles(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("piston_pole", "Piston Extension Poles"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + + Selection kinetics = util.select.fromTo(3, 1, 3, 3, 1, 2); + BlockPos piston = util.grid.at(3, 1, 2); + + scene.idle(5); + scene.world.showSection(util.select.fromTo(3, 1, 3, 3, 2, 5), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.position(piston), Direction.DOWN); + ElementLink contraption = + scene.world.showIndependentSection(util.select.position(3, 1, 1), Direction.DOWN); + scene.world.moveSection(contraption, util.vector.of(0, 0, 1), 0); + scene.idle(20); + + BlockPos leverPos = util.grid.at(3, 2, 4); + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.setKineticSpeed(kinetics, 16); + scene.idle(10); + + scene.overlay.showSelectionWithText(util.select.position(piston), 50) + .colored(PonderPalette.RED) + .placeNearTarget() + .text("Without attached Poles, a Mechanical Piston cannot move"); + scene.idle(60); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.setKineticSpeed(kinetics, 0); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(piston.north() + .east()), Direction.DOWN, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(piston.north() + .east(2)), Direction.DOWN, contraption); + scene.idle(10); + + scene.overlay.showOutline(PonderPalette.RED, new Object(), util.select.fromTo(piston.east(), piston.east(2)), + 100); + scene.overlay.showSelectionWithText(util.select.fromTo(piston.west(), piston.west(2)), 100) + .text("The Length of pole added at its back determines the Extension Range") + .placeNearTarget() + .colored(PonderPalette.GREEN); + scene.idle(110); + + scene.world.showSectionAndMerge(util.select.position(piston.north() + .west()), Direction.EAST, contraption); + scene.idle(10); + ElementLink birb = + scene.special.createBirb(util.vector.topOf(piston.west()), FaceCursorPose::new); + scene.idle(15); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.setKineticSpeed(kinetics, 16); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 40); + scene.special.moveParrot(birb, util.vector.of(-2, 0, 0), 40); + + } + + public static void movementModes(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("mechanical_piston_modes", "Movement Modes of the Mechanical Piston"); + scene.configureBasePlate(0, 0, 5); + Selection rose = util.select.fromTo(0, 2, 2, 0, 1, 2); + scene.world.showSection(util.select.layer(0) + .add(rose), Direction.UP); + + Selection kinetics = util.select.fromTo(3, 1, 3, 3, 1, 2); + BlockPos piston = util.grid.at(3, 1, 2); + BlockPos leverPos = util.grid.at(3, 2, 4); + BlockPos shaft = util.grid.at(3, 1, 3); + + scene.idle(5); + scene.world.showSection(util.select.fromTo(3, 1, 3, 3, 2, 5), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.position(piston), Direction.DOWN); + ElementLink contraption = + scene.world.showIndependentSection(util.select.position(3, 1, 1), Direction.DOWN); + scene.world.moveSection(contraption, util.vector.of(0, 0, 1), 0); + scene.idle(20); + scene.world.showSectionAndMerge(util.select.position(piston.north() + .east()), Direction.DOWN, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(piston.north() + .east(2)), Direction.DOWN, contraption); + scene.world.showSectionAndMerge(util.select.position(piston.north() + .west()), Direction.DOWN, contraption); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(piston.north() + .west() + .up()), Direction.DOWN, contraption); + scene.idle(15); + scene.effects.superGlue(piston.west(), Direction.UP, true); + scene.idle(10); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.modifyKineticSpeed(kinetics, f -> -f); + scene.effects.rotationDirectionIndicator(shaft); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 40); + scene.idle(40); + + scene.world.destroyBlock(util.grid.at(0, 1, 2)); + scene.world.destroyBlock(util.grid.at(0, 2, 2)); + scene.idle(10); + scene.overlay.showSelectionWithText(rose, 70) + .text("Whenever Pistons stop moving, the moved structure reverts to blocks") + .colored(PonderPalette.RED); + scene.idle(80); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.modifyKineticSpeed(kinetics, f -> -f); + scene.effects.rotationDirectionIndicator(shaft); + scene.world.moveSection(contraption, util.vector.of(2, 0, 0), 40); + scene.world.hideSection(rose, Direction.UP); + scene.idle(50); + + scene.world.setBlock(util.grid.at(0, 1, 2), Blocks.ROSE_BUSH.getDefaultState(), false); + scene.world.setBlock(util.grid.at(0, 2, 2), Blocks.ROSE_BUSH.getDefaultState() + .with(DoublePlantBlock.HALF, DoubleBlockHalf.UPPER), false); + scene.world.showIndependentSection(rose, Direction.DOWN); + scene.overlay.showCenteredScrollInput(piston, Direction.UP, 60); + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(piston), Pointing.DOWN).scroll() + .withWrench(), 60); + scene.overlay.showText(70) + .pointAt(util.vector.topOf(piston)) + .placeNearTarget() + .sharedText("behaviour_modify_wrench"); + scene.idle(80); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.world.modifyKineticSpeed(kinetics, f -> -f); + scene.effects.rotationDirectionIndicator(shaft); + scene.world.moveSection(contraption, util.vector.of(-2, 0, 0), 40); + scene.idle(50); + scene.overlay.showText(120) + .colored(PonderPalette.GREEN) + .pointAt(util.vector.blockSurface(util.grid.at(0, 1, 2), Direction.WEST)) + .placeNearTarget() + .text("It can be configured never to revert to solid blocks, or only at the location it started at"); + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderChapter.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderChapter.java new file mode 100644 index 000000000..a77388d12 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderChapter.java @@ -0,0 +1,53 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.Create; +import com.simibubi.create.foundation.gui.IScreenRenderable; +import com.simibubi.create.foundation.ponder.PonderRegistry; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.AbstractGui; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; + +public class PonderChapter implements IScreenRenderable { + + private final String id; + private final ResourceLocation icon; + + private PonderChapter(String id) { + this.id = id; + icon = new ResourceLocation(Create.ID, "textures/ponder/chapter/" + id + ".png"); + } + + @Override + public void draw(MatrixStack ms, AbstractGui screen, int x, int y) { + RenderSystem.pushMatrix(); + Minecraft.getInstance().getTextureManager().bindTexture(icon); + RenderSystem.scaled(0.25, 0.25, 1); + //x and y offset, blit z offset, tex x and y, tex width and height, entire tex sheet width and height + AbstractGui.drawTexture(ms, x, y, 0, 0, 0, 64, 64, 64, 64); + RenderSystem.popMatrix(); + } + + @Nonnull + public static PonderChapter of(String id) { + PonderChapter chapter = PonderRegistry.chapters.getChapter(id); + if (chapter == null) { + chapter = PonderRegistry.chapters.addChapter(new PonderChapter(id)); + } + + return chapter; + } + + public PonderChapter addTagsToChapter(PonderTag... tags) { + for (PonderTag t : tags) + PonderRegistry.tags.add(t, this); + return this; + } + + public String getId() { + return id; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderChapterRegistry.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderChapterRegistry.java new file mode 100644 index 000000000..66da66763 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderChapterRegistry.java @@ -0,0 +1,49 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.foundation.ponder.PonderStoryBoardEntry; +import com.simibubi.create.foundation.utility.Pair; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; +import java.util.stream.Collectors; + +public class PonderChapterRegistry { + + private final Map>> chapters; + + public PonderChapterRegistry() { + chapters = new HashMap<>(); + } + + public void addStoriesToChapter(@Nonnull PonderChapter chapter, PonderStoryBoardEntry... entries) { + chapters.get(chapter.getId()).getSecond().addAll(Arrays.asList(entries)); + } + + PonderChapter addChapter(@Nonnull PonderChapter chapter) { + chapters.put(chapter.getId(), Pair.of(chapter, new ArrayList<>())); + return chapter; + } + + @Nullable + PonderChapter getChapter(String id) { + Pair> pair = chapters.get(id); + if (pair == null) + return null; + + return pair.getFirst(); + } + + public List getAllChapters() { + return chapters + .values() + .stream() + .map(Pair::getFirst) + .collect(Collectors.toList()); + } + + public List getStories(PonderChapter chapter) { + return chapters.get(chapter.getId()).getSecond(); + } + +} 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 new file mode 100644 index 000000000..d5a31962b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java @@ -0,0 +1,356 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.foundation.ponder.PonderRegistry; + +import net.minecraft.block.Blocks; + +public class PonderIndex { + + public static final boolean EDITOR_MODE = true; + + public static void register() { + // Register storyboards here + // (!) Added entries require re-launch + // (!) Modifications inside storyboard methods only require re-opening the ui + + PonderRegistry.forComponents(AllBlocks.SHAFT) + .addStoryBoard("shaft/relay", KineticsScenes::shaftAsRelay, PonderTag.KINETIC_RELAYS); + PonderRegistry.forComponents(AllBlocks.SHAFT, AllBlocks.ANDESITE_ENCASED_SHAFT, AllBlocks.BRASS_ENCASED_SHAFT) + .addStoryBoard("shaft/encasing", KineticsScenes::shaftsCanBeEncased); + + PonderRegistry.forComponents(AllBlocks.COGWHEEL) + .addStoryBoard("cog/small", KineticsScenes::cogAsRelay, PonderTag.KINETIC_RELAYS) + .addStoryBoard("cog/speedup", KineticsScenes::cogsSpeedUp); + + PonderRegistry.forComponents(AllBlocks.LARGE_COGWHEEL) + .addStoryBoard("cog/speedup", KineticsScenes::cogsSpeedUp) + .addStoryBoard("cog/large", KineticsScenes::largeCogAsRelay, PonderTag.KINETIC_RELAYS); + + PonderRegistry.forComponents(AllItems.BELT_CONNECTOR) + .addStoryBoard("belt/connect", BeltScenes::beltConnector, PonderTag.KINETIC_RELAYS) + .addStoryBoard("belt/directions", BeltScenes::directions) + .addStoryBoard("belt/transport", BeltScenes::transport, PonderTag.LOGISTICS) + .addStoryBoard("belt/encasing", BeltScenes::beltsCanBeEncased); + + PonderRegistry.forComponents(AllBlocks.ANDESITE_CASING, AllBlocks.BRASS_CASING) + .addStoryBoard("shaft/encasing", KineticsScenes::shaftsCanBeEncased) + .addStoryBoard("belt/encasing", BeltScenes::beltsCanBeEncased); + + PonderRegistry.forComponents(AllBlocks.GEARBOX, AllItems.VERTICAL_GEARBOX) + .addStoryBoard("gearbox", KineticsScenes::gearbox, PonderTag.KINETIC_RELAYS); + + PonderRegistry.addStoryBoard(AllBlocks.CLUTCH, "clutch", KineticsScenes::clutch, PonderTag.KINETIC_RELAYS); + PonderRegistry.addStoryBoard(AllBlocks.GEARSHIFT, "gearshift", KineticsScenes::gearshift, + PonderTag.KINETIC_RELAYS); + + PonderRegistry.forComponents(AllBlocks.SEQUENCED_GEARSHIFT) + .addStoryBoard("sequenced_gearshift", KineticsScenes::sequencedGearshift); + + PonderRegistry.forComponents(AllBlocks.ENCASED_FAN) + .addStoryBoard("fan/direction", FanScenes::direction, PonderTag.KINETIC_APPLIANCES) + .addStoryBoard("fan/processing", FanScenes::processing) + .addStoryBoard("fan/source", FanScenes::source, PonderTag.KINETIC_SOURCES); + + PonderRegistry.addStoryBoard(AllBlocks.CREATIVE_MOTOR, "creative_motor", KineticsScenes::creativeMotor, + PonderTag.KINETIC_SOURCES); + PonderRegistry.addStoryBoard(AllBlocks.WATER_WHEEL, "water_wheel", KineticsScenes::waterWheel, + PonderTag.KINETIC_SOURCES); + PonderRegistry.addStoryBoard(AllBlocks.HAND_CRANK, "hand_crank", KineticsScenes::handCrank, + PonderTag.KINETIC_SOURCES); + + PonderRegistry.addStoryBoard(AllBlocks.COPPER_VALVE_HANDLE, "valve_handle", KineticsScenes::valveHandle, + PonderTag.KINETIC_SOURCES); + PonderRegistry.forComponents(AllBlocks.DYED_VALVE_HANDLES) + .addStoryBoard("valve_handle", KineticsScenes::valveHandle); + + PonderRegistry.addStoryBoard(AllBlocks.ENCASED_CHAIN_DRIVE, "chain_drive/relay", + ChainDriveScenes::chainDriveAsRelay, PonderTag.KINETIC_RELAYS); + PonderRegistry.forComponents(AllBlocks.ENCASED_CHAIN_DRIVE, AllBlocks.ADJUSTABLE_CHAIN_GEARSHIFT) + .addStoryBoard("chain_drive/gearshift", ChainDriveScenes::adjustableChainGearshift); + + PonderRegistry.forComponents(AllBlocks.FURNACE_ENGINE) + .addStoryBoard("furnace_engine", KineticsScenes::furnaceEngine); + PonderRegistry.forComponents(AllBlocks.FLYWHEEL) + .addStoryBoard("furnace_engine", KineticsScenes::flywheel); + PonderRegistry.forComponents(AllBlocks.ROTATION_SPEED_CONTROLLER) + .addStoryBoard("speed_controller", KineticsScenes::speedController); + + // Funnels + PonderRegistry.addStoryBoard(AllBlocks.BRASS_FUNNEL, "funnels/brass", FunnelScenes::brass); + PonderRegistry.forComponents(AllBlocks.ANDESITE_FUNNEL, AllBlocks.BRASS_FUNNEL) + .addStoryBoard("funnels/intro", FunnelScenes::intro, PonderTag.LOGISTICS) + .addStoryBoard("funnels/direction", FunnelScenes::directionality) + .addStoryBoard("funnels/compat", FunnelScenes::compat) + .addStoryBoard("funnels/redstone", FunnelScenes::redstone) + .addStoryBoard("funnels/transposer", FunnelScenes::transposer); + PonderRegistry.addStoryBoard(AllBlocks.ANDESITE_FUNNEL, "funnels/brass", FunnelScenes::brass); + + // Chassis & Super Glue + PonderRegistry.forComponents(AllBlocks.LINEAR_CHASSIS, AllBlocks.SECONDARY_LINEAR_CHASSIS) + .addStoryBoard("chassis/linear_group", ChassisScenes::linearGroup, PonderTag.CONTRAPTION_ASSEMBLY) + .addStoryBoard("chassis/linear_attachment", ChassisScenes::linearAttachement); + PonderRegistry.forComponents(AllBlocks.RADIAL_CHASSIS) + .addStoryBoard("chassis/radial", ChassisScenes::radial, PonderTag.CONTRAPTION_ASSEMBLY); + PonderRegistry.forComponents(AllItems.SUPER_GLUE) + .addStoryBoard("super_glue", ChassisScenes::superGlue, PonderTag.CONTRAPTION_ASSEMBLY); + PonderRegistry.forComponents(AllBlocks.STICKER) + .addStoryBoard("sticker", RedstoneScenes::sticker, PonderTag.CONTRAPTION_ASSEMBLY); + + // Mechanical Piston + PonderRegistry.forComponents(AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON) + .addStoryBoard("mechanical_piston/anchor", PistonScenes::movement, PonderTag.KINETIC_APPLIANCES, + PonderTag.MOVEMENT_ANCHOR); + PonderRegistry + .forComponents(AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON, + AllBlocks.PISTON_EXTENSION_POLE) + .addStoryBoard("mechanical_piston/piston_pole", PistonScenes::poles); + PonderRegistry.forComponents(AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON) + .addStoryBoard("mechanical_piston/modes", PistonScenes::movementModes); + + // Windmill Bearing + PonderRegistry.forComponents(AllBlocks.ROPE_PULLEY) + .addStoryBoard("rope_pulley/anchor", PulleyScenes::movement, PonderTag.KINETIC_APPLIANCES, + PonderTag.MOVEMENT_ANCHOR) + .addStoryBoard("rope_pulley/modes", PulleyScenes::movementModes) + .addStoryBoard("rope_pulley/attachment", PulleyScenes::attachment); + + // Windmill Bearing + PonderRegistry.forComponents(AllBlocks.WINDMILL_BEARING) + .addStoryBoard("windmill_bearing/source", BearingScenes::windmillsAsSource, PonderTag.KINETIC_SOURCES) + .addStoryBoard("windmill_bearing/structure", BearingScenes::windmillsAnyStructure, + PonderTag.MOVEMENT_ANCHOR); + + // Mechanical Bearing + PonderRegistry.forComponents(AllBlocks.MECHANICAL_BEARING) + .addStoryBoard("mechanical_bearing/anchor", BearingScenes::mechanicalBearing, PonderTag.KINETIC_APPLIANCES, + PonderTag.MOVEMENT_ANCHOR) + .addStoryBoard("mechanical_bearing/modes", BearingScenes::bearingModes) + .addStoryBoard("mechanical_bearing/stabilized", BearingScenes::stabilizedBearings, + PonderTag.CONTRAPTION_ACTOR); + + // Clockwork Bearing + PonderRegistry.addStoryBoard(AllBlocks.CLOCKWORK_BEARING, "clockwork_bearing", BearingScenes::clockwork, + PonderTag.KINETIC_APPLIANCES, PonderTag.MOVEMENT_ANCHOR); + + // Gantries + PonderRegistry.addStoryBoard(AllBlocks.GANTRY_SHAFT, "gantry/intro", GantryScenes::introForShaft, + PonderTag.KINETIC_APPLIANCES, PonderTag.MOVEMENT_ANCHOR); + PonderRegistry.addStoryBoard(AllBlocks.GANTRY_CARRIAGE, "gantry/intro", GantryScenes::introForPinion, + PonderTag.KINETIC_APPLIANCES, PonderTag.MOVEMENT_ANCHOR); + PonderRegistry.forComponents(AllBlocks.GANTRY_SHAFT, AllBlocks.GANTRY_CARRIAGE) + .addStoryBoard("gantry/redstone", GantryScenes::redstone) + .addStoryBoard("gantry/direction", GantryScenes::direction) + .addStoryBoard("gantry/subgantry", GantryScenes::subgantry); + + // Cart Assembler + PonderRegistry.forComponents(AllBlocks.CART_ASSEMBLER) + .addStoryBoard("cart_assembler/anchor", CartAssemblerScenes::anchor, PonderTag.MOVEMENT_ANCHOR) + .addStoryBoard("cart_assembler/modes", CartAssemblerScenes::modes) + .addStoryBoard("cart_assembler/dual", CartAssemblerScenes::dual) + .addStoryBoard("cart_assembler/rails", CartAssemblerScenes::rails); + + // Movement Actors + PonderRegistry.forComponents(AllBlocks.PORTABLE_STORAGE_INTERFACE) + .addStoryBoard("portable_interface/transfer", MovementActorScenes::psiTransfer, PonderTag.CONTRAPTION_ACTOR) + .addStoryBoard("portable_interface/redstone", MovementActorScenes::psiRedstone); + PonderRegistry.forComponents(AllBlocks.REDSTONE_CONTACT) + .addStoryBoard("redstone_contact", RedstoneScenes::contact); + PonderRegistry.forComponents(AllBlocks.MECHANICAL_SAW) + .addStoryBoard("mechanical_saw/processing", MechanicalSawScenes::processing, PonderTag.KINETIC_APPLIANCES) + .addStoryBoard("mechanical_saw/breaker", MechanicalSawScenes::treeCutting) + .addStoryBoard("mechanical_saw/contraption", MechanicalSawScenes::contraption, PonderTag.CONTRAPTION_ACTOR); + PonderRegistry.forComponents(AllBlocks.MECHANICAL_DRILL) + .addStoryBoard("mechanical_drill/breaker", MechanicalDrillScenes::breaker, PonderTag.KINETIC_APPLIANCES) + .addStoryBoard("mechanical_drill/contraption", MechanicalDrillScenes::contraption, + PonderTag.CONTRAPTION_ACTOR); + PonderRegistry.forComponents(AllBlocks.DEPLOYER) + .addStoryBoard("deployer/filter", DeployerScenes::filter, PonderTag.KINETIC_APPLIANCES) + .addStoryBoard("deployer/modes", DeployerScenes::modes) + .addStoryBoard("deployer/redstone", DeployerScenes::redstone) + .addStoryBoard("deployer/contraption", DeployerScenes::contraption, PonderTag.CONTRAPTION_ACTOR); + PonderRegistry.forComponents(AllBlocks.MECHANICAL_HARVESTER) + .addStoryBoard("harvester", MovementActorScenes::harvester); + PonderRegistry.forComponents(AllBlocks.MECHANICAL_PLOUGH) + .addStoryBoard("plough", MovementActorScenes::plough); + + // Redstone + PonderRegistry.forComponents(AllBlocks.PULSE_REPEATER) + .addStoryBoard("pulse_repeater", RedstoneScenes::pulseRepeater); + PonderRegistry.forComponents(AllBlocks.ADJUSTABLE_REPEATER) + .addStoryBoard("adjustable_repeater", RedstoneScenes::adjustableRepeater); + PonderRegistry.forComponents(AllBlocks.ADJUSTABLE_PULSE_REPEATER) + .addStoryBoard("adjustable_pulse_repeater", RedstoneScenes::adjustablePulseRepeater); + PonderRegistry.forComponents(AllBlocks.POWERED_LATCH) + .addStoryBoard("powered_latch", RedstoneScenes::poweredLatch); + PonderRegistry.forComponents(AllBlocks.POWERED_TOGGLE_LATCH) + .addStoryBoard("powered_toggle_latch", RedstoneScenes::poweredToggleLatch); + PonderRegistry.forComponents(AllBlocks.ANALOG_LEVER) + .addStoryBoard("analog_lever", RedstoneScenes::analogLever); + PonderRegistry.forComponents(AllBlocks.NIXIE_TUBE) + .addStoryBoard("nixie_tube", RedstoneScenes::nixieTube); + PonderRegistry.forComponents(AllBlocks.REDSTONE_LINK) + .addStoryBoard("redstone_link", RedstoneScenes::redstoneLink); + + // Debug scenes, can be found in game via the Brass Hand + if (EDITOR_MODE) + DebugScenes.registerAll(); + } + + public static void registerTags() { + // Add items to tags here + + PonderRegistry.tags.forTag(PonderTag.KINETIC_RELAYS) + .add(AllBlocks.SHAFT) + .add(AllBlocks.COGWHEEL) + .add(AllBlocks.LARGE_COGWHEEL) + .add(AllItems.BELT_CONNECTOR) + .add(AllBlocks.GEARBOX) + .add(AllBlocks.CLUTCH) + .add(AllBlocks.GEARSHIFT) + .add(AllBlocks.ENCASED_CHAIN_DRIVE) + .add(AllBlocks.ADJUSTABLE_CHAIN_GEARSHIFT) + .add(AllBlocks.SEQUENCED_GEARSHIFT) + .add(AllBlocks.ROTATION_SPEED_CONTROLLER); + + PonderRegistry.tags.forTag(PonderTag.KINETIC_SOURCES) + .add(AllBlocks.HAND_CRANK) + .add(AllBlocks.COPPER_VALVE_HANDLE) + .add(AllBlocks.WATER_WHEEL) + .add(AllBlocks.ENCASED_FAN) + .add(AllBlocks.WINDMILL_BEARING) + .add(AllBlocks.FURNACE_ENGINE) + .add(AllBlocks.FLYWHEEL) + .add(AllBlocks.CREATIVE_MOTOR); + + PonderRegistry.tags.forTag(PonderTag.KINETIC_APPLIANCES) + .add(AllBlocks.MILLSTONE) + .add(AllBlocks.TURNTABLE) + .add(AllBlocks.ENCASED_FAN) + .add(AllBlocks.CUCKOO_CLOCK) + .add(AllBlocks.MECHANICAL_PRESS) + .add(AllBlocks.MECHANICAL_MIXER) + .add(AllBlocks.MECHANICAL_CRAFTER) + .add(AllBlocks.MECHANICAL_DRILL) + .add(AllBlocks.MECHANICAL_SAW) + .add(AllBlocks.DEPLOYER) + .add(AllBlocks.MECHANICAL_PUMP) + .add(AllBlocks.MECHANICAL_ARM) + .add(AllBlocks.MECHANICAL_PISTON) + .add(AllBlocks.ROPE_PULLEY) + .add(AllBlocks.MECHANICAL_BEARING) + .add(AllBlocks.GANTRY_SHAFT) + .add(AllBlocks.GANTRY_CARRIAGE) + .add(AllBlocks.CLOCKWORK_BEARING) + .add(AllBlocks.CRUSHING_WHEEL); + + PonderRegistry.tags.forTag(PonderTag.FLUIDS) + .add(AllBlocks.FLUID_PIPE) + .add(AllBlocks.MECHANICAL_PUMP) + .add(AllBlocks.FLUID_VALVE) + .add(AllBlocks.SMART_FLUID_PIPE) + .add(AllBlocks.HOSE_PULLEY) + .add(AllBlocks.ITEM_DRAIN) + .add(AllBlocks.SPOUT) + .add(AllBlocks.PORTABLE_FLUID_INTERFACE) + .add(AllBlocks.FLUID_TANK) + .add(AllBlocks.CREATIVE_FLUID_TANK); + + PonderRegistry.tags.forTag(PonderTag.ARM_TARGETS) + .add(AllItems.BELT_CONNECTOR) + .add(AllBlocks.CHUTE) + .add(AllBlocks.DEPOT) + .add(AllBlocks.BASIN) + .add(AllBlocks.ANDESITE_FUNNEL) + .add(AllBlocks.BRASS_FUNNEL) + .add(AllBlocks.MECHANICAL_CRAFTER) + .add(AllBlocks.MILLSTONE) + .add(AllBlocks.DEPLOYER) + .add(AllBlocks.MECHANICAL_SAW) + .add(Blocks.COMPOSTER) + .add(AllBlocks.BLAZE_BURNER) + .add(Blocks.JUKEBOX) + .add(AllBlocks.CRUSHING_WHEEL); + + PonderRegistry.tags.forTag(PonderTag.LOGISTICS) + .add(AllItems.BELT_CONNECTOR) + .add(AllItems.FILTER) + .add(AllItems.ATTRIBUTE_FILTER) + .add(AllBlocks.CHUTE) + .add(AllBlocks.SMART_CHUTE) + .add(AllBlocks.DEPOT) + .add(AllBlocks.MECHANICAL_ARM) + .add(AllBlocks.ANDESITE_FUNNEL) + .add(AllBlocks.BRASS_FUNNEL) + .add(AllBlocks.ANDESITE_TUNNEL) + .add(AllBlocks.BRASS_TUNNEL) + .add(AllBlocks.CONTENT_OBSERVER) + .add(AllBlocks.STOCKPILE_SWITCH) + .add(AllBlocks.ADJUSTABLE_CRATE) + .add(AllBlocks.CREATIVE_CRATE) + .add(AllBlocks.PORTABLE_STORAGE_INTERFACE); + + PonderRegistry.tags.forTag(PonderTag.DECORATION) + .add(AllBlocks.NIXIE_TUBE) + .add(AllBlocks.CUCKOO_CLOCK) + .add(AllBlocks.WOODEN_BRACKET) + .add(AllBlocks.METAL_BRACKET) + .add(AllBlocks.ANDESITE_CASING) + .add(AllBlocks.BRASS_CASING) + .add(AllBlocks.COPPER_CASING); + + PonderRegistry.tags.forTag(PonderTag.CREATIVE) + .add(AllBlocks.CREATIVE_CRATE) + .add(AllBlocks.CREATIVE_FLUID_TANK) + .add(AllBlocks.CREATIVE_MOTOR); + + PonderRegistry.tags.forTag(PonderTag.REDSTONE) + .add(AllBlocks.NIXIE_TUBE) + .add(AllBlocks.REDSTONE_CONTACT) + .add(AllBlocks.ANALOG_LEVER) + .add(AllBlocks.REDSTONE_LINK) + .add(AllBlocks.ADJUSTABLE_REPEATER) + .add(AllBlocks.PULSE_REPEATER) + .add(AllBlocks.ADJUSTABLE_PULSE_REPEATER) + .add(AllBlocks.POWERED_LATCH) + .add(AllBlocks.POWERED_TOGGLE_LATCH); + + PonderRegistry.tags.forTag(PonderTag.MOVEMENT_ANCHOR) + .add(AllBlocks.MECHANICAL_PISTON) + .add(AllBlocks.WINDMILL_BEARING) + .add(AllBlocks.MECHANICAL_BEARING) + .add(AllBlocks.CLOCKWORK_BEARING) + .add(AllBlocks.ROPE_PULLEY) + .add(AllBlocks.GANTRY_CARRIAGE) + .add(AllBlocks.CART_ASSEMBLER); + + PonderRegistry.tags.forTag(PonderTag.CONTRAPTION_ASSEMBLY) + .add(AllBlocks.LINEAR_CHASSIS) + .add(AllBlocks.SECONDARY_LINEAR_CHASSIS) + .add(AllBlocks.RADIAL_CHASSIS) + .add(AllItems.SUPER_GLUE) + .add(AllBlocks.STICKER) + .add(Blocks.SLIME_BLOCK) + .add(Blocks.HONEY_BLOCK); + + PonderRegistry.tags.forTag(PonderTag.CONTRAPTION_ACTOR) + .add(AllBlocks.MECHANICAL_HARVESTER) + .add(AllBlocks.MECHANICAL_PLOUGH) + .add(AllBlocks.MECHANICAL_DRILL) + .add(AllBlocks.MECHANICAL_SAW) + .add(AllBlocks.DEPLOYER) + .add(AllBlocks.PORTABLE_STORAGE_INTERFACE) + .add(AllBlocks.PORTABLE_FLUID_INTERFACE) + .add(AllBlocks.MECHANICAL_BEARING) + .add(AllBlocks.ANDESITE_FUNNEL) + .add(AllBlocks.BRASS_FUNNEL) + .add(AllBlocks.SEATS[0]) + .add(AllBlocks.REDSTONE_CONTACT) + .add(Blocks.BELL) + .add(Blocks.DISPENSER) + .add(Blocks.DROPPER); + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndexScreen.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndexScreen.java new file mode 100644 index 000000000..9e302619d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndexScreen.java @@ -0,0 +1,226 @@ +package com.simibubi.create.foundation.ponder.content; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import com.mojang.blaze3d.matrix.MatrixStack; +import org.apache.commons.lang3.mutable.MutableBoolean; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.components.crank.ValveHandleBlock; +import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import com.simibubi.create.foundation.ponder.NavigatableSimiScreen; +import com.simibubi.create.foundation.ponder.PonderRegistry; +import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.ponder.ui.ChapterLabel; +import com.simibubi.create.foundation.ponder.ui.LayoutHelper; +import com.simibubi.create.foundation.ponder.ui.PonderButton; + +import net.minecraft.block.Block; +import net.minecraft.client.MainWindow; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.renderer.Rectangle2d; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.registries.ForgeRegistries; + +public class PonderIndexScreen extends NavigatableSimiScreen { + + protected final List chapters; + private final double chapterXmult = 0.5; + private final double chapterYmult = 0.3; + protected Rectangle2d chapterArea; + + protected final List items; + private final double itemXmult = 0.5; + private double itemYmult = 0.75; + protected Rectangle2d itemArea; + + private ItemStack hoveredItem = ItemStack.EMPTY; + + public PonderIndexScreen() { + chapters = new ArrayList<>(); + items = new ArrayList<>(); + } + + @Override + protected void init() { + widgets.clear(); + super.init(); + + chapters.clear(); + // chapters.addAll(PonderRegistry.chapters.getAllChapters()); + + items.clear(); + PonderRegistry.all.keySet() + .stream() + .map(key -> { + Item item = ForgeRegistries.ITEMS.getValue(key); + if (item == null) { + Block b = ForgeRegistries.BLOCKS.getValue(key); + if (b != null) + item = b.asItem(); + } + return item; + }) + .filter(Objects::nonNull) + .filter(PonderIndexScreen::exclusions) + .forEach(items::add); + + boolean hasChapters = !chapters.isEmpty(); + + // setup chapters + LayoutHelper layout = LayoutHelper.centeredHorizontal(chapters.size(), + MathHelper.clamp((int) Math.ceil(chapters.size() / 4f), 1, 4), 200, 38, 16); + chapterArea = layout.getArea(); + int chapterCenterX = (int) (width * chapterXmult); + int chapterCenterY = (int) (height * chapterYmult); + + // todo at some point pagination or horizontal scrolling may be needed for + // chapters/items + for (PonderChapter chapter : chapters) { + ChapterLabel label = new ChapterLabel(chapter, chapterCenterX + layout.getX(), + chapterCenterY + layout.getY(), (mouseX, mouseY) -> { + centerScalingOn(mouseX, mouseY); + ScreenOpener.transitionTo(PonderUI.of(chapter)); + }); + + widgets.add(label); + layout.next(); + } + + // setup items + if (!hasChapters) { + itemYmult = 0.5; + } + + int maxItemRows = hasChapters ? 4 : 7; + layout = LayoutHelper.centeredHorizontal(items.size(), + MathHelper.clamp((int) Math.ceil(items.size() / 11f), 1, maxItemRows), 28, 28, 8); + itemArea = layout.getArea(); + int itemCenterX = (int) (width * itemXmult); + int itemCenterY = (int) (height * itemYmult); + + for (Item item : items) { + PonderButton button = + new PonderButton(itemCenterX + layout.getX() + 4, itemCenterY + layout.getY() + 4, (x, y) -> { + if (!PonderRegistry.all.containsKey(item.getRegistryName())) + return; + + centerScalingOn(x, y); + ScreenOpener.transitionTo(PonderUI.of(new ItemStack(item))); + }).showing(new ItemStack(item)); + + button.fade(1); + widgets.add(button); + layout.next(); + } + + } + + private static boolean exclusions(Item item) { + if (item instanceof BlockItem) { + Block block = ((BlockItem) item).getBlock(); + if (block instanceof ValveHandleBlock && !AllBlocks.COPPER_VALVE_HANDLE.is(item)) + return false; + } + + return true; + } + + @Override + public void tick() { + super.tick(); + PonderUI.ponderTicks++; + + hoveredItem = ItemStack.EMPTY; + MainWindow w = client.getWindow(); + double mouseX = client.mouseHelper.getMouseX() * w.getScaledWidth() / w.getWidth(); + double mouseY = client.mouseHelper.getMouseY() * w.getScaledHeight() / w.getHeight(); + for (Widget widget : widgets) { + if (widget instanceof PonderButton) + if (widget.isMouseOver(mouseX, mouseY)) { + hoveredItem = ((PonderButton) widget).getItem(); + } + } + } + + @Override + protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + int x = (int) (width * chapterXmult); + int y = (int) (height * chapterYmult); + + if (!chapters.isEmpty()) { + RenderSystem.pushMatrix(); + RenderSystem.translated(x, y, 0); + + UIRenderHelper.streak(ms, 0, chapterArea.getX() - 10, chapterArea.getY() - 20, 20, 220, 0x101010); + textRenderer.draw(ms, "Topics to Ponder about", chapterArea.getX() - 5, chapterArea.getY() - 25, 0xffddeeff); + + RenderSystem.popMatrix(); + } + + x = (int) (width * itemXmult); + y = (int) (height * itemYmult); + + RenderSystem.pushMatrix(); + RenderSystem.translated(x, y, 0); + + UIRenderHelper.streak(ms, 0, itemArea.getX() - 10, itemArea.getY() - 20, 20, 220, 0x101010); + textRenderer.draw(ms, "Items to inspect", itemArea.getX() - 5, itemArea.getY() - 25, 0xffddeeff); + + RenderSystem.popMatrix(); + } + + @Override + protected void renderWindowForeground(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + if (hoveredItem.isEmpty()) + return; + + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, 200); + + renderTooltip(ms, hoveredItem, mouseX, mouseY); + + RenderSystem.popMatrix(); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + MutableBoolean handled = new MutableBoolean(false); + widgets.forEach(w -> { + if (handled.booleanValue()) + return; + if (!w.isMouseOver(x, y)) + return; + if (w instanceof PonderButton) { + PonderButton btn = (PonderButton) w; + btn.runCallback(x, y); + handled.setTrue(); + } + }); + + if (handled.booleanValue()) + return true; + return super.mouseClicked(x, y, button); + } + + @Override + public boolean isEquivalentTo(NavigatableSimiScreen other) { + return other instanceof PonderIndexScreen; + } + + public ItemStack getHoveredTooltipItem() { + return hoveredItem; + } + + @Override + public boolean isPauseScreen() { + return true; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderPalette.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderPalette.java new file mode 100644 index 000000000..ede4108ed --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderPalette.java @@ -0,0 +1,27 @@ +package com.simibubi.create.foundation.ponder.content; + +public enum PonderPalette { + + WHITE(0xFF_eeeeee), + BLACK(0xFF_221111), + + RED(0xFF_ff5d6c), + GREEN(0xFF_8cba51), + BLUE(0xFF_5f6caf), + + SLOW(0xFF_22ff22), + MEDIUM(0xFF_0084ff), + FAST(0xFF_ff55ff), + + ; + + private int color; + + private PonderPalette(int color) { + this.color = color; + } + + public int getColor() { + return color; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTag.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTag.java new file mode 100644 index 000000000..6f7deba08 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTag.java @@ -0,0 +1,159 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.foundation.gui.GuiGameElement; +import com.simibubi.create.foundation.gui.IScreenRenderable; +import com.simibubi.create.foundation.ponder.PonderLocalization; + +import net.minecraft.block.Blocks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.AbstractGui; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.IItemProvider; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class PonderTag implements IScreenRenderable { + + // + + public static final PonderTag + + KINETIC_RELAYS = new PonderTag("kinetic_relays").item(AllBlocks.COGWHEEL.get(), true, false) + .defaultLang("Kinetic Blocks", "Components which help relaying Rotational Force elsewhere"), + + KINETIC_SOURCES = new PonderTag("kinetic_sources").item(AllBlocks.WATER_WHEEL.get(), true, false) + .defaultLang("Kinetic Sources", "Components which generate Rotational Force"), + + KINETIC_APPLIANCES = new PonderTag("kinetic_appliances").item(AllBlocks.MECHANICAL_PRESS.get(), true, false) + .defaultLang("Kinetic Appliances", "Components which make use of Rotational Force"), + + FLUIDS = new PonderTag("fluids").item(AllBlocks.FLUID_PIPE.get(), true, false) + .defaultLang("Fluid Manipulators", "Components which help relaying and making use of Fluids"), + + LOGISTICS = new PonderTag("logistics").item(Blocks.CHEST, true, false) + .defaultLang("Item Transportation", "Components which help moving items around"), + + REDSTONE = new PonderTag("redstone").item(Items.REDSTONE, true, false) + .defaultLang("Logic Components", "Components which help with redstone engineering"), + + DECORATION = new PonderTag("decoration").item(Items.ROSE_BUSH, true, false) + .defaultLang("Aesthetics", "Components used mostly for decorative purposes"), + + CREATIVE = new PonderTag("creative").item(AllBlocks.CREATIVE_CRATE.get(), true, false) + .defaultLang("Creative Mode", "Components not usually available for Survival Mode"), + + MOVEMENT_ANCHOR = new PonderTag("movement_anchor").item(AllBlocks.MECHANICAL_PISTON.get(), true, false) + .defaultLang("Movement Anchors", + "Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways"), + + CONTRAPTION_ACTOR = new PonderTag("contraption_actor").item(AllBlocks.MECHANICAL_HARVESTER.get(), true, false) + .defaultLang("Contraption Actors", + "Components which expose special behaviour when attached to a moving contraption"), + + CONTRAPTION_ASSEMBLY = new PonderTag("contraption_assembly").item(AllItems.SUPER_GLUE.get(), true, false) + .defaultLang("Block Attachment Utility", + "Tools and Components used to assemble structures moved as an animated Contraption"), + +// FLUID_TRANSFER = new PonderTag("fluid_transfer").idAsIcon(), +// +// OPEN_INVENTORY = new PonderTag("open_inventory").item(AllBlocks.BASIN.get() +// .asItem()), +// +// REDSTONE_CONTROL = new PonderTag("redstone_control").item(Items.REDSTONE, true, false), +// +// ITEM_TRANSFER = new PonderTag("item_transfer").idAsIcon(), + + ARM_TARGETS = new PonderTag("arm_targets").item(AllBlocks.MECHANICAL_ARM.get()) + .defaultLang("Targets for Mechanical Arms", + "Components which can be selected as inputs or outputs to the Mechanical Arm"); + + public static class Highlight { + public static final PonderTag ALL = new PonderTag("_all"); + } + + // + + private final String id; + private ResourceLocation icon; + private ItemStack itemIcon = ItemStack.EMPTY; + private ItemStack mainItem = ItemStack.EMPTY; + + public String getTitle() { + return PonderLocalization.getTag(id); + } + + public String getDescription() { + return PonderLocalization.getTagDescription(id); + } + + // Builder + + public PonderTag(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public PonderTag defaultLang(String title, String description) { + PonderLocalization.registerTag(id, title, description); + return this; + } + + public ItemStack getMainItem() { + return mainItem; + } + + public PonderTag idAsIcon() { + return icon(id); + } + + public PonderTag icon(String location) { + this.icon = new ResourceLocation(com.simibubi.create.Create.ID, "textures/ponder/tag/" + location + ".png"); + return this; + } + + public PonderTag item(IItemProvider item) { + return this.item(item, true, true); + } + + public PonderTag item(IItemProvider item, boolean useAsIcon, boolean useAsMainItem) { + if (useAsIcon) + this.itemIcon = new ItemStack(item); + if (useAsMainItem) + this.mainItem = new ItemStack(item); + return this; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void draw(MatrixStack ms, AbstractGui screen, int x, int y) { + RenderSystem.pushMatrix(); + RenderSystem.translated(x, y, 0); + if (icon != null) { + Minecraft.getInstance() + .getTextureManager() + .bindTexture(icon); + RenderSystem.scaled(0.25, 0.25, 1); + // x and y offset, blit z offset, tex x and y, tex width and height, entire tex sheet width and height + AbstractGui.drawTexture(ms, 0, 0, 0, 0, 0, 64, 64, 64, 64); + } else if (!itemIcon.isEmpty()) { + RenderSystem.translated(-4, -4, 0); + RenderSystem.scaled(1.5, 1.5, 1.5); + GuiGameElement.of(itemIcon) + .render(ms); + } + RenderSystem.popMatrix(); + } + + // Load class + public static void register() {} + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagRegistry.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagRegistry.java new file mode 100644 index 000000000..9ff0a6763 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagRegistry.java @@ -0,0 +1,104 @@ +package com.simibubi.create.foundation.ponder.content; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import com.simibubi.create.foundation.ponder.PonderRegistry; +import com.tterrag.registrate.util.entry.ItemProviderEntry; + +import net.minecraft.util.IItemProvider; +import net.minecraft.util.ResourceLocation; + +public class PonderTagRegistry { + + private final Multimap tags; + private final Multimap chapterTags; + + public PonderTagRegistry() { + tags = LinkedHashMultimap.create(); + chapterTags = LinkedHashMultimap.create(); + } + + public Set getTags(ResourceLocation item) { + return ImmutableSet.copyOf(tags.get(item)); + } + + public Set getTags(PonderChapter chapter) { + return ImmutableSet.copyOf(chapterTags.get(chapter)); + } + + public Set getItems(PonderTag tag) { + return tags.entries() + .stream() + .filter(e -> e.getValue() == tag) + .map(Map.Entry::getKey) + .collect(ImmutableSet.toImmutableSet()); + } + + public Set getChapters(PonderTag tag) { + return chapterTags.entries() + .stream() + .filter(e -> e.getValue() == tag) + .map(Map.Entry::getKey) + .collect(ImmutableSet.toImmutableSet()); + } + + public void add(PonderTag tag, ResourceLocation item) { + tags.put(item, tag); + } + + public void add(PonderTag tag, PonderChapter chapter) { + chapterTags.put(chapter, tag); + } + + public ItemBuilder forItems(ResourceLocation... items) { + return new ItemBuilder(items); + } + + public TagBuilder forTag(PonderTag tag) { + return new TagBuilder(tag); + } + + public static class ItemBuilder { + + private final Collection items; + + private ItemBuilder(ResourceLocation... items) { + this.items = Arrays.asList(items); + } + + public ItemBuilder add(PonderTag tag) { + items.forEach(i -> PonderRegistry.tags.add(tag, i)); + return this; + } + + } + + public static class TagBuilder { + + private final PonderTag tag; + + private TagBuilder(PonderTag tag) { + this.tag = tag; + } + + public TagBuilder add(ResourceLocation item) { + PonderRegistry.tags.add(tag, item); + return this; + } + + public TagBuilder add(IItemProvider item) { + return add(item.asItem() + .getRegistryName()); + } + + public TagBuilder add(ItemProviderEntry entry) { + return add(entry.get()); + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagScreen.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagScreen.java new file mode 100644 index 000000000..d0788ed5c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagScreen.java @@ -0,0 +1,315 @@ +package com.simibubi.create.foundation.ponder.content; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import com.mojang.blaze3d.matrix.MatrixStack; +import org.apache.commons.lang3.mutable.MutableBoolean; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import com.simibubi.create.foundation.ponder.NavigatableSimiScreen; +import com.simibubi.create.foundation.ponder.PonderLocalization; +import com.simibubi.create.foundation.ponder.PonderRegistry; +import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.ponder.ui.ChapterLabel; +import com.simibubi.create.foundation.ponder.ui.LayoutHelper; +import com.simibubi.create.foundation.ponder.ui.PonderButton; +import com.simibubi.create.foundation.utility.FontHelper; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.block.Block; +import net.minecraft.client.MainWindow; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.renderer.Rectangle2d; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.registries.ForgeRegistries; + +public class PonderTagScreen extends NavigatableSimiScreen { + + public static final String ASSOCIATED = PonderLocalization.LANG_PREFIX + "associated"; + + private final PonderTag tag; + protected final List items; + private final double itemXmult = 0.5; + protected Rectangle2d itemArea; + protected final List chapters; + private final double chapterXmult = 0.5; + private final double chapterYmult = 0.75; + protected Rectangle2d chapterArea; + private final double mainYmult = 0.15; + + private ItemStack hoveredItem = ItemStack.EMPTY; + + public PonderTagScreen(PonderTag tag) { + this.tag = tag; + items = new ArrayList<>(); + chapters = new ArrayList<>(); + } + + @Override + protected void init() { + widgets.clear(); + super.init(); + + // items + items.clear(); + PonderRegistry.tags.getItems(tag) + .stream() + .map(key -> { + Item item = ForgeRegistries.ITEMS.getValue(key); + if (item == null) { + Block b = ForgeRegistries.BLOCKS.getValue(key); + if (b != null) + item = b.asItem(); + } + return item; + }) + .filter(Objects::nonNull) + .forEach(items::add); + + int rowCount = MathHelper.clamp((int) Math.ceil(items.size() / 11d), 1, 3); + LayoutHelper layout = LayoutHelper.centeredHorizontal(items.size(), rowCount, 28, 28, 8); + itemArea = layout.getArea(); + int itemCenterX = (int) (width * itemXmult); + int itemCenterY = getItemsY(); + + for (Item i : items) { + final boolean canClick = PonderRegistry.all.containsKey(i.getRegistryName()); + PonderButton button = + new PonderButton(itemCenterX + layout.getX() + 4, itemCenterY + layout.getY() + 4, (mouseX, mouseY) -> { + if (!canClick) + return; + centerScalingOn(mouseX, mouseY); + ScreenOpener.transitionTo(PonderUI.of(new ItemStack(i), tag)); + }).showing(new ItemStack(i)); + if (!canClick) + button.noClickEvent(); + + button.fade(1); + widgets.add(button); + layout.next(); + } + + if (!tag.getMainItem() + .isEmpty()) { + final boolean canClick = PonderRegistry.all.containsKey(tag.getMainItem() + .getItem() + .getRegistryName()); + PonderButton button = + new PonderButton(itemCenterX - layout.getTotalWidth() / 2 - 42, itemCenterY - 10, (mouseX, mouseY) -> { + if (!canClick) + return; + centerScalingOn(mouseX, mouseY); + ScreenOpener.transitionTo(PonderUI.of(tag.getMainItem(), tag)); + }).showing(tag.getMainItem()); + if (!canClick) + button.noClickEvent(); + + button.fade(1); + widgets.add(button); + } + + // chapters + chapters.clear(); + chapters.addAll(PonderRegistry.tags.getChapters(tag)); + + rowCount = MathHelper.clamp((int) Math.ceil(chapters.size() / 3f), 1, 3); + layout = LayoutHelper.centeredHorizontal(chapters.size(), rowCount, 200, 38, 16); + chapterArea = layout.getArea(); + int chapterCenterX = (int) (width * chapterXmult); + int chapterCenterY = (int) (height * chapterYmult); + + for (PonderChapter chapter : chapters) { + ChapterLabel label = new ChapterLabel(chapter, chapterCenterX + layout.getX(), + chapterCenterY + layout.getY(), (mouseX, mouseY) -> { + centerScalingOn(mouseX, mouseY); + ScreenOpener.transitionTo(PonderUI.of(chapter)); + }); + + widgets.add(label); + layout.next(); + } + + } + + @Override + public void tick() { + super.tick(); + PonderUI.ponderTicks++; + + hoveredItem = ItemStack.EMPTY; + MainWindow w = client.getWindow(); + double mouseX = client.mouseHelper.getMouseX() * w.getScaledWidth() / w.getWidth(); + double mouseY = client.mouseHelper.getMouseY() * w.getScaledHeight() / w.getHeight(); + for (Widget widget : widgets) { + if (widget == backTrack) + continue; + if (widget instanceof PonderButton) + if (widget.isMouseOver(mouseX, mouseY)) { + hoveredItem = ((PonderButton) widget).getItem(); + } + } + } + + @Override + protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + renderItems(ms, mouseX, mouseY, partialTicks); + + renderChapters(ms, mouseX, mouseY, partialTicks); + + RenderSystem.pushMatrix(); + RenderSystem.translated(width / 2 - 120, height * mainYmult - 40, 0); + + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, 800); + int x = 31 + 20 + 8; + int y = 31; + + String title = tag.getTitle(); + + int streakHeight = 35; + UIRenderHelper.streak(ms, 0, x - 4, y - 12 + streakHeight / 2, streakHeight, (int) (240), 0x101010); + PonderUI.renderBox(ms, 21, 21, 30, 30, false); + + textRenderer.draw(ms, Lang.translate(PonderUI.PONDERING), x, y - 6, 0xffa3a3a3); + y += 8; + x += 0; + RenderSystem.translated(x, y, 0); + RenderSystem.translated(0, 0, 5); + textRenderer.draw(ms, title, 0, 0, 0xeeeeee); + RenderSystem.popMatrix(); + + RenderSystem.pushMatrix(); + RenderSystem.translated(23, 23, 0); + RenderSystem.scaled(1.66, 1.66, 1.66); + tag.draw(ms, this, 0, 0); + RenderSystem.popMatrix(); + RenderSystem.popMatrix(); + + RenderSystem.pushMatrix(); + int w = (int) (width * .45); + x = (width - w) / 2; + y = getItemsY() - 10 + Math.max(itemArea.getHeight(), 48); + + String desc = tag.getDescription(); + int h = textRenderer.getWordWrappedHeight(desc, w); + + PonderUI.renderBox(ms, x - 3, y - 3, w + 6, h + 6, false); + RenderSystem.translated(0, 0, 100); + FontHelper.drawSplitString(textRenderer, desc, x, y, w, 0xeeeeee); + RenderSystem.popMatrix(); + + } + + protected void renderItems(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + if (items.isEmpty()) + return; + + int x = (int) (width * itemXmult); + int y = getItemsY(); + + String relatedTitle = Lang.translate(ASSOCIATED).getString(); + int stringWidth = textRenderer.getStringWidth(relatedTitle); + + RenderSystem.pushMatrix(); + RenderSystem.translated(x, y, 0); + PonderUI.renderBox(ms, (sWidth - stringWidth) / 2 - 5, itemArea.getY() - 21, stringWidth + 10, 10, false); + RenderSystem.translated(0, 0, 200); + +// UIRenderHelper.streak(0, itemArea.getX() - 10, itemArea.getY() - 20, 20, 180, 0x101010); + drawCenteredString(ms, textRenderer, relatedTitle, sWidth / 2, itemArea.getY() - 20, 0xeeeeee); + + UIRenderHelper.streak(ms, 0, 0, 0, itemArea.getHeight() + 10, itemArea.getWidth() / 2 + 75, 0x101010); + UIRenderHelper.streak(ms, 180, 0, 0, itemArea.getHeight() + 10, itemArea.getWidth() / 2 + 75, 0x101010); + + RenderSystem.popMatrix(); + + } + + public int getItemsY() { + return (int) (mainYmult * height + 85); + } + + protected void renderChapters(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + if (chapters.isEmpty()) + return; + + int chapterX = (int) (width * chapterXmult); + int chapterY = (int) (height * chapterYmult); + + RenderSystem.pushMatrix(); + RenderSystem.translated(chapterX, chapterY, 0); + + UIRenderHelper.streak(ms, 0, chapterArea.getX() - 10, chapterArea.getY() - 20, 20, 220, 0x101010); + textRenderer.draw(ms, "More Topics to Ponder about", chapterArea.getX() - 5, chapterArea.getY() - 25, 0xffddeeff); + + RenderSystem.popMatrix(); + } + + @Override + protected void renderWindowForeground(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + RenderSystem.pushMatrix(); + RenderSystem.disableRescaleNormal(); + RenderSystem.disableDepthTest(); + + RenderSystem.translated(0, 0, 200); + if (!hoveredItem.isEmpty()) { + renderTooltip(ms, hoveredItem, mouseX, mouseY); + } + RenderSystem.enableDepthTest(); + RenderSystem.enableRescaleNormal(); + RenderSystem.popMatrix(); + } + + @Override + protected String getBreadcrumbTitle() { + return tag.getTitle(); + } + + public ItemStack getHoveredTooltipItem() { + return hoveredItem; + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + MutableBoolean handled = new MutableBoolean(false); + widgets.forEach(w -> { + if (handled.booleanValue()) + return; + if (!w.isMouseOver(x, y)) + return; + if (w instanceof PonderButton) { + PonderButton mtdButton = (PonderButton) w; + mtdButton.runCallback(x, y); + handled.setTrue(); + return; + } + }); + + if (handled.booleanValue()) + return true; + return super.mouseClicked(x, y, button); + } + + @Override + public boolean isEquivalentTo(NavigatableSimiScreen other) { + if (other instanceof PonderTagScreen) + return tag == ((PonderTagScreen) other).tag; + return super.isEquivalentTo(other); + } + + @Override + public boolean isPauseScreen() { + return true; + } + + public PonderTag getTag() { + return tag; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PulleyScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PulleyScenes.java new file mode 100644 index 000000000..8b11d693e --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PulleyScenes.java @@ -0,0 +1,227 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.Blocks; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; + +public class PulleyScenes { + + public static void movement(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("rope_pulley", "Moving Structures using Rope Pulleys"); + scene.configureBasePlate(0, 0, 5); + scene.scaleSceneView(0.95f); + scene.setSceneOffsetY(-1); + + Selection reversable = util.select.fromTo(2, 3, 4, 2, 4, 2); + BlockPos leverPos = util.grid.at(1, 2, 4); + BlockPos pulleyPos = util.grid.at(2, 4, 2); + Selection redstoneStuff = util.select.fromTo(leverPos, leverPos.east()); + + scene.world.showSection(util.select.layer(0), Direction.UP); + ElementLink plank = + scene.world.showIndependentSection(util.select.position(2, 1, 2), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(1, 4, 3, 2, 1, 4), Direction.DOWN); + scene.idle(10); + + scene.world.showSection(util.select.position(pulleyPos), Direction.SOUTH); + scene.idle(20); + + scene.world.toggleRedstonePower(redstoneStuff); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reversable, f -> -f); + scene.effects.rotationDirectionIndicator(pulleyPos.south()); + scene.world.movePulley(pulleyPos, 2, 40); + + scene.idle(45); + scene.overlay.showText(60) + .pointAt(util.vector.blockSurface(pulleyPos, Direction.WEST)) + .text("Rope Pulleys can move blocks vertically when given Rotational Force") + .placeNearTarget(); + scene.idle(70); + + scene.world.toggleRedstonePower(redstoneStuff); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reversable, f -> -f); + scene.effects.rotationDirectionIndicator(pulleyPos.south()); + scene.world.movePulley(pulleyPos, -2, 40); + scene.world.moveSection(plank, util.vector.of(0, 2, 0), 40); + scene.idle(60); + + scene.overlay.showText(60) + .pointAt(util.vector.blockSurface(pulleyPos, Direction.SOUTH)) + .text("Direction and Speed of movement depend on the Rotational Input") + .placeNearTarget(); + + scene.world.toggleRedstonePower(redstoneStuff); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reversable, f -> -f); + scene.effects.rotationDirectionIndicator(pulleyPos.south()); + scene.world.movePulley(pulleyPos, 2, 40); + scene.world.moveSection(plank, util.vector.of(0, -2, 0), 40); + scene.idle(50); + + scene.world.hideIndependentSection(plank, Direction.NORTH); + scene.idle(15); + ElementLink chassis = + scene.world.showIndependentSection(util.select.fromTo(2, 1, 1, 0, 2, 1), Direction.SOUTH); + scene.world.moveSection(chassis, util.vector.of(1, 0, 1), 0); + scene.idle(5); + scene.world.showSectionAndMerge(util.select.position(2, 1, 0), Direction.SOUTH, chassis); + scene.idle(15); + scene.effects.superGlue(util.grid.at(3, 1, 1), Direction.SOUTH, true); + scene.overlay.showText(80) + .pointAt(util.vector.blockSurface(util.grid.at(1, 2, 2), Direction.NORTH)) + .placeNearTarget() + .sharedText("movement_anchors"); + scene.idle(90); + + scene.world.toggleRedstonePower(redstoneStuff); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reversable, f -> -f); + scene.effects.rotationDirectionIndicator(pulleyPos.south()); + scene.world.movePulley(pulleyPos, -2, 40); + scene.world.moveSection(chassis, util.vector.of(0, 2, 0), 40); + scene.idle(50); + + scene.world.toggleRedstonePower(redstoneStuff); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reversable, f -> -f); + scene.effects.rotationDirectionIndicator(pulleyPos.south()); + scene.world.movePulley(pulleyPos, 2, 40); + scene.world.moveSection(chassis, util.vector.of(0, -2, 0), 40); + scene.idle(50); + } + + public static void movementModes(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("rope_pulley_modes", "Movement Modes of the Rope Pulley"); + scene.configureBasePlate(0, 0, 5); + scene.scaleSceneView(0.95f); + scene.setSceneOffsetY(-1); + + Selection reversable = util.select.fromTo(2, 3, 4, 2, 4, 2); + BlockPos leverPos = util.grid.at(1, 2, 4); + BlockPos pulleyPos = util.grid.at(2, 4, 2); + Selection redstoneStuff = util.select.fromTo(leverPos, leverPos.east()); + BlockPos flowerPos = util.grid.at(2, 1, 2); + + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.world.showSection(util.select.position(flowerPos), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(1, 4, 3, 2, 1, 4), Direction.DOWN); + scene.idle(10); + + scene.world.showSection(util.select.position(pulleyPos), Direction.SOUTH); + ElementLink glass = + scene.world.showIndependentSection(util.select.position(pulleyPos.down()), Direction.UP); + scene.idle(20); + + scene.world.toggleRedstonePower(redstoneStuff); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reversable, f -> -f); + scene.effects.rotationDirectionIndicator(pulleyPos.south()); + scene.world.movePulley(pulleyPos, 2, 40); + scene.world.moveSection(glass, util.vector.of(0, -2, 0), 40); + scene.idle(40); + + scene.world.destroyBlock(flowerPos); + scene.idle(10); + scene.overlay.showSelectionWithText(util.select.position(flowerPos), 70) + .text("Whenever Pulleys stop moving, the moved structure reverts to blocks") + .placeNearTarget() + .colored(PonderPalette.RED); + scene.idle(80); + + scene.world.toggleRedstonePower(redstoneStuff); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reversable, f -> -f); + scene.effects.rotationDirectionIndicator(pulleyPos.south()); + scene.world.movePulley(pulleyPos, -2, 40); + scene.world.moveSection(glass, util.vector.of(0, 2, 0), 40); + scene.world.hideSection(util.select.position(flowerPos), Direction.DOWN); + scene.idle(40); + + scene.world.setBlock(flowerPos, Blocks.BLUE_ORCHID.getDefaultState(), false); + scene.world.showSection(util.select.position(flowerPos), Direction.DOWN); + scene.overlay.showCenteredScrollInput(pulleyPos, Direction.UP, 60); + scene.overlay.showControls(new InputWindowElement(util.vector.topOf(pulleyPos), Pointing.DOWN).scroll() + .withWrench(), 60); + scene.overlay.showText(70) + .pointAt(util.vector.topOf(pulleyPos)) + .placeNearTarget() + .sharedText("behaviour_modify_wrench"); + scene.idle(80); + + scene.world.toggleRedstonePower(redstoneStuff); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reversable, f -> -f); + scene.effects.rotationDirectionIndicator(pulleyPos.south()); + scene.world.movePulley(pulleyPos, 2, 40); + scene.world.moveSection(glass, util.vector.of(0, -2, 0), 40); + scene.idle(50); + scene.overlay.showText(120) + .colored(PonderPalette.GREEN) + .pointAt(util.vector.blockSurface(flowerPos, Direction.WEST)) + .placeNearTarget() + .text("It can be configured never to revert to solid blocks, or only at the location it started at"); + } + + public static void attachment(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("rope_pulley_attachment", "Moving Pulleys as part of a Contraption"); + scene.configureBasePlate(0, 0, 5); + scene.scaleSceneView(0.95f); + scene.setSceneOffsetY(-1); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + + Selection kinetics = util.select.fromTo(4, 3, 2, 4, 1, 5); + Selection largeCog = util.select.position(3, 0, 5); + + scene.world.showSection(kinetics, Direction.DOWN); + ElementLink poles = + scene.world.showIndependentSection(util.select.fromTo(4, 4, 2, 6, 4, 2), Direction.DOWN); + scene.world.moveSection(poles, util.vector.of(0, -1, 0), 0); + scene.idle(10); + + BlockPos pulleyPos = util.grid.at(3, 3, 2); + ElementLink pulley = + scene.world.showIndependentSection(util.select.position(pulleyPos), Direction.EAST); + scene.idle(10); + scene.world.showSectionAndMerge(util.select.fromTo(3, 1, 1, 3, 1, 2) + .add(util.select.position(3, 2, 1)), Direction.SOUTH, pulley); + + scene.idle(10); + scene.overlay.showText(50) + .pointAt(util.vector.blockSurface(pulleyPos, Direction.WEST)) + .placeNearTarget() + .text("Whenever Pulleys are themselves being moved by a Contraption..."); + scene.idle(60); + + scene.world.setKineticSpeed(largeCog, -16); + scene.world.setKineticSpeed(kinetics, 32); + scene.effects.rotationDirectionIndicator(util.grid.at(4, 1, 5)); + scene.world.moveSection(poles, util.vector.of(-2, 0, 0), 40); + scene.world.moveSection(pulley, util.vector.of(-2, 0, 0), 40); + scene.idle(40); + + scene.overlay.showSelectionWithText(util.select.fromTo(1, 1, 1, 1, 1, 2), 50) + .colored(PonderPalette.GREEN) + .placeNearTarget() + .text("...its attached structure will be dragged with it"); + scene.idle(60); + scene.overlay.showText(80) + .colored(PonderPalette.RED) + .pointAt(util.vector.topOf(pulleyPos.west(2))) + .placeNearTarget() + .text("Mind that pulleys are only movable while stopped"); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/RedstoneScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/RedstoneScenes.java new file mode 100644 index 000000000..4871477ff --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/RedstoneScenes.java @@ -0,0 +1,829 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerTileEntity; +import com.simibubi.create.content.logistics.block.diodes.AdjustablePulseRepeaterTileEntity; +import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterBlock; +import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterTileEntity; +import com.simibubi.create.content.logistics.block.diodes.PoweredLatchBlock; +import com.simibubi.create.content.logistics.block.diodes.PulseRepeaterBlock; +import com.simibubi.create.content.logistics.block.diodes.ToggleLatchBlock; +import com.simibubi.create.content.logistics.block.redstone.AnalogLeverTileEntity; +import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; +import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock; +import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkTileEntity; +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.block.RedstoneWireBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.state.IntegerProperty; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; + +public class RedstoneScenes { + + public static void sticker(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("sticker", "Attaching blocks using the Sticker"); + scene.configureBasePlate(0, 0, 5); + scene.showBasePlate(); + scene.idle(5); + + Selection redstone = util.select.fromTo(0, 2, 2, 2, 2, 2); + BlockPos stickerPos = util.grid.at(2, 2, 2); + Selection stickerSelect = util.select.position(stickerPos); + BlockPos buttonPos = util.grid.at(0, 2, 2); + BlockPos bearingPos = util.grid.at(2, 1, 2); + + scene.world.showSection(util.select.fromTo(2, 1, 2, 0, 2, 2) + .substract(stickerSelect), Direction.DOWN); + scene.idle(10); + ElementLink sticker = scene.world.showIndependentSection(stickerSelect, Direction.DOWN); + scene.idle(10); + ElementLink plank = + scene.world.showIndependentSection(util.select.position(2, 2, 1), Direction.SOUTH); + scene.world.configureCenterOfRotation(sticker, util.vector.centerOf(stickerPos)); + scene.world.configureCenterOfRotation(plank, util.vector.centerOf(stickerPos)); + scene.overlay.showText(60) + .text("Stickers are ideal for Redstone-controlled block attachment") + .attachKeyFrame() + .pointAt(util.vector.blockSurface(stickerPos, Direction.WEST)) + .placeNearTarget(); + scene.idle(70); + + scene.world.toggleRedstonePower(redstone); + scene.world.modifyBlock(stickerPos, s -> s.with(StickerBlock.EXTENDED, true), false); + scene.effects.indicateRedstone(buttonPos); + scene.world.modifyTileNBT(stickerSelect, StickerTileEntity.class, nbt -> { + }); + scene.idle(20); + + scene.world.toggleRedstonePower(redstone); + scene.idle(20); + + scene.overlay.showText(60) + .text("Upon receiving a signal, it will toggle its state") + .pointAt(util.vector.blockSurface(stickerPos, Direction.WEST)) + .placeNearTarget(); + scene.idle(70); + + scene.world.rotateBearing(bearingPos, 180 * 3, 80); + scene.world.rotateSection(sticker, 0, 180 * 3, 0, 80); + scene.world.rotateSection(plank, 0, 180 * 3, 0, 80); + scene.overlay.showText(70) + .text("If it is now moved in a contraption, the block will move with it") + .pointAt(util.vector.topOf(stickerPos)) + .placeNearTarget(); + scene.idle(90); + scene.addKeyframe(); + + scene.world.toggleRedstonePower(redstone); + scene.world.modifyBlock(stickerPos, s -> s.with(StickerBlock.EXTENDED, false), false); + scene.effects.indicateRedstone(buttonPos); + scene.world.modifyTileNBT(stickerSelect, StickerTileEntity.class, nbt -> { + }); + scene.idle(20); + + scene.world.toggleRedstonePower(redstone); + scene.idle(20); + + scene.overlay.showText(60) + .text("Toggled once again, the block is no longer attached") + .pointAt(util.vector.blockSurface(stickerPos, Direction.WEST)) + .placeNearTarget(); + scene.idle(70); + + scene.world.rotateBearing(bearingPos, 180 * 3, 80); + scene.world.rotateSection(sticker, 0, 180 * 3, 0, 80); + } + + public static void contact(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("redstone_contact", "Redstone Contacts"); + scene.configureBasePlate(0, 0, 5); + scene.showBasePlate(); + scene.idle(5); + Selection contactAndRedstone = util.select.fromTo(1, 1, 0, 1, 1, 2); + Selection topContact = util.select.position(1, 2, 2); + + scene.world.toggleRedstonePower(contactAndRedstone); + scene.world.toggleRedstonePower(topContact); + scene.world.showSection(contactAndRedstone, Direction.DOWN); + + BlockPos bearingPos = util.grid.at(3, 1, 2); + scene.idle(25); + + ElementLink contact = scene.world.showIndependentSection(topContact, Direction.DOWN); + scene.idle(10); + scene.world.toggleRedstonePower(topContact); + scene.world.toggleRedstonePower(contactAndRedstone); + scene.effects.indicateRedstone(util.grid.at(1, 1, 2)); + scene.idle(10); + scene.overlay.showText(60) + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector.of(1, 2, 2.5)) + .text("Redstone Contacts facing each other will emit a redstone signal"); + scene.idle(70); + + scene.world.showSection(util.select.position(bearingPos), Direction.DOWN); + scene.idle(10); + scene.world.showSectionAndMerge(util.select.fromTo(2, 2, 2, 4, 2, 2), Direction.DOWN, contact); + scene.idle(10); + scene.effects.superGlue(util.grid.at(1, 2, 2), Direction.EAST, true); + scene.world.configureCenterOfRotation(contact, util.vector.centerOf(bearingPos)); + + int speed = 2; + + scene.idle(10); + scene.world.rotateBearing(bearingPos, 10, speed); + scene.world.rotateSection(contact, 0, 10, 0, speed); + scene.idle(speed); + + scene.world.toggleRedstonePower(topContact); + scene.world.toggleRedstonePower(contactAndRedstone); + scene.effects.indicateRedstone(util.grid.at(1, 1, 2)); + scene.world.rotateBearing(bearingPos, 340, 34 * speed); + scene.world.rotateSection(contact, 0, 340, 0, 34 * speed); + scene.addKeyframe(); + scene.idle(34 * speed); + + scene.overlay.showText(100) + .placeNearTarget() + .pointAt(util.vector.of(1, 1.5, 2.5)) + .text("This still applies when one of them is part of a moving Contraption"); + + for (int i = 0; i < 5; i++) { + scene.world.toggleRedstonePower(topContact); + scene.world.toggleRedstonePower(contactAndRedstone); + scene.effects.indicateRedstone(util.grid.at(1, 1, 2)); + scene.world.rotateBearing(bearingPos, 20, 2 * speed); + scene.world.rotateSection(contact, 0, 20, 0, 2 * speed); + scene.idle(2 * speed); + + scene.world.toggleRedstonePower(topContact); + scene.world.toggleRedstonePower(contactAndRedstone); + scene.world.rotateBearing(bearingPos, 340, 34 * speed); + scene.world.rotateSection(contact, 0, 340, 0, 34 * speed); + scene.idle(34 * speed); + + if (i == 0) + scene.markAsFinished(); + } + + scene.world.toggleRedstonePower(topContact); + scene.world.toggleRedstonePower(contactAndRedstone); + scene.world.rotateBearing(bearingPos, 10, speed); + scene.world.rotateSection(contact, 0, 10, 0, speed); + } + + public static void pulseRepeater(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("pulse_repeater", "Controlling signals using Pulse Repeaters"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos circuitPos = util.grid.at(2, 1, 2); + BlockPos leverPos = util.grid.at(4, 1, 2); + + scene.world.showSection(util.select.layersFrom(1) + .substract(util.select.position(circuitPos)), Direction.UP); + scene.idle(10); + scene.world.showSection(util.select.position(circuitPos), Direction.DOWN); + scene.idle(20); + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, PulseRepeaterBlock.PULSING); + scene.idle(3); + scene.world.cycleBlockProperty(circuitPos, PulseRepeaterBlock.PULSING); + scene.world.toggleRedstonePower(util.select.position(1, 1, 2)); + scene.idle(2); + scene.world.toggleRedstonePower(util.select.position(0, 1, 2)); + + scene.idle(15); + scene.overlay.showText(70) + .text("Pulse Repeaters will shorten any redstone signal to a single pulse") + .placeNearTarget() + .attachKeyFrame() + .pointAt(util.vector.topOf(util.grid.at(0, 1, 2))); + scene.idle(60); + + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 2, 1, 2)); + scene.idle(20); + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, PulseRepeaterBlock.PULSING); + scene.idle(3); + scene.world.cycleBlockProperty(circuitPos, PulseRepeaterBlock.PULSING); + scene.world.toggleRedstonePower(util.select.position(1, 1, 2)); + scene.idle(2); + scene.world.toggleRedstonePower(util.select.position(0, 1, 2)); + } + + public static void adjustableRepeater(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("adjustable_repeater", "Controlling signals using Adjustable Repeaters"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos circuitPos = util.grid.at(2, 1, 2); + BlockPos leverPos = util.grid.at(4, 1, 2); + + scene.world.modifyTileNBT(util.select.position(circuitPos), AdjustableRepeaterTileEntity.class, + nbt -> nbt.putInt("ScrollValue", 30)); + scene.world.showSection(util.select.layersFrom(1) + .substract(util.select.position(circuitPos)), Direction.UP); + scene.idle(10); + scene.world.showSection(util.select.position(circuitPos), Direction.DOWN); + scene.idle(20); + + Vector3d circuitTop = util.vector.blockSurface(circuitPos, Direction.DOWN) + .add(0, 3 / 16f, 0); + scene.overlay.showText(70) + .text("Adjustable Repeaters behave similarly to regular Repeaters") + .attachKeyFrame() + .placeNearTarget() + .pointAt(circuitTop); + scene.idle(60); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 2, 1, 2)); + scene.idle(30); + scene.world.cycleBlockProperty(circuitPos, AdjustableRepeaterBlock.POWERING); + scene.world.toggleRedstonePower(util.select.fromTo(1, 1, 2, 0, 1, 2)); + scene.idle(15); + + scene.overlay.showText(40) + .text("They charge up for a set time...") + .placeNearTarget() + .pointAt(util.vector.topOf(util.grid.at(0, 1, 2))); + scene.idle(50); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 2, 1, 2)); + scene.idle(30); + scene.world.cycleBlockProperty(circuitPos, AdjustableRepeaterBlock.POWERING); + scene.world.toggleRedstonePower(util.select.fromTo(1, 1, 2, 0, 1, 2)); + scene.idle(15); + + scene.overlay.showText(40) + .text("...and cool down for the same duration") + .placeNearTarget() + .pointAt(util.vector.topOf(util.grid.at(0, 1, 2))); + scene.idle(50); + + scene.overlay.showRepeaterScrollInput(circuitPos, 60); + scene.overlay.showControls(new InputWindowElement(circuitTop, Pointing.DOWN).scroll(), 60); + scene.idle(10); + scene.overlay.showText(60) + .text("Using the mouse wheel, the charge time can be configured") + .attachKeyFrame() + .placeNearTarget() + .pointAt(circuitTop); + scene.world.modifyTileNBT(util.select.position(circuitPos), AdjustableRepeaterTileEntity.class, + nbt -> nbt.putInt("ScrollValue", 120)); + scene.idle(70); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 2, 1, 2)); + scene.idle(60); + scene.overlay.showText(50) + .text("Configured delays can range up to 30 minutes") + .placeNearTarget() + .pointAt(circuitTop); + scene.idle(60); + scene.world.cycleBlockProperty(circuitPos, AdjustableRepeaterBlock.POWERING); + scene.world.toggleRedstonePower(util.select.fromTo(1, 1, 2, 0, 1, 2)); + scene.idle(15); + + } + + public static void adjustablePulseRepeater(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("adjustable_pulse_repeater", "Controlling signals using Adjustable Pulse Repeaters"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos circuitPos = util.grid.at(2, 1, 2); + BlockPos leverPos = util.grid.at(4, 1, 2); + + scene.world.modifyTileNBT(util.select.position(circuitPos), AdjustablePulseRepeaterTileEntity.class, + nbt -> nbt.putInt("ScrollValue", 30)); + scene.world.showSection(util.select.layersFrom(1) + .substract(util.select.position(circuitPos)), Direction.UP); + scene.idle(10); + scene.world.showSection(util.select.position(circuitPos), Direction.DOWN); + scene.idle(20); + + Vector3d circuitTop = util.vector.blockSurface(circuitPos, Direction.DOWN) + .add(0, 3 / 16f, 0); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 2, 1, 2)); + scene.idle(30); + scene.world.cycleBlockProperty(circuitPos, AdjustableRepeaterBlock.POWERING); + scene.world.toggleRedstonePower(util.select.fromTo(1, 1, 2, 0, 1, 2)); + scene.idle(3); + scene.world.toggleRedstonePower(util.select.fromTo(1, 1, 2, 0, 1, 2)); + scene.idle(15); + + scene.overlay.showText(60) + .text("Adjustable Pulse Repeaters emit a short pulse at a delay") + .attachKeyFrame() + .placeNearTarget() + .pointAt(circuitTop); + + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 2, 1, 2)); + scene.idle(70); + + scene.overlay.showRepeaterScrollInput(circuitPos, 60); + scene.overlay.showControls(new InputWindowElement(circuitTop, Pointing.DOWN).scroll(), 60); + scene.idle(10); + scene.overlay.showText(60) + .text("Using the mouse wheel, the charge time can be configured") + .attachKeyFrame() + .placeNearTarget() + .pointAt(circuitTop); + scene.world.modifyTileNBT(util.select.position(circuitPos), AdjustablePulseRepeaterTileEntity.class, + nbt -> nbt.putInt("ScrollValue", 120)); + scene.idle(70); + + scene.effects.indicateRedstone(leverPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 2, 1, 2)); + scene.idle(60); + scene.overlay.showText(50) + .text("Configured delays can range up to 30 minutes") + .placeNearTarget() + .pointAt(circuitTop); + scene.idle(60); + scene.world.cycleBlockProperty(circuitPos, AdjustableRepeaterBlock.POWERING); + scene.world.toggleRedstonePower(util.select.fromTo(1, 1, 2, 0, 1, 2)); + scene.idle(3); + scene.world.toggleRedstonePower(util.select.fromTo(1, 1, 2, 0, 1, 2)); + } + + public static void poweredLatch(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("powered_latch", "Controlling signals using the Powered Latch"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos circuitPos = util.grid.at(2, 1, 2); + BlockPos buttonPos = util.grid.at(4, 1, 2); + Vector3d circuitTop = util.vector.blockSurface(circuitPos, Direction.DOWN) + .add(0, 3 / 16f, 0); + + scene.world.showSection(util.select.layersFrom(1) + .substract(util.select.position(circuitPos)), Direction.UP); + scene.idle(10); + scene.world.showSection(util.select.position(circuitPos), Direction.DOWN); + scene.idle(20); + + scene.overlay.showText(40) + .attachKeyFrame() + .text("Powered Latches are redstone controllable Levers") + .placeNearTarget() + .pointAt(circuitTop); + scene.idle(50); + + scene.effects.indicateRedstone(buttonPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, PoweredLatchBlock.POWERING); + scene.idle(30); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 3, 1, 2)); + + AxisAlignedBB bb = new AxisAlignedBB(circuitPos).grow(-.48f, -.45f, -.05f) + .offset(.575, -.45, 0); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.GREEN, bb, bb, 40); + scene.overlay.showText(40) + .colored(PonderPalette.GREEN) + .text("Signals at the back switch it on") + .placeNearTarget() + .pointAt(bb.getCenter()); + scene.idle(60); + + scene.effects.indicateRedstone(util.grid.at(2, 1, 0)); + scene.world.toggleRedstonePower(util.select.fromTo(2, 1, 0, 2, 1, 1)); + scene.world.toggleRedstonePower(util.select.fromTo(2, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, PoweredLatchBlock.POWERING); + scene.idle(30); + scene.world.toggleRedstonePower(util.select.fromTo(2, 1, 0, 2, 1, 1)); + + bb = new AxisAlignedBB(circuitPos).grow(-.05f, -.45f, -.48f) + .offset(0, -.45, .575); + AxisAlignedBB bb2 = new AxisAlignedBB(circuitPos).grow(-.05f, -.45f, -.48f) + .offset(0, -.45, -.575); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.RED, bb, bb, 40); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.RED, bb2, bb2, 40); + scene.overlay.showText(40) + .colored(PonderPalette.RED) + .text("Signals from the side switch it back off") + .placeNearTarget() + .pointAt(bb2.getCenter()); + scene.idle(50); + + scene.addKeyframe(); + scene.idle(10); + scene.overlay.showControls(new InputWindowElement(circuitTop, Pointing.DOWN).rightClick(), 40); + scene.idle(7); + scene.world.toggleRedstonePower(util.select.fromTo(2, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, PoweredLatchBlock.POWERING); + scene.idle(10); + + scene.overlay.showText(50) + .text("Powered latches can also be toggled manually") + .placeNearTarget() + .pointAt(circuitTop); + scene.idle(60); + + scene.overlay.showControls(new InputWindowElement(circuitTop, Pointing.DOWN).rightClick(), 40); + scene.idle(7); + scene.world.toggleRedstonePower(util.select.fromTo(2, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, PoweredLatchBlock.POWERING); + scene.idle(10); + } + + public static void poweredToggleLatch(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("powered_toggle_latch", "Controlling signals using the Powered Toggle Latch"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + + BlockPos circuitPos = util.grid.at(2, 1, 2); + BlockPos buttonPos = util.grid.at(4, 1, 2); + Vector3d circuitTop = util.vector.blockSurface(circuitPos, Direction.DOWN) + .add(0, 3 / 16f, 0); + + scene.world.showSection(util.select.layersFrom(1) + .substract(util.select.position(circuitPos)), Direction.UP); + scene.idle(10); + scene.world.showSection(util.select.position(circuitPos), Direction.DOWN); + scene.idle(20); + + scene.overlay.showText(40) + .attachKeyFrame() + .text("Powered Toggle Latches are redstone controllable Levers") + .placeNearTarget() + .pointAt(circuitTop); + scene.idle(50); + + scene.effects.indicateRedstone(buttonPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, ToggleLatchBlock.POWERING); + scene.idle(30); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 3, 1, 2)); + + AxisAlignedBB bb = new AxisAlignedBB(circuitPos).grow(-.48f, -.45f, -.05f) + .offset(.575, -.45, 0); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.GREEN, bb, bb, 40); + scene.overlay.showText(40) + .colored(PonderPalette.GREEN) + .text("Signals at the back will toggle its state") + .placeNearTarget() + .pointAt(bb.getCenter()); + scene.idle(60); + + scene.effects.indicateRedstone(buttonPos); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, ToggleLatchBlock.POWERING); + scene.idle(30); + scene.world.toggleRedstonePower(util.select.fromTo(4, 1, 2, 3, 1, 2)); + scene.overlay.chaseBoundingBoxOutline(PonderPalette.RED, bb, bb, 40); + scene.overlay.showText(30) + .colored(PonderPalette.RED) + .text("...on and back off") + .placeNearTarget() + .pointAt(bb.getCenter()); + scene.idle(50); + + scene.addKeyframe(); + scene.idle(10); + scene.overlay.showControls(new InputWindowElement(circuitTop, Pointing.DOWN).rightClick(), 40); + scene.idle(7); + scene.world.toggleRedstonePower(util.select.fromTo(2, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, ToggleLatchBlock.POWERING); + scene.idle(10); + + scene.overlay.showText(50) + .text("Powered toggle latches can also be toggled manually") + .placeNearTarget() + .pointAt(circuitTop); + scene.idle(60); + + scene.overlay.showControls(new InputWindowElement(circuitTop, Pointing.DOWN).rightClick(), 40); + scene.idle(7); + scene.world.toggleRedstonePower(util.select.fromTo(2, 1, 2, 0, 1, 2)); + scene.world.cycleBlockProperty(circuitPos, ToggleLatchBlock.POWERING); + scene.idle(10); + } + + public static void analogLever(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("analog_lever", "Controlling signals using the Analog Lever"); + scene.configureBasePlate(0, 0, 5); + + BlockPos[] wireLocations = new BlockPos[] { util.grid.at(2, 1, 1), util.grid.at(2, 1, 0), util.grid.at(1, 1, 0), + util.grid.at(0, 1, 0), util.grid.at(0, 1, 1), util.grid.at(0, 1, 2), util.grid.at(0, 1, 3), + util.grid.at(0, 1, 4), util.grid.at(1, 1, 4), util.grid.at(2, 1, 4), util.grid.at(3, 1, 4), + util.grid.at(4, 1, 4), util.grid.at(4, 1, 3), util.grid.at(4, 1, 2), util.grid.at(4, 1, 1) }; + + Selection leverSelection = util.select.fromTo(2, 1, 2, 2, 2, 2); + Selection lamp = util.select.position(4, 1, 0); + BlockPos leverPos = util.grid.at(2, 2, 2); + Vector3d leverVec = util.vector.centerOf(leverPos) + .add(0, -.25, 0); + + scene.world.showSection(util.select.layersFrom(0) + .substract(lamp) + .substract(leverSelection), Direction.UP); + scene.idle(5); + scene.world.showSection(lamp, Direction.DOWN); + scene.idle(10); + + scene.world.showSection(leverSelection, Direction.DOWN); + scene.idle(20); + + scene.overlay.showText(60) + .text("Analog Levers make for a compact and precise source of redstone power") + .placeNearTarget() + .attachKeyFrame() + .pointAt(leverVec); + scene.idle(70); + + IntegerProperty power = RedstoneWireBlock.POWER; + scene.overlay.showControls(new InputWindowElement(leverVec, Pointing.DOWN).rightClick(), 40); + scene.idle(7); + for (int i = 0; i < 7; i++) { + scene.idle(2); + final int state = i + 1; + scene.world.modifyTileNBT(leverSelection, AnalogLeverTileEntity.class, nbt -> nbt.putInt("State", state)); + scene.world.modifyBlock(wireLocations[i], s -> s.with(power, 7 - state), false); + scene.effects.indicateRedstone(wireLocations[i]); + } + scene.idle(20); + + scene.overlay.showText(60) + .attachKeyFrame() + .text("Right-click to increase its analog power output") + .placeNearTarget() + .pointAt(leverVec); + scene.idle(70); + + scene.overlay.showControls(new InputWindowElement(leverVec, Pointing.DOWN).rightClick() + .whileSneaking(), 40); + scene.idle(7); + for (int i = 7; i > 0; i--) { + scene.idle(2); + final int state = i - 1; + if (i > 3) { + scene.world.modifyTileNBT(leverSelection, AnalogLeverTileEntity.class, + nbt -> nbt.putInt("State", state)); + scene.effects.indicateRedstone(wireLocations[i]); + } + scene.world.modifyBlock(wireLocations[i], s -> s.with(power, state > 2 ? 0 : 3 - state), false); + } + scene.world.modifyBlock(wireLocations[0], s -> s.with(power, 3), false); + scene.idle(20); + + scene.overlay.showText(60) + .attachKeyFrame() + .text("Right-click while Sneaking to decrease the power output again") + .placeNearTarget() + .pointAt(leverVec); + scene.idle(70); + + scene.overlay.showControls(new InputWindowElement(leverVec, Pointing.DOWN).rightClick(), 40); + scene.idle(7); + for (int i = 0; i < 15; i++) { + scene.idle(2); + final int state = i + 1; + if (i >= 4) { + scene.world.modifyTileNBT(leverSelection, AnalogLeverTileEntity.class, + nbt -> nbt.putInt("State", state)); + scene.effects.indicateRedstone(wireLocations[i]); + } + scene.world.modifyBlock(wireLocations[i], s -> s.with(power, 15 - state), false); + } + + scene.world.toggleRedstonePower(lamp); + scene.effects.indicateRedstone(leverPos); + scene.effects.indicateRedstone(util.grid.at(4, 1, 1)); + scene.idle(20); + } + + public static void nixieTube(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("analog_lever", "Using Nixie Tubes"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0) + .add(util.select.fromTo(2, 1, 1, 2, 1, 2)), Direction.UP); + scene.idle(10); + scene.world.showSection(util.select.position(2, 1, 3), Direction.DOWN); + scene.idle(20); + + Selection tubes = util.select.fromTo(3, 1, 3, 1, 1, 3); + + scene.effects.indicateRedstone(util.grid.at(2, 1, 1)); + scene.world.modifyTileNBT(util.select.position(2, 1, 1), AnalogLeverTileEntity.class, + nbt -> nbt.putInt("State", 11)); + scene.world.modifyBlock(util.grid.at(2, 1, 2), s -> s.with(RedstoneWireBlock.POWER, 11), false); + scene.world.modifyTileNBT(tubes, NixieTubeTileEntity.class, nbt -> nbt.putInt("RedstoneStrength", 11)); + scene.idle(20); + + Vector3d centerTube = util.vector.centerOf(2, 1, 3); + + scene.overlay.showText(60) + .attachKeyFrame() + .text("When powered by Redstone, Nixie Tubes will display the redstone signals' strength") + .placeNearTarget() + .pointAt(util.vector.blockSurface(util.grid.at(2, 1, 3), Direction.WEST)); + scene.idle(70); + + scene.world.hideSection(util.select.position(2, 1, 3), Direction.UP); + scene.idle(5); + scene.world.hideSection(util.select.fromTo(2, 1, 1, 2, 1, 2), Direction.NORTH); + scene.idle(10); + scene.world.modifyTileNBT(tubes, NixieTubeTileEntity.class, nbt -> nbt.putInt("RedstoneStrength", 0)); + scene.world.showSection(tubes, Direction.DOWN); + scene.idle(20); + + scene.overlay.showControls(new InputWindowElement(centerTube.add(0, .35, 0), Pointing.DOWN).rightClick() + .withItem(new ItemStack(Items.NAME_TAG)), 40); + scene.idle(7); + + ITextComponent component = new StringTextComponent("CREATE"); + for (int i = 0; i < 3; i++) { + final int index = i; + scene.world.modifyTileNBT(util.select.position(3 - i, 1, 3), NixieTubeTileEntity.class, nbt -> { + nbt.putString("RawCustomText", component.getString()); + nbt.putString("CustomText", ITextComponent.Serializer.toJson(component)); + nbt.putInt("CustomTextIndex", index); + }); + } + + scene.idle(10); + scene.world.showSection(util.select.position(4, 1, 3), Direction.DOWN); + scene.idle(10); + scene.special.createBirb(util.vector.topOf(util.grid.at(0, 0, 3)), ParrotElement.DancePose::new); + + scene.idle(20); + scene.overlay.showText(80) + .attachKeyFrame() + .text("Using name tags edited with an anvil, custom text can be displayed") + .pointAt(util.vector.topOf(util.grid.at(2, 1, 3)) + .add(.25, -.05f, 0)); + scene.idle(70); + } + + public static void redstoneLink(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("redstone_link", "Using Redstone Links"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0) + .add(util.select.fromTo(3, 1, 1, 2, 1, 1)), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(4, 1, 3, 0, 2, 3), Direction.DOWN); + scene.idle(10); + + Selection redstone = util.select.fromTo(3, 1, 1, 1, 1, 1); + BlockPos leverPos = util.grid.at(3, 1, 1); + BlockPos link1Pos = util.grid.at(1, 1, 1); + BlockPos link2Pos = util.grid.at(1, 2, 2); + BlockPos link3Pos = util.grid.at(3, 2, 2); + Selection link1Select = util.select.position(link1Pos); + Selection link2Select = util.select.position(link2Pos); + Selection link3Select = util.select.position(link3Pos); + Vector3d link1Vec = util.vector.blockSurface(link1Pos, Direction.DOWN) + .add(0, 3 / 16f, 0); + Vector3d link2Vec = util.vector.blockSurface(link2Pos, Direction.SOUTH) + .add(0, 0, -3 / 16f); + Vector3d link3Vec = util.vector.blockSurface(link3Pos, Direction.SOUTH) + .add(0, 0, -3 / 16f); + + scene.world.showSection(link1Select, Direction.DOWN); + scene.idle(5); + scene.world.showSection(link2Select, Direction.DOWN); + scene.idle(5); + scene.world.showSection(link3Select, Direction.DOWN); + scene.idle(10); + + scene.overlay.showText(50) + .attachKeyFrame() + .text("Redstone Links can transmit redstone signals wirelessly") + .placeNearTarget() + .pointAt(link1Vec); + scene.idle(60); + + scene.overlay.showControls(new InputWindowElement(link2Vec, Pointing.UP).rightClick() + .whileSneaking(), 40); + scene.idle(7); + scene.world.modifyBlock(link2Pos, s -> s.cycle(RedstoneLinkBlock.RECEIVER), true); + scene.idle(10); + scene.overlay.showText(50) + .text("Right-click while Sneaking to toggle receive mode") + .placeNearTarget() + .pointAt(link2Vec); + scene.idle(60); + + scene.overlay.showControls(new InputWindowElement(link3Vec, Pointing.UP).rightClick() + .withWrench(), 40); + scene.idle(7); + scene.world.modifyBlock(link3Pos, s -> s.cycle(RedstoneLinkBlock.RECEIVER), true); + scene.idle(10); + scene.overlay.showText(50) + .text("A simple Right-click with a Wrench can do the same") + .placeNearTarget() + .pointAt(link3Vec); + scene.idle(70); + + scene.addKeyframe(); + scene.idle(10); + scene.world.toggleRedstonePower(redstone); + scene.effects.indicateRedstone(leverPos); + scene.idle(5); + scene.world.toggleRedstonePower(util.select.fromTo(3, 2, 3, 1, 2, 2)); + scene.effects.indicateRedstone(link2Pos); + scene.effects.indicateRedstone(link3Pos); + + scene.idle(10); + scene.overlay.showText(70) + .colored(PonderPalette.GREEN) + .text("Receivers emit the redstone power of transmitters within 128 blocks") + .placeNearTarget() + .pointAt(link2Vec); + scene.idle(80); + scene.world.toggleRedstonePower(redstone); + scene.idle(5); + scene.world.toggleRedstonePower(util.select.fromTo(3, 2, 3, 1, 2, 2)); + scene.idle(20); + + Vector3d frontSlot = link1Vec.add(.18, -.05, -.15); + Vector3d backSlot = link1Vec.add(.18, -.05, .15); + Vector3d top2Slot = link2Vec.add(-.09, .15, 0); + Vector3d bottom2Slot = link2Vec.add(-.09, -.2, 0); + Vector3d top3Slot = link3Vec.add(-.09, .15, 0); + Vector3d bottom3Slot = link3Vec.add(-.09, -.2, 0); + + scene.addKeyframe(); + scene.idle(10); + scene.overlay.showFilterSlotInput(frontSlot, 100); + scene.overlay.showFilterSlotInput(backSlot, 100); + scene.idle(10); + + scene.overlay.showText(50) + .text("Placing items in the two slots can specify a Frequency") + .placeNearTarget() + .pointAt(backSlot); + scene.idle(60); + + ItemStack iron = new ItemStack(Items.IRON_INGOT); + ItemStack gold = new ItemStack(Items.GOLD_INGOT); + ItemStack sapling = new ItemStack(Items.OAK_SAPLING); + + scene.overlay.showControls(new InputWindowElement(backSlot, Pointing.DOWN).withItem(iron), 40); + scene.idle(7); + scene.overlay.showControls(new InputWindowElement(frontSlot, Pointing.UP).withItem(sapling), 40); + scene.world.modifyTileNBT(link1Select, RedstoneLinkTileEntity.class, + nbt -> nbt.put("FrequencyLast", iron.write(new CompoundNBT()))); + scene.idle(7); + scene.world.modifyTileNBT(link1Select, RedstoneLinkTileEntity.class, + nbt -> nbt.put("FrequencyFirst", sapling.write(new CompoundNBT()))); + scene.idle(20); + + scene.overlay.showControls(new InputWindowElement(top2Slot, Pointing.DOWN).withItem(iron), 40); + scene.idle(7); + scene.overlay.showControls(new InputWindowElement(bottom2Slot, Pointing.UP).withItem(sapling), 40); + scene.world.modifyTileNBT(link2Select, RedstoneLinkTileEntity.class, + nbt -> nbt.put("FrequencyLast", iron.write(new CompoundNBT()))); + scene.idle(7); + scene.world.modifyTileNBT(link2Select, RedstoneLinkTileEntity.class, + nbt -> nbt.put("FrequencyFirst", sapling.write(new CompoundNBT()))); + scene.idle(20); + + scene.overlay.showControls(new InputWindowElement(top3Slot, Pointing.DOWN).withItem(gold), 40); + scene.idle(7); + scene.overlay.showControls(new InputWindowElement(bottom3Slot, Pointing.UP).withItem(sapling), 40); + scene.world.modifyTileNBT(link3Select, RedstoneLinkTileEntity.class, + nbt -> nbt.put("FrequencyLast", gold.write(new CompoundNBT()))); + scene.idle(7); + scene.world.modifyTileNBT(link3Select, RedstoneLinkTileEntity.class, + nbt -> nbt.put("FrequencyFirst", sapling.write(new CompoundNBT()))); + scene.idle(20); + + scene.world.toggleRedstonePower(redstone); + scene.effects.indicateRedstone(leverPos); + scene.idle(5); + scene.world.toggleRedstonePower(util.select.fromTo(1, 2, 2, 1, 2, 3)); + scene.effects.indicateRedstone(link2Pos); + scene.overlay.showText(90) + .attachKeyFrame() + .text("Only the links with matching Frequencies will communicate") + .placeNearTarget() + .pointAt(link2Vec); + scene.idle(100); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/SharedText.java b/src/main/java/com/simibubi/create/foundation/ponder/content/SharedText.java new file mode 100644 index 000000000..bd83c5bd6 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/SharedText.java @@ -0,0 +1,32 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.foundation.ponder.PonderLocalization; + +public class SharedText { + + public static void gatherText() { + // Add entries used across several ponder scenes (Safe for hotswap) + + add("sneak_and", "Sneak +"); + add("ctrl_and", "Ctrl +"); + + add("rpm8", "8 RPM"); + add("rpm16", "16 RPM"); + add("rpm16_source", "Source: 16 RPM"); + add("rpm32", "32 RPM"); + + add("movement_anchors", "With the help of Chassis or Super Glue, larger structures can be moved."); + add("behaviour_modify_wrench", "This behaviour can be modified using a Wrench"); + add("storage_on_contraption", "Inventories attached to the Contraption will pick up their drops automatically"); + + } + + public static String get(String key) { + return PonderLocalization.getShared(key); + } + + private static void add(String k, String v) { + PonderLocalization.registerShared(k, v); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/TemplateScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/TemplateScenes.java new file mode 100644 index 000000000..72fc1b7e5 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/TemplateScenes.java @@ -0,0 +1,18 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.foundation.ponder.SceneBuilder; +import com.simibubi.create.foundation.ponder.SceneBuildingUtil; + +import net.minecraft.util.Direction; + +public class TemplateScenes { + + public static void templateMethod(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("", ""); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.layersFrom(1), Direction.DOWN); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/AnimatedOverlayElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/AnimatedOverlayElement.java new file mode 100644 index 000000000..8f2fc1375 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/AnimatedOverlayElement.java @@ -0,0 +1,29 @@ +package com.simibubi.create.foundation.ponder.elements; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; + +public abstract class AnimatedOverlayElement extends PonderOverlayElement { + + protected LerpedFloat fade; + + public AnimatedOverlayElement() { + fade = LerpedFloat.linear() + .startWithValue(0); + } + + public void setFade(float fade) { + this.fade.setValue(fade); + } + + @Override + public final void render(PonderScene scene, PonderUI screen, MatrixStack ms, float partialTicks) { + float currentFade = fade.getValue(partialTicks); + render(scene, screen, ms, partialTicks, currentFade); + } + + protected abstract void render(PonderScene scene, PonderUI screen, MatrixStack ms, float partialTicks, float fade); + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/AnimatedSceneElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/AnimatedSceneElement.java new file mode 100644 index 000000000..fa5e0ff54 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/AnimatedSceneElement.java @@ -0,0 +1,84 @@ +package com.simibubi.create.foundation.ponder.elements; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.ponder.PonderWorld; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.foundation.utility.MatrixStacker; + +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3d; + +public abstract class AnimatedSceneElement extends PonderSceneElement { + + protected Vector3d fadeVec; + protected LerpedFloat fade; + + public AnimatedSceneElement() { + fade = LerpedFloat.linear() + .startWithValue(0); + } + + public void forceApplyFade(float fade) { + this.fade.startWithValue(fade); + } + + public void setFade(float fade) { + this.fade.setValue(fade); + } + + public void setFadeVec(Vector3d fadeVec) { + this.fadeVec = fadeVec; + } + + @Override + public final void renderFirst(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float pt) { + ms.push(); + float currentFade = applyFade(ms, pt); + renderFirst(world, buffer, ms, currentFade, pt); + ms.pop(); + } + + @Override + public final void renderLayer(PonderWorld world, IRenderTypeBuffer buffer, RenderType type, MatrixStack ms, + float pt) { + ms.push(); + float currentFade = applyFade(ms, pt); + renderLayer(world, buffer, type, ms, currentFade, pt); + ms.pop(); + } + + @Override + public final void renderLast(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float pt) { + ms.push(); + float currentFade = applyFade(ms, pt); + renderLast(world, buffer, ms, currentFade, pt); + ms.pop(); + } + + protected float applyFade(MatrixStack ms, float pt) { + float currentFade = fade.getValue(pt); + if (fadeVec != null) + MatrixStacker.of(ms) + .translate(fadeVec.scale(-1 + currentFade)); + return currentFade; + } + + protected void renderLayer(PonderWorld world, IRenderTypeBuffer buffer, RenderType type, MatrixStack ms, float fade, + float pt) {} + + protected void renderFirst(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float fade, float pt) {} + + protected void renderLast(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float fade, float pt) {} + + protected int lightCoordsFromFade(float fade) { + int light = 0xF000F0; + if (fade != 1) { + light = (int) (MathHelper.lerp(fade, 5, 0xF)); + light = light << 4 | light << 20; + } + return light; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/BeltItemElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/BeltItemElement.java new file mode 100644 index 000000000..4935b3da4 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/BeltItemElement.java @@ -0,0 +1,11 @@ +package com.simibubi.create.foundation.ponder.elements; + +import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; + +public class BeltItemElement extends TrackedElement { + + public BeltItemElement(TransportedItemStack wrapped) { + super(wrapped); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/EntityElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/EntityElement.java new file mode 100644 index 000000000..556d300a4 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/EntityElement.java @@ -0,0 +1,16 @@ +package com.simibubi.create.foundation.ponder.elements; + +import net.minecraft.entity.Entity; + +public class EntityElement extends TrackedElement { + + public EntityElement(Entity wrapped) { + super(wrapped); + } + + @Override + protected boolean isStillValid(Entity element) { + return element.isAlive(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/InputWindowElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/InputWindowElement.java new file mode 100644 index 000000000..ddc951e1c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/InputWindowElement.java @@ -0,0 +1,140 @@ +package com.simibubi.create.foundation.ponder.elements; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.AllItems; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.GuiGameElement; +import com.simibubi.create.foundation.ponder.PonderLocalization; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.ponder.content.PonderPalette; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.Pointing; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.vector.Vector2f; +import net.minecraft.util.math.vector.Vector3d; + +public class InputWindowElement extends AnimatedOverlayElement { + + private Pointing direction; + String key; + AllIcons icon; + ItemStack item = ItemStack.EMPTY; + private Vector3d sceneSpace; + + public InputWindowElement clone() { + InputWindowElement inputWindowElement = new InputWindowElement(sceneSpace, direction); + inputWindowElement.key = key; + inputWindowElement.icon = icon; + inputWindowElement.item = item.copy(); + return inputWindowElement; + } + + public InputWindowElement(Vector3d sceneSpace, Pointing direction) { + this.sceneSpace = sceneSpace; + this.direction = direction; + } + + public InputWindowElement withItem(ItemStack stack) { + item = stack; + return this; + } + + public InputWindowElement withWrench() { + item = AllItems.WRENCH.asStack(); + return this; + } + + public InputWindowElement scroll() { + icon = AllIcons.I_SCROLL; + return this; + } + + public InputWindowElement rightClick() { + icon = AllIcons.I_RMB; + return this; + } + + public InputWindowElement leftClick() { + icon = AllIcons.I_LMB; + return this; + } + + public InputWindowElement whileSneaking() { + key = "sneak_and"; + return this; + } + + public InputWindowElement whileCTRL() { + key = "ctrl_and"; + return this; + } + + @Override + protected void render(PonderScene scene, PonderUI screen, MatrixStack ms, float partialTicks, float fade) { + FontRenderer font = screen.getFontRenderer(); + int width = 0; + int height = 0; + + int xFade = direction == Pointing.RIGHT ? -1 : direction == Pointing.LEFT ? 1 : 0; + int yFade = direction == Pointing.DOWN ? -1 : direction == Pointing.UP ? 1 : 0; + xFade *= 10 * (1 - fade); + yFade *= 10 * (1 - fade); + + boolean hasItem = !item.isEmpty(); + boolean hasText = key != null; + boolean hasIcon = icon != null; + int keyWidth = 0; + String text = hasText ? PonderLocalization.getShared(key) : ""; + + if (fade < 1 / 16f) + return; + Vector2f sceneToScreen = scene.getTransform().sceneToScreen(sceneSpace); + + if (hasIcon) { + width += 24; + height = 24; + } + + if (hasText) { + keyWidth = font.getStringWidth(text); + width += keyWidth; + } + + if (hasItem) { + width += 24; + height = 24; + } + + RenderSystem.pushMatrix(); + RenderSystem.translated(sceneToScreen.x + xFade, sceneToScreen.y + yFade, 400); + + PonderUI.renderSpeechBox(ms, 0, 0, width, height, false, direction, true); + + if (hasText) + font.draw(ms, text, 2, (height - font.FONT_HEIGHT) / 2f + 2, + ColorHelper.applyAlpha(PonderPalette.WHITE.getColor(), fade)); + + if (hasIcon) { + RenderSystem.pushMatrix(); + RenderSystem.translated(keyWidth, 0, 0); + RenderSystem.scaled(1.5, 1.5, 1.5); + icon.draw(ms, 0, 0); + RenderSystem.popMatrix(); + } + + if (hasItem) { + GuiGameElement.of(item) + .at(keyWidth + (hasIcon ? 24 : 0), 0) + .scale(1.5) + .render(ms); + RenderSystem.disableDepthTest(); + } + + RenderSystem.popMatrix(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/MinecartElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/MinecartElement.java new file mode 100644 index 000000000..93c0be467 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/MinecartElement.java @@ -0,0 +1,113 @@ +package com.simibubi.create.foundation.ponder.elements; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderWorld; +import com.simibubi.create.foundation.utility.MatrixStacker; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.World; + +public class MinecartElement extends AnimatedSceneElement { + + private Vector3d location; + private LerpedFloat rotation; + private AbstractMinecartEntity entity; + private MinecartConstructor constructor; + private float initialRotation; + + public interface MinecartConstructor { + AbstractMinecartEntity create(World w, double x, double y, double z); + } + + public MinecartElement(Vector3d location, float rotation, MinecartConstructor constructor) { + initialRotation = rotation; + this.location = location.add(0, 1 / 16f, 0); + this.constructor = constructor; + this.rotation = LerpedFloat.angular() + .startWithValue(rotation); + } + + @Override + public void reset(PonderScene scene) { + super.reset(scene); + entity.setPos(0, 0, 0); + entity.prevPosX = 0; + entity.prevPosY = 0; + entity.prevPosZ = 0; + entity.lastTickPosX = 0; + entity.lastTickPosY = 0; + entity.lastTickPosZ = 0; + rotation.startWithValue(initialRotation); + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + if (entity == null) + entity = constructor.create(scene.getWorld(), 0, 0, 0); + + entity.ticksExisted++; + entity.onGround = true; + entity.prevPosX = entity.getX(); + entity.prevPosY = entity.getY(); + entity.prevPosZ = entity.getZ(); + entity.lastTickPosX = entity.getX(); + entity.lastTickPosY = entity.getY(); + entity.lastTickPosZ = entity.getZ(); + } + + public void setPositionOffset(Vector3d position, boolean immediate) { + if (entity == null) + return; + entity.setPosition(position.x, position.y, position.z); + if (!immediate) + return; + entity.prevPosX = position.x; + entity.prevPosY = position.y; + entity.prevPosZ = position.z; + } + + public void setRotation(float angle, boolean immediate) { + if (entity == null) + return; + rotation.setValue(angle); + if (!immediate) + return; + rotation.startWithValue(angle); + } + + public Vector3d getPositionOffset() { + return entity != null ? entity.getPositionVec() : Vector3d.ZERO; + } + + public Vector3d getRotation() { + return new Vector3d(0, rotation.getValue(), 0); + } + + @Override + protected void renderLast(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float fade, float pt) { + EntityRendererManager entityrenderermanager = Minecraft.getInstance() + .getRenderManager(); + if (entity == null) + entity = constructor.create(world, 0, 0, 0); + + ms.push(); + ms.translate(location.x, location.y, location.z); + ms.translate(MathHelper.lerp(pt, entity.prevPosX, entity.getX()), + MathHelper.lerp(pt, entity.prevPosY, entity.getY()), MathHelper.lerp(pt, entity.prevPosZ, entity.getZ())); + + MatrixStacker.of(ms) + .rotateY(rotation.getValue(pt)); + + entityrenderermanager.render(entity, 0, 0, 0, 0, pt, ms, buffer, lightCoordsFromFade(fade)); + ms.pop(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/OutlinerElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/OutlinerElement.java new file mode 100644 index 000000000..44773221a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/OutlinerElement.java @@ -0,0 +1,35 @@ +package com.simibubi.create.foundation.ponder.elements; + +import java.util.function.Function; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams; +import com.simibubi.create.foundation.utility.outliner.Outliner; + +public class OutlinerElement extends AnimatedSceneElement { + + private Function outlinerCall; + private int overrideColor; + + public OutlinerElement(Function outlinerCall) { + this.outlinerCall = outlinerCall; + this.overrideColor = -1; + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + if (fade.getValue() < 1/16f) + return; + if (fade.getValue(0) > fade.getValue(1)) + return; + OutlineParams params = outlinerCall.apply(scene.getOutliner()); + if (overrideColor != -1) + params.colored(overrideColor); + } + + public void setColor(int overrideColor) { + this.overrideColor = overrideColor; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/ParrotElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/ParrotElement.java new file mode 100644 index 000000000..6f647b9f5 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/ParrotElement.java @@ -0,0 +1,254 @@ +package com.simibubi.create.foundation.ponder.elements; + +import java.util.function.Supplier; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.ponder.PonderWorld; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.MatrixStacker; + +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.passive.ParrotEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3d; + +public class ParrotElement extends AnimatedSceneElement { + + private Vector3d location; + private ParrotEntity entity; + private ParrotPose pose; + private Supplier initialPose; + + public static ParrotElement create(Vector3d location, Supplier pose) { + return new ParrotElement(location, pose); + } + + protected ParrotElement(Vector3d location, Supplier pose) { + this.location = location; + initialPose = pose; + setPose(initialPose.get()); + } + + @Override + public void reset(PonderScene scene) { + super.reset(scene); + setPose(initialPose.get()); + entity.setPos(0, 0, 0); + entity.prevPosX = 0; + entity.prevPosY = 0; + entity.prevPosZ = 0; + entity.lastTickPosX = 0; + entity.lastTickPosY = 0; + entity.lastTickPosZ = 0; + entity.prevRotationPitch = entity.rotationPitch = 0; + entity.prevRotationYaw = entity.rotationYaw = 180; + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + if (entity == null) { + entity = pose.create(scene.getWorld()); + entity.prevRotationYaw = entity.rotationYaw = 180; + } + + entity.ticksExisted++; + entity.prevRotationYawHead = entity.rotationYawHead; + entity.oFlapSpeed = entity.flapSpeed; + entity.oFlap = entity.flap; + entity.onGround = true; + + entity.prevPosX = entity.getX(); + entity.prevPosY = entity.getY(); + entity.prevPosZ = entity.getZ(); + entity.prevRotationYaw = entity.rotationYaw; + entity.prevRotationPitch = entity.rotationPitch; + + pose.tick(scene, entity, location); + + entity.lastTickPosX = entity.getX(); + entity.lastTickPosY = entity.getY(); + entity.lastTickPosZ = entity.getZ(); + } + + public void setPositionOffset(Vector3d position, boolean immediate) { + if (entity == null) + return; + entity.setPosition(position.x, position.y, position.z); + if (!immediate) + return; + entity.prevPosX = position.x; + entity.prevPosY = position.y; + entity.prevPosZ = position.z; + } + + public void setRotation(Vector3d eulers, boolean immediate) { + if (entity == null) + return; + entity.rotationPitch = (float) eulers.x; + entity.rotationYaw = (float) eulers.y; + if (!immediate) + return; + entity.prevRotationPitch = entity.rotationPitch; + entity.prevRotationYaw = entity.rotationYaw; + } + + public Vector3d getPositionOffset() { + return entity != null ? entity.getPositionVec() : Vector3d.ZERO; + } + + public Vector3d getRotation() { + return entity != null ? new Vector3d(entity.rotationPitch, entity.rotationYaw, 0) : Vector3d.ZERO; + } + + @Override + protected void renderLast(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float fade, float pt) { + EntityRendererManager entityrenderermanager = Minecraft.getInstance() + .getRenderManager(); + + if (entity == null) { + entity = pose.create(world); + entity.prevRotationYaw = entity.rotationYaw = 180; + } + + ms.push(); + ms.translate(location.x, location.y, location.z); + ms.translate(MathHelper.lerp(pt, entity.prevPosX, entity.getX()), + MathHelper.lerp(pt, entity.prevPosY, entity.getY()), MathHelper.lerp(pt, entity.prevPosZ, entity.getZ())); + + MatrixStacker.of(ms) + .rotateY(AngleHelper.angleLerp(pt, entity.prevRotationYaw, entity.rotationYaw)); + + entityrenderermanager.render(entity, 0, 0, 0, 0, pt, ms, buffer, lightCoordsFromFade(fade)); + ms.pop(); + } + + public void setPose(ParrotPose pose) { + this.pose = pose; + } + + public static abstract class ParrotPose { + + abstract void tick(PonderScene scene, ParrotEntity entity, Vector3d location); + + ParrotEntity create(PonderWorld world) { + ParrotEntity entity = new ParrotEntity(EntityType.PARROT, world); + int nextInt = Create.random.nextInt(5); + entity.setVariant(nextInt == 1 ? 0 : nextInt); // blue parrots are kinda hard to see + return entity; + } + + } + + public static class DancePose extends ParrotPose { + + @Override + ParrotEntity create(PonderWorld world) { + ParrotEntity entity = super.create(world); + entity.setPartying(BlockPos.ZERO, true); + return entity; + } + + @Override + void tick(PonderScene scene, ParrotEntity entity, Vector3d location) { + entity.prevRotationYaw = entity.rotationYaw; + entity.rotationYaw -= 2; + } + + } + + public static class FlappyPose extends ParrotPose { + + @Override + void tick(PonderScene scene, ParrotEntity entity, Vector3d location) { + double length = entity.getPositionVec() + .subtract(entity.lastTickPosX, entity.lastTickPosY, entity.lastTickPosZ) + .length(); + entity.onGround = false; + double phase = Math.min(length * 15, 8); + float f = (float) ((PonderUI.ponderTicks % 100) * phase); + entity.flapSpeed = MathHelper.sin(f) + 1; + if (length == 0) + entity.flapSpeed = 0; + } + + } + + public static class SpinOnComponentPose extends ParrotPose { + + private BlockPos componentPos; + + public SpinOnComponentPose(BlockPos componentPos) { + this.componentPos = componentPos; + } + + @Override + void tick(PonderScene scene, ParrotEntity entity, Vector3d location) { + TileEntity tileEntity = scene.getWorld() + .getTileEntity(componentPos); + if (!(tileEntity instanceof KineticTileEntity)) + return; + float rpm = ((KineticTileEntity) tileEntity).getSpeed(); + entity.prevRotationYaw = entity.rotationYaw; + entity.rotationYaw += (rpm * .3f); + } + + } + + public static abstract class FaceVecPose extends ParrotPose { + + @Override + void tick(PonderScene scene, ParrotEntity entity, Vector3d location) { + Vector3d p_200602_2_ = getFacedVec(scene); + Vector3d Vector3d = location.add(entity.getEyePosition(0)); + double d0 = p_200602_2_.x - Vector3d.x; + double d1 = p_200602_2_.y - Vector3d.y; + double d2 = p_200602_2_.z - Vector3d.z; + double d3 = (double) MathHelper.sqrt(d0 * d0 + d2 * d2); + float targetPitch = + MathHelper.wrapDegrees((float) -(MathHelper.atan2(d1, d3) * (double) (180F / (float) Math.PI))); + float targetYaw = + MathHelper.wrapDegrees((float) -(MathHelper.atan2(d2, d0) * (double) (180F / (float) Math.PI)) + 90); + + entity.rotationPitch = AngleHelper.angleLerp(.4f, entity.rotationPitch, targetPitch); + entity.rotationYaw = AngleHelper.angleLerp(.4f, entity.rotationYaw, targetYaw); + } + + protected abstract Vector3d getFacedVec(PonderScene scene); + + } + + public static class FacePointOfInterestPose extends FaceVecPose { + + @Override + protected Vector3d getFacedVec(PonderScene scene) { + return scene.getPointOfInterest(); + } + + } + + public static class FaceCursorPose extends FaceVecPose { + + @Override + protected Vector3d getFacedVec(PonderScene scene) { + Minecraft minecraft = Minecraft.getInstance(); + MainWindow w = minecraft.getWindow(); + double mouseX = minecraft.mouseHelper.getMouseX() * w.getScaledWidth() / w.getWidth(); + double mouseY = minecraft.mouseHelper.getMouseY() * w.getScaledHeight() / w.getHeight(); + return scene.getTransform() + .screenToScene(mouseX, mouseY, 300); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/PonderOverlayElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/PonderOverlayElement.java new file mode 100644 index 000000000..89db05a60 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/PonderOverlayElement.java @@ -0,0 +1,14 @@ +package com.simibubi.create.foundation.ponder.elements; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.ponder.PonderElement; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderUI; + +public abstract class PonderOverlayElement extends PonderElement { + + public void tick(PonderScene scene) {} + + public abstract void render(PonderScene scene, PonderUI screen, MatrixStack ms, float partialTicks); + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/PonderSceneElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/PonderSceneElement.java new file mode 100644 index 000000000..dfa176d04 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/PonderSceneElement.java @@ -0,0 +1,18 @@ +package com.simibubi.create.foundation.ponder.elements; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.ponder.PonderElement; +import com.simibubi.create.foundation.ponder.PonderWorld; + +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; + +public abstract class PonderSceneElement extends PonderElement { + + public abstract void renderFirst(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float pt); + + public abstract void renderLayer(PonderWorld world, IRenderTypeBuffer buffer, RenderType type, MatrixStack ms, float pt); + + public abstract void renderLast(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float pt); + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/TextWindowElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/TextWindowElement.java new file mode 100644 index 000000000..a20e0f63b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/TextWindowElement.java @@ -0,0 +1,138 @@ +package com.simibubi.create.foundation.ponder.elements; + +import java.util.List; +import java.util.function.Supplier; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.ponder.PonderLocalization; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.ponder.content.PonderPalette; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.FontHelper; + +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.Vector2f; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.ITextProperties; +import net.minecraft.util.text.Style; +import net.minecraftforge.fml.client.gui.GuiUtils; + +public class TextWindowElement extends AnimatedOverlayElement { + + Supplier textGetter = () -> "(?) No text was provided"; + String bakedText; + + // from 0 to 200 + int y; + + Vector3d vec; + + boolean nearScene = false; + int color = PonderPalette.WHITE.getColor(); + + public class Builder { + + private PonderScene scene; + + public Builder(PonderScene scene) { + this.scene = scene; + } + + public Builder colored(PonderPalette color) { + TextWindowElement.this.color = color.getColor(); + return this; + } + + public Builder pointAt(Vector3d vec) { + TextWindowElement.this.vec = vec; + return this; + } + + public Builder independent(int y) { + TextWindowElement.this.y = y; + return this; + } + + public Builder independent() { + return independent(0); + } + + public Builder text(String defaultText) { + textGetter = scene.registerText(defaultText); + return this; + } + + public Builder sharedText(String key) { + textGetter = () -> PonderLocalization.getShared(key); + return this; + } + + public Builder placeNearTarget() { + TextWindowElement.this.nearScene = true; + return this; + } + + public Builder attachKeyFrame() { + scene.builder() + .addLazyKeyframe(); + return this; + } + + } + + @Override + protected void render(PonderScene scene, PonderUI screen, MatrixStack ms, float partialTicks, float fade) { + if (bakedText == null) + bakedText = textGetter.get(); + if (fade < 1 / 16f) + return; + Vector2f sceneToScreen = vec != null ? scene.getTransform() + .sceneToScreen(vec) : new Vector2f(screen.width / 2f, (screen.height - 200) / 2f + y - 8); + + float yDiff = (screen.height / 2f - sceneToScreen.y - 10) / 100f; + int targetX = (int) (screen.width * MathHelper.lerp(yDiff * yDiff, 6f / 8, 5f / 8)); + + if (nearScene) + targetX = (int) Math.min(targetX, sceneToScreen.x + 50); + + int textWidth = Math.min(screen.width - targetX, 180); + + List lines = screen.getFontRenderer().getTextHandler().wrapLines(bakedText, textWidth, Style.EMPTY); + + int boxWidth = 0; + for (ITextProperties line : lines) + boxWidth = Math.max(boxWidth, screen.getFontRenderer().getWidth(line)); + + int boxHeight = screen.getFontRenderer() + .getWordWrappedHeight(bakedText, boxWidth); + + RenderSystem.pushMatrix(); + RenderSystem.translatef(0, sceneToScreen.y, 400); + + PonderUI.renderBox(ms, targetX - 10, 3, boxWidth, boxHeight - 1, 0xaa000000, 0x30eebb00, 0x10eebb00); + + int brighterColor = ColorHelper.mixAlphaColors(color, 0xFFffffdd, 1 / 2f); + if (vec != null) { + RenderSystem.pushMatrix(); + RenderSystem.translatef(sceneToScreen.x, 0, 0); + double lineTarget = (targetX - sceneToScreen.x) * fade; + RenderSystem.scaled(lineTarget, 1, 1); + Matrix4f model = ms.peek().getModel(); + GuiUtils.drawGradientRect(model, -100, 0, 0, 1, 1, brighterColor, brighterColor); + GuiUtils.drawGradientRect(model, -100, 0, 1, 1, 2, 0xFF494949, 0xFF393939); + RenderSystem.popMatrix(); + } + + FontHelper.drawSplitString(screen.getFontRenderer(), bakedText, targetX - 10, 3, textWidth, + ColorHelper.applyAlpha(brighterColor, fade)); + RenderSystem.popMatrix(); + } + + public int getColor() { + return color; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/TrackedElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/TrackedElement.java new file mode 100644 index 000000000..b7c2cd7f9 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/TrackedElement.java @@ -0,0 +1,42 @@ +package com.simibubi.create.foundation.ponder.elements; + +import java.lang.ref.WeakReference; +import java.util.function.Consumer; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.ponder.PonderWorld; + +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; + +public abstract class TrackedElement extends PonderSceneElement { + + private WeakReference reference; + + public TrackedElement(T wrapped) { + this.reference = new WeakReference<>(wrapped); + } + + public void ifPresent(Consumer func) { + if (reference == null) + return; + T resolved = reference.get(); + if (resolved == null) + return; + func.accept(resolved); + } + + protected boolean isStillValid(T element) { + return true; + } + + @Override + public void renderFirst(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float pt) {} + + @Override + public void renderLayer(PonderWorld world, IRenderTypeBuffer buffer, RenderType type, MatrixStack ms, float pt) {} + + @Override + public void renderLast(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float pt) {} + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/WorldSectionElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/WorldSectionElement.java new file mode 100644 index 000000000..3d28d0283 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/WorldSectionElement.java @@ -0,0 +1,412 @@ +package com.simibubi.create.foundation.ponder.elements; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; + +import net.minecraft.fluid.FluidState; +import net.minecraft.util.math.vector.Vector3d; +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import com.mojang.blaze3d.vertex.MatrixApplyingVertexBuilder; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderWorld; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.render.Compartment; +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBufferCache; +import com.simibubi.create.foundation.render.TileEntityRenderHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import com.simibubi.create.foundation.utility.Pair; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BlockModelRenderer; +import net.minecraft.client.renderer.BlockRendererDispatcher; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.RenderTypeLookup; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.model.ModelBakery; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceContext.BlockMode; +import net.minecraft.util.math.RayTraceContext.FluidMode; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.data.EmptyModelData; + +public class WorldSectionElement extends AnimatedSceneElement { + + public static final Compartment> DOC_WORLD_SECTION = new Compartment<>(); + + List renderedTileEntities; + Selection section; + boolean redraw; + + Vector3d prevAnimatedOffset = Vector3d.ZERO; + Vector3d animatedOffset = Vector3d.ZERO; + Vector3d prevAnimatedRotation = Vector3d.ZERO; + Vector3d animatedRotation = Vector3d.ZERO; + Vector3d centerOfRotation = Vector3d.ZERO; + Vector3d stabilizationAnchor = null; + + BlockPos selectedBlock; + + public WorldSectionElement() {} + + public WorldSectionElement(Selection section) { + this.section = section.copy(); + centerOfRotation = section.getCenter(); + } + + public void mergeOnto(WorldSectionElement other) { + setVisible(false); + if (other.isEmpty()) + other.set(section); + else + other.add(section); + } + + public void set(Selection selection) { + applyNewSelection(selection.copy()); + } + + public void add(Selection toAdd) { + applyNewSelection(this.section.add(toAdd)); + } + + public void erase(Selection toErase) { + applyNewSelection(this.section.substract(toErase)); + } + + private void applyNewSelection(Selection selection) { + this.section = selection; + queueRedraw(); + } + + public void setCenterOfRotation(Vector3d center) { + centerOfRotation = center; + } + + public void stabilizeRotation(Vector3d anchor) { + stabilizationAnchor = anchor; + } + + @Override + public void reset(PonderScene scene) { + super.reset(scene); + resetAnimatedTransform(); + resetSelectedBlock(); + } + + public void selectBlock(BlockPos pos) { + selectedBlock = pos; + } + + public void resetSelectedBlock() { + selectedBlock = null; + } + + public void resetAnimatedTransform() { + prevAnimatedOffset = Vector3d.ZERO; + animatedOffset = Vector3d.ZERO; + prevAnimatedRotation = Vector3d.ZERO; + animatedRotation = Vector3d.ZERO; + } + + public void queueRedraw() { + redraw = true; + } + + public boolean isEmpty() { + return section == null; + } + + public void setEmpty() { + section = null; + } + + public void setAnimatedRotation(Vector3d eulerAngles, boolean force) { + this.animatedRotation = eulerAngles; + if (force) + prevAnimatedRotation = animatedRotation; + } + + public Vector3d getAnimatedRotation() { + return animatedRotation; + } + + public void setAnimatedOffset(Vector3d offset, boolean force) { + this.animatedOffset = offset; + if (force) + prevAnimatedOffset = animatedOffset; + } + + public Vector3d getAnimatedOffset() { + return animatedOffset; + } + + @Override + public boolean isVisible() { + return super.isVisible() && !isEmpty(); + } + + class WorldSectionRayTraceResult { + Vector3d actualHitVec; + BlockPos worldPos; + } + + public Pair rayTrace(PonderWorld world, Vector3d source, Vector3d target) { + world.setMask(this.section); + Vector3d transformedTarget = reverseTransformVec(target); + BlockRayTraceResult rayTraceBlocks = world.rayTraceBlocks(new RayTraceContext(reverseTransformVec(source), + transformedTarget, BlockMode.OUTLINE, FluidMode.NONE, null)); + world.clearMask(); + + if (rayTraceBlocks == null) + return null; + if (rayTraceBlocks.getHitVec() == null) + return null; + + double t = rayTraceBlocks.getHitVec() + .subtract(transformedTarget) + .lengthSquared() + / source.subtract(target) + .lengthSquared(); + Vector3d actualHit = VecHelper.lerp((float) t, target, source); + return Pair.of(actualHit, rayTraceBlocks.getPos()); + } + + private Vector3d reverseTransformVec(Vector3d in) { + float pt = AnimationTickHolder.getPartialTicks(); + in = in.subtract(VecHelper.lerp(pt, prevAnimatedOffset, animatedOffset)); + if (!animatedRotation.equals(Vector3d.ZERO) || !prevAnimatedRotation.equals(Vector3d.ZERO)) { + if (centerOfRotation == null) + centerOfRotation = section.getCenter(); + double rotX = MathHelper.lerp(pt, prevAnimatedRotation.x, animatedRotation.x); + double rotZ = MathHelper.lerp(pt, prevAnimatedRotation.z, animatedRotation.z); + double rotY = MathHelper.lerp(pt, prevAnimatedRotation.y, animatedRotation.y); + in = in.subtract(centerOfRotation); + in = VecHelper.rotate(in, -rotX, Axis.X); + in = VecHelper.rotate(in, -rotZ, Axis.Z); + in = VecHelper.rotate(in, -rotY, Axis.Y); + in = in.add(centerOfRotation); + if (stabilizationAnchor != null) { + in = in.subtract(stabilizationAnchor); + in = VecHelper.rotate(in, rotX, Axis.X); + in = VecHelper.rotate(in, rotZ, Axis.Z); + in = VecHelper.rotate(in, rotY, Axis.Y); + in = in.add(stabilizationAnchor); + } + } + return in; + } + + public void transformMS(MatrixStack ms, float pt) { + MatrixStacker.of(ms) + .translate(VecHelper.lerp(pt, prevAnimatedOffset, animatedOffset)); + if (!animatedRotation.equals(Vector3d.ZERO) || !prevAnimatedRotation.equals(Vector3d.ZERO)) { + if (centerOfRotation == null) + centerOfRotation = section.getCenter(); + double rotX = MathHelper.lerp(pt, prevAnimatedRotation.x, animatedRotation.x); + double rotZ = MathHelper.lerp(pt, prevAnimatedRotation.z, animatedRotation.z); + double rotY = MathHelper.lerp(pt, prevAnimatedRotation.y, animatedRotation.y); + MatrixStacker.of(ms) + .translate(centerOfRotation) + .rotateX(rotX) + .rotateZ(rotZ) + .rotateY(rotY) + .translateBack(centerOfRotation); + if (stabilizationAnchor != null) { + MatrixStacker.of(ms) + .translate(stabilizationAnchor) + .rotateX(-rotX) + .rotateZ(-rotZ) + .rotateY(-rotY) + .translateBack(stabilizationAnchor); + } + } + } + + public void tick(PonderScene scene) { + prevAnimatedOffset = animatedOffset; + prevAnimatedRotation = animatedRotation; + if (!isVisible()) + return; + loadTEsIfMissing(scene.getWorld()); + renderedTileEntities.removeIf(te -> scene.getWorld() + .getTileEntity(te.getPos()) != te); + renderedTileEntities.forEach(te -> { + if (te instanceof ITickableTileEntity) + ((ITickableTileEntity) te).tick(); + }); + } + + @Override + public void whileSkipping(PonderScene scene) { + if (redraw) + renderedTileEntities = null; + redraw = false; + } + + protected void loadTEsIfMissing(PonderWorld world) { + if (renderedTileEntities != null) + return; + renderedTileEntities = new ArrayList<>(); + section.forEach(pos -> { + TileEntity tileEntity = world.getTileEntity(pos); + if (tileEntity == null) + return; + renderedTileEntities.add(tileEntity); + tileEntity.updateContainingBlockInfo(); + }); + } + + @Override + protected void renderLayer(PonderWorld world, IRenderTypeBuffer buffer, RenderType type, MatrixStack ms, float fade, + float pt) { + transformMS(ms, pt); + renderStructure(world, ms, buffer, type, fade); + } + + @Override + public void renderFirst(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float fade, float pt) { + int light = -1; + if (fade != 1) + light = (int) (MathHelper.lerp(fade, 5, 14)); + if (redraw) + renderedTileEntities = null; + transformMS(ms, pt); + world.pushFakeLight(light); + renderTileEntities(world, ms, buffer, pt); + world.popLight(); + + Map blockBreakingProgressions = world.getBlockBreakingProgressions(); + MatrixStack overlayMS = null; + + for (Entry entry : blockBreakingProgressions.entrySet()) { + BlockPos pos = entry.getKey(); + if (!section.test(pos)) + continue; + if (overlayMS == null) { + overlayMS = new MatrixStack(); + world.scene.getTransform() + .apply(overlayMS, pt, true); + transformMS(overlayMS, pt); + } + ms.push(); + ms.translate(pos.getX(), pos.getY(), pos.getZ()); + IVertexBuilder builder = new MatrixApplyingVertexBuilder( + buffer.getBuffer(ModelBakery.BLOCK_DESTRUCTION_RENDER_LAYERS.get(entry.getValue())), + overlayMS.peek().getModel(), + overlayMS.peek().getNormal()); + Minecraft.getInstance() + .getBlockRendererDispatcher() + .renderModel(world.getBlockState(pos), pos, world, ms, builder, true, world.rand, EmptyModelData.INSTANCE); + ms.pop(); + } + } + + protected void renderStructure(PonderWorld world, MatrixStack ms, IRenderTypeBuffer buffer, RenderType type, + float fade) { + SuperByteBufferCache bufferCache = CreateClient.bufferCache; + int code = hashCode() ^ world.hashCode(); + + Pair key = Pair.of(code, RenderType.getBlockLayers() + .indexOf(type)); + if (redraw) + bufferCache.invalidate(DOC_WORLD_SECTION, key); + SuperByteBuffer contraptionBuffer = + bufferCache.get(DOC_WORLD_SECTION, key, () -> buildStructureBuffer(world, type)); + if (contraptionBuffer.isEmpty()) + return; + + int light = lightCoordsFromFade(fade); + contraptionBuffer.light(light) + .renderInto(ms, buffer.getBuffer(type)); + } + + @Override + protected void renderLast(PonderWorld world, IRenderTypeBuffer buffer, MatrixStack ms, float fade, float pt) { + redraw = false; + if (selectedBlock == null) + return; + BlockState blockState = world.getBlockState(selectedBlock); + if (blockState.isAir(world, selectedBlock)) + return; + VoxelShape shape = + blockState.getShape(world, selectedBlock, ISelectionContext.forEntity(Minecraft.getInstance().player)); + if (shape.isEmpty()) + return; + + ms.push(); + transformMS(ms, pt); + RenderSystem.disableTexture(); + WorldRenderer.drawBox(ms, buffer.getBuffer(RenderType.getLines()), shape.getBoundingBox() + .offset(selectedBlock), 1, 1, 1, 0.6f); + ms.pop(); + } + + private void renderTileEntities(PonderWorld world, MatrixStack ms, IRenderTypeBuffer buffer, float pt) { + loadTEsIfMissing(world); + TileEntityRenderHelper.renderTileEntities(world, renderedTileEntities, ms, new MatrixStack(), buffer, pt); + } + + private SuperByteBuffer buildStructureBuffer(PonderWorld world, RenderType layer) { + ForgeHooksClient.setRenderLayer(layer); + MatrixStack ms = new MatrixStack(); + BlockRendererDispatcher dispatcher = Minecraft.getInstance() + .getBlockRendererDispatcher(); + BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer(); + Random random = new Random(); + BufferBuilder builder = new BufferBuilder(DefaultVertexFormats.BLOCK.getIntegerSize()); + builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); + world.setMask(this.section); + + section.forEach(pos -> { + BlockState state = world.getBlockState(pos); + FluidState ifluidstate = world.getFluidState(pos); + + ms.push(); + ms.translate(pos.getX(), pos.getY(), pos.getZ()); + + if (state.getRenderType() != BlockRenderType.ENTITYBLOCK_ANIMATED && state.getBlock() != Blocks.AIR + && RenderTypeLookup.canRenderInLayer(state, layer)) { + TileEntity tileEntity = world.getTileEntity(pos); + blockRenderer.renderModel(world, dispatcher.getModelForState(state), state, pos, ms, builder, true, + random, 42, OverlayTexture.DEFAULT_UV, + tileEntity != null ? tileEntity.getModelData() : EmptyModelData.INSTANCE); + } + + if (!ifluidstate.isEmpty() && RenderTypeLookup.canRenderInLayer(ifluidstate, layer)) + dispatcher.renderFluid(pos, world, builder, ifluidstate); + + ms.pop(); + }); + + world.clearMask(); + builder.finishDrawing(); + return new SuperByteBuffer(builder); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateElementInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateElementInstruction.java new file mode 100644 index 000000000..21e2a6c4a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateElementInstruction.java @@ -0,0 +1,58 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.elements.PonderSceneElement; + +import net.minecraft.util.math.vector.Vector3d; + +public class AnimateElementInstruction extends TickingInstruction { + + protected Vector3d deltaPerTick; + protected Vector3d totalDelta; + protected Vector3d target; + protected ElementLink link; + protected T element; + + private BiConsumer setter; + private Function getter; + + protected AnimateElementInstruction(ElementLink link, Vector3d totalDelta, int ticks, + BiConsumer setter, Function getter) { + super(false, ticks); + this.link = link; + this.setter = setter; + this.getter = getter; + this.deltaPerTick = totalDelta.scale(1d / ticks); + this.totalDelta = totalDelta; + this.target = totalDelta; + } + + @Override + protected final void firstTick(PonderScene scene) { + super.firstTick(scene); + element = scene.resolve(link); + if (element == null) + return; + target = getter.apply(element) + .add(totalDelta); + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + if (element == null) + return; + if (remainingTicks == 0) { + setter.accept(element, target); + setter.accept(element, target); + return; + } + setter.accept(element, getter.apply(element) + .add(deltaPerTick)); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateMinecartInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateMinecartInstruction.java new file mode 100644 index 000000000..a96e111d5 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateMinecartInstruction.java @@ -0,0 +1,28 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.elements.MinecartElement; + +import net.minecraft.util.math.vector.Vector3d; + +public class AnimateMinecartInstruction extends AnimateElementInstruction { + + public static AnimateMinecartInstruction rotate(ElementLink link, float rotation, int ticks) { + return new AnimateMinecartInstruction(link, new Vector3d(0, rotation, 0), ticks, + (wse, v) -> wse.setRotation((float) v.y, ticks == 0), MinecartElement::getRotation); + } + + public static AnimateMinecartInstruction move(ElementLink link, Vector3d offset, int ticks) { + return new AnimateMinecartInstruction(link, offset, ticks, (wse, v) -> wse.setPositionOffset(v, ticks == 0), + MinecartElement::getPositionOffset); + } + + protected AnimateMinecartInstruction(ElementLink link, Vector3d totalDelta, int ticks, + BiConsumer setter, Function getter) { + super(link, totalDelta, ticks, setter, getter); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateParrotInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateParrotInstruction.java new file mode 100644 index 000000000..e0a45765b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateParrotInstruction.java @@ -0,0 +1,28 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.elements.ParrotElement; + +import net.minecraft.util.math.vector.Vector3d; + +public class AnimateParrotInstruction extends AnimateElementInstruction { + + public static AnimateParrotInstruction rotate(ElementLink link, Vector3d rotation, int ticks) { + return new AnimateParrotInstruction(link, rotation, ticks, (wse, v) -> wse.setRotation(v, ticks == 0), + ParrotElement::getRotation); + } + + public static AnimateParrotInstruction move(ElementLink link, Vector3d offset, int ticks) { + return new AnimateParrotInstruction(link, offset, ticks, (wse, v) -> wse.setPositionOffset(v, ticks == 0), + ParrotElement::getPositionOffset); + } + + protected AnimateParrotInstruction(ElementLink link, Vector3d totalDelta, int ticks, + BiConsumer setter, Function getter) { + super(link, totalDelta, ticks, setter, getter); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateTileEntityInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateTileEntityInstruction.java new file mode 100644 index 000000000..273d520b2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateTileEntityInstruction.java @@ -0,0 +1,83 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import java.util.Optional; +import java.util.function.BiConsumer; +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.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderWorld; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; + +public class AnimateTileEntityInstruction extends TickingInstruction { + + protected double deltaPerTick; + protected double totalDelta; + protected double target; + protected final BlockPos location; + + private BiConsumer setter; + private Function getter; + + public static AnimateTileEntityInstruction bearing(BlockPos location, float totalDelta, int ticks) { + return new AnimateTileEntityInstruction(location, totalDelta, ticks, + (w, f) -> castIfPresent(w, location, IBearingTileEntity.class).ifPresent(bte -> bte.setAngle(f)), + (w) -> castIfPresent(w, location, IBearingTileEntity.class).map(bte -> bte.getInterpolatedAngle(0)) + .orElse(0f)); + } + + public static AnimateTileEntityInstruction pulley(BlockPos location, float totalDelta, int ticks) { + return new AnimateTileEntityInstruction(location, totalDelta, ticks, + (w, f) -> castIfPresent(w, location, PulleyTileEntity.class).ifPresent(pulley -> pulley.animateOffset(f)), + (w) -> castIfPresent(w, location, PulleyTileEntity.class).map(pulley -> pulley.offset) + .orElse(0f)); + } + + public static AnimateTileEntityInstruction deployer(BlockPos location, float totalDelta, int ticks) { + return new AnimateTileEntityInstruction(location, totalDelta, ticks, + (w, f) -> castIfPresent(w, location, DeployerTileEntity.class) + .ifPresent(deployer -> deployer.setAnimatedOffset(f)), + (w) -> castIfPresent(w, location, DeployerTileEntity.class).map(deployer -> deployer.getHandOffset(1)) + .orElse(0f)); + } + + protected AnimateTileEntityInstruction(BlockPos location, float totalDelta, int ticks, + BiConsumer setter, Function getter) { + super(false, ticks); + this.location = location; + this.setter = setter; + this.getter = getter; + this.deltaPerTick = totalDelta * (1d / ticks); + this.totalDelta = totalDelta; + this.target = totalDelta; + } + + @Override + protected final void firstTick(PonderScene scene) { + super.firstTick(scene); + target = getter.apply(scene.getWorld()) + totalDelta; + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + PonderWorld world = scene.getWorld(); + float current = getter.apply(world); + float next = (float) (remainingTicks == 0 ? target : current + deltaPerTick); + setter.accept(world, next); + if (remainingTicks == 0) // lock interpolation + setter.accept(world, next); + } + + private static Optional castIfPresent(PonderWorld world, BlockPos pos, Class teType) { + TileEntity tileEntity = world.getTileEntity(pos); + if (teType.isInstance(tileEntity)) + return Optional.of(teType.cast(tileEntity)); + return Optional.empty(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateWorldSectionInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateWorldSectionInstruction.java new file mode 100644 index 000000000..5fb7b2c23 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/AnimateWorldSectionInstruction.java @@ -0,0 +1,29 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; + +import net.minecraft.util.math.vector.Vector3d; + +public class AnimateWorldSectionInstruction extends AnimateElementInstruction { + + public static AnimateWorldSectionInstruction rotate(ElementLink link, Vector3d rotation, + int ticks) { + return new AnimateWorldSectionInstruction(link, rotation, ticks, + (wse, v) -> wse.setAnimatedRotation(v, ticks == 0), WorldSectionElement::getAnimatedRotation); + } + + public static AnimateWorldSectionInstruction move(ElementLink link, Vector3d offset, int ticks) { + return new AnimateWorldSectionInstruction(link, offset, ticks, (wse, v) -> wse.setAnimatedOffset(v, ticks == 0), + WorldSectionElement::getAnimatedOffset); + } + + protected AnimateWorldSectionInstruction(ElementLink link, Vector3d totalDelta, int ticks, + BiConsumer setter, Function getter) { + super(link, totalDelta, ticks, setter, getter); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/ChaseAABBInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/ChaseAABBInstruction.java new file mode 100644 index 000000000..e0a19f30b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/ChaseAABBInstruction.java @@ -0,0 +1,30 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.content.PonderPalette; + +import net.minecraft.util.math.AxisAlignedBB; + +public class ChaseAABBInstruction extends TickingInstruction { + + private AxisAlignedBB bb; + private Object slot; + private PonderPalette color; + + public ChaseAABBInstruction(PonderPalette color, Object slot, AxisAlignedBB bb, int ticks) { + super(false, ticks); + this.color = color; + this.slot = slot; + this.bb = bb; + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + scene.getOutliner() + .chaseAABB(slot, bb) + .lineWidth(1 / 16f) + .colored(color.getColor()); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/CreateMinecartInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/CreateMinecartInstruction.java new file mode 100644 index 000000000..a6216f177 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/CreateMinecartInstruction.java @@ -0,0 +1,18 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.elements.MinecartElement; + +import net.minecraft.util.Direction; + +public class CreateMinecartInstruction extends FadeIntoSceneInstruction { + + public CreateMinecartInstruction(int fadeInTicks, Direction fadeInFrom, MinecartElement element) { + super(fadeInTicks, fadeInFrom, element); + } + + @Override + protected Class getElementClass() { + return MinecartElement.class; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/CreateParrotInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/CreateParrotInstruction.java new file mode 100644 index 000000000..56ada8ae2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/CreateParrotInstruction.java @@ -0,0 +1,18 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.elements.ParrotElement; + +import net.minecraft.util.Direction; + +public class CreateParrotInstruction extends FadeIntoSceneInstruction { + + public CreateParrotInstruction(int fadeInTicks, Direction fadeInFrom, ParrotElement element) { + super(fadeInTicks, fadeInFrom, element); + } + + @Override + protected Class getElementClass() { + return ParrotElement.class; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/DelayInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/DelayInstruction.java new file mode 100644 index 000000000..0965aa74b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/DelayInstruction.java @@ -0,0 +1,9 @@ +package com.simibubi.create.foundation.ponder.instructions; + +public class DelayInstruction extends TickingInstruction { + + public DelayInstruction(int ticks) { + super(true, ticks); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/DisplayWorldSectionInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/DisplayWorldSectionInstruction.java new file mode 100644 index 000000000..d9f5c70fc --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/DisplayWorldSectionInstruction.java @@ -0,0 +1,59 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import java.util.Optional; +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueItem; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; + +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; + +public class DisplayWorldSectionInstruction extends FadeIntoSceneInstruction { + + private Selection initialSelection; + private Optional> mergeOnto; + private BlockPos glue; + + public DisplayWorldSectionInstruction(int fadeInTicks, Direction fadeInFrom, Selection selection, + Optional> mergeOnto) { + this(fadeInTicks, fadeInFrom, selection, mergeOnto, null); + } + + public DisplayWorldSectionInstruction(int fadeInTicks, Direction fadeInFrom, Selection selection, + Optional> mergeOnto, @Nullable BlockPos glue) { + super(fadeInTicks, fadeInFrom, new WorldSectionElement(selection)); + initialSelection = selection; + this.mergeOnto = mergeOnto; + this.glue = glue; + } + + @Override + protected void firstTick(PonderScene scene) { + super.firstTick(scene); + mergeOnto.ifPresent(wse -> element.setAnimatedOffset(wse.get() + .getAnimatedOffset(), true)); + element.set(initialSelection); + element.setVisible(true); + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + if (remainingTicks > 0) + return; + mergeOnto.ifPresent(c -> element.mergeOnto(c.get())); + if (glue != null) + SuperGlueItem.spawnParticles(scene.getWorld(), glue, fadeInFrom, true); + } + + @Override + protected Class getElementClass() { + return WorldSectionElement.class; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/EmitParticlesInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/EmitParticlesInstruction.java new file mode 100644 index 000000000..176e79b05 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/EmitParticlesInstruction.java @@ -0,0 +1,56 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.Create; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderWorld; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.ParticleManager; +import net.minecraft.particles.IParticleData; +import net.minecraft.util.math.vector.Vector3d; + +public class EmitParticlesInstruction extends TickingInstruction { + + private Vector3d anchor; + private Emitter emitter; + private float runsPerTick; + + @FunctionalInterface + public static interface Emitter { + + public static Emitter simple(T data, Vector3d motion) { + return (w, x, y, z) -> w.addParticle(data, x, y, z, motion.x, motion.y, motion.z); + } + + public static Emitter withinBlockSpace(T data, Vector3d motion) { + return (w, x, y, z) -> w.addParticle(data, Math.floor(x) + Create.random.nextFloat(), + Math.floor(y) + Create.random.nextFloat(), Math.floor(z) + Create.random.nextFloat(), motion.x, + motion.y, motion.z); + } + + static ParticleManager paticleManager() { + return Minecraft.getInstance().particles; + } + + public void create(PonderWorld world, double x, double y, double z); + + } + + public EmitParticlesInstruction(Vector3d anchor, Emitter emitter, float runsPerTick, int ticks) { + super(false, ticks); + this.anchor = anchor; + this.emitter = emitter; + this.runsPerTick = runsPerTick; + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + int runs = (int) runsPerTick; + if (Create.random.nextFloat() < (runsPerTick - runs)) + runs++; + for (int i = 0; i < runs; i++) + emitter.create(scene.getWorld(), anchor.x, anchor.y, anchor.z); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/FadeInOutInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/FadeInOutInstruction.java new file mode 100644 index 000000000..a7f195ffe --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/FadeInOutInstruction.java @@ -0,0 +1,49 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderScene; + +public abstract class FadeInOutInstruction extends TickingInstruction { + + protected static final int fadeTime = 5; + + public FadeInOutInstruction(int duration) { + super(false, duration + 2 * fadeTime); + } + + protected abstract void show(PonderScene scene); + + protected abstract void hide(PonderScene scene); + + protected abstract void applyFade(PonderScene scene, float fade); + + @Override + protected void firstTick(PonderScene scene) { + super.firstTick(scene); + show(scene); + applyFade(scene, 0); + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + int elapsed = totalTicks - remainingTicks; + + if (elapsed < fadeTime) { + float fade = (elapsed / (float) fadeTime); + applyFade(scene, fade * fade); + + } else if (remainingTicks < fadeTime) { + float fade = (remainingTicks / (float) fadeTime); + applyFade(scene, fade * fade); + + } else + applyFade(scene, 1); + + if (remainingTicks == 0) { + applyFade(scene, 0); + hide(scene); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/FadeIntoSceneInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/FadeIntoSceneInstruction.java new file mode 100644 index 000000000..10a1bbaa9 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/FadeIntoSceneInstruction.java @@ -0,0 +1,53 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.elements.AnimatedSceneElement; + +import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.Vector3d; + +public abstract class FadeIntoSceneInstruction extends TickingInstruction { + + protected Direction fadeInFrom; + protected T element; + private ElementLink elementLink; + + public FadeIntoSceneInstruction(int fadeInTicks, Direction fadeInFrom, T element) { + super(false, fadeInTicks); + this.fadeInFrom = fadeInFrom; + this.element = element; + } + + @Override + protected void firstTick(PonderScene scene) { + super.firstTick(scene); + scene.addElement(element); + element.setVisible(true); + element.setFade(0); + element.setFadeVec(Vector3d.of(fadeInFrom.getDirectionVec()).scale(.5f)); + if (elementLink != null) + scene.linkElement(element, elementLink); + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + float fade = totalTicks == 0 ? 1 : (remainingTicks / (float) totalTicks); + element.setFade(1 - fade * fade); + if (remainingTicks == 0) { + if (totalTicks == 0) + element.setFade(1); + element.setFade(1); + } + } + + public ElementLink createLink(PonderScene scene) { + elementLink = new ElementLink<>(getElementClass()); + scene.linkElement(element, elementLink); + return elementLink; + } + + protected abstract Class getElementClass(); + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/FadeOutOfSceneInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/FadeOutOfSceneInstruction.java new file mode 100644 index 000000000..269ca682a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/FadeOutOfSceneInstruction.java @@ -0,0 +1,46 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.ElementLink; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.elements.AnimatedSceneElement; + +import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.Vector3d; + +public class FadeOutOfSceneInstruction extends TickingInstruction { + + private Direction fadeOutTo; + private ElementLink link; + private T element; + + public FadeOutOfSceneInstruction(int fadeOutTicks, Direction fadeOutTo, ElementLink link) { + super(false, fadeOutTicks); + this.fadeOutTo = fadeOutTo.getOpposite(); + this.link = link; + } + + @Override + protected void firstTick(PonderScene scene) { + super.firstTick(scene); + element = scene.resolve(link); + if (element == null) + return; + element.setVisible(true); + element.setFade(1); + element.setFadeVec(Vector3d.of(fadeOutTo.getDirectionVec()).scale(.5f)); + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + if (element == null) + return; + float fade = (remainingTicks / (float) totalTicks); + element.setFade(1 - (1 - fade) * (1 - fade)); + if (remainingTicks == 0) { + element.setVisible(false); + element.setFade(0); + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/HideAllInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/HideAllInstruction.java new file mode 100644 index 000000000..227893e68 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/HideAllInstruction.java @@ -0,0 +1,55 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.elements.AnimatedOverlayElement; +import com.simibubi.create.foundation.ponder.elements.AnimatedSceneElement; + +import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.Vector3d; + +public class HideAllInstruction extends TickingInstruction { + + private Direction fadeOutTo; + + public HideAllInstruction(int fadeOutTicks, Direction fadeOutTo) { + super(false, fadeOutTicks); + this.fadeOutTo = fadeOutTo; + } + + @Override + protected void firstTick(PonderScene scene) { + super.firstTick(scene); + scene.getElements() + .forEach(element -> { + if (element instanceof AnimatedSceneElement) { + AnimatedSceneElement animatedSceneElement = (AnimatedSceneElement) element; + animatedSceneElement.setFade(1); + animatedSceneElement + .setFadeVec(fadeOutTo == null ? null : Vector3d.of(fadeOutTo.getDirectionVec()).scale(.5f)); + } else if (element instanceof AnimatedOverlayElement) { + AnimatedOverlayElement animatedSceneElement = (AnimatedOverlayElement) element; + animatedSceneElement.setFade(1); + } else + element.setVisible(false); + }); + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + float fade = (remainingTicks / (float) totalTicks); + + scene.forEach(AnimatedSceneElement.class, ase -> { + ase.setFade(fade * fade); + if (remainingTicks == 0) + ase.setFade(0); + }); + + scene.forEach(AnimatedOverlayElement.class, aoe -> { + aoe.setFade(fade * fade); + if (remainingTicks == 0) + aoe.setFade(0); + }); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/HighlightValueBoxInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/HighlightValueBoxInstruction.java new file mode 100644 index 000000000..b00f89dd2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/HighlightValueBoxInstruction.java @@ -0,0 +1,31 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.content.PonderPalette; + +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.vector.Vector3d; + +public class HighlightValueBoxInstruction extends TickingInstruction { + + private Vector3d vec; + private Vector3d expands; + + public HighlightValueBoxInstruction(Vector3d vec, Vector3d expands, int duration) { + super(false, duration); + this.vec = vec; + this.expands = expands; + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + AxisAlignedBB point = new AxisAlignedBB(vec, vec); + AxisAlignedBB expanded = point.grow(expands.x, expands.y, expands.z); + scene.getOutliner() + .chaseAABB(vec, remainingTicks == totalTicks ? point : expanded) + .lineWidth(1 / 32f) + .colored(PonderPalette.WHITE.getColor()); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/KeyframeInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/KeyframeInstruction.java new file mode 100644 index 000000000..8bc6ea00a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/KeyframeInstruction.java @@ -0,0 +1,29 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderInstruction; +import com.simibubi.create.foundation.ponder.PonderScene; + +public class KeyframeInstruction extends PonderInstruction { + + public static final KeyframeInstruction IMMEDIATE = new KeyframeInstruction(false); + public static final KeyframeInstruction DELAYED = new KeyframeInstruction(true); + + private boolean delayed; + + private KeyframeInstruction(boolean delayed) { + this.delayed = delayed; + } + + @Override + public boolean isComplete() { + return true; + } + + @Override + public void tick(PonderScene scene) { } + + @Override + public void onScheduled(PonderScene scene) { + scene.markKeyframe(delayed ? 6 : 0); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/LineInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/LineInstruction.java new file mode 100644 index 000000000..63bd171d2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/LineInstruction.java @@ -0,0 +1,30 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.content.PonderPalette; + +import net.minecraft.util.math.vector.Vector3d; + +public class LineInstruction extends TickingInstruction { + + private PonderPalette color; + private Vector3d start; + private Vector3d end; + + public LineInstruction(PonderPalette color, Vector3d start, Vector3d end, int ticks) { + super(false, ticks); + this.color = color; + this.start = start; + this.end = end; + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + scene.getOutliner() + .showLine(start, start, end) + .lineWidth(1 / 16f) + .colored(color.getColor()); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/MarkAsFinishedInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/MarkAsFinishedInstruction.java new file mode 100644 index 000000000..ef15e46dd --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/MarkAsFinishedInstruction.java @@ -0,0 +1,23 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderInstruction; +import com.simibubi.create.foundation.ponder.PonderScene; + +public class MarkAsFinishedInstruction extends PonderInstruction { + + @Override + public boolean isComplete() { + return true; + } + + @Override + public void tick(PonderScene scene) { + scene.setFinished(true); + } + + @Override + public void onScheduled(PonderScene scene) { + scene.stopCounting(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/MovePoiInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/MovePoiInstruction.java new file mode 100644 index 000000000..a914595de --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/MovePoiInstruction.java @@ -0,0 +1,26 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderInstruction; +import com.simibubi.create.foundation.ponder.PonderScene; + +import net.minecraft.util.math.vector.Vector3d; + +public class MovePoiInstruction extends PonderInstruction { + + private Vector3d poi; + + public MovePoiInstruction(Vector3d poi) { + this.poi = poi; + } + + @Override + public boolean isComplete() { + return true; + } + + @Override + public void tick(PonderScene scene) { + scene.setPointOfInterest(poi); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/OutlineSelectionInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/OutlineSelectionInstruction.java new file mode 100644 index 000000000..23207f9fc --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/OutlineSelectionInstruction.java @@ -0,0 +1,28 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.content.PonderPalette; + +public class OutlineSelectionInstruction extends TickingInstruction { + + private PonderPalette color; + private Object slot; + private Selection selection; + + public OutlineSelectionInstruction(PonderPalette color, Object slot, Selection selection, int ticks) { + super(false, ticks); + this.color = color; + this.slot = slot; + this.selection = selection; + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + selection.makeOutline(scene.getOutliner(), slot) + .lineWidth(1 / 16f) + .colored(color.getColor()); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/ReplaceBlocksInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/ReplaceBlocksInstruction.java new file mode 100644 index 000000000..d71ad0919 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/ReplaceBlocksInstruction.java @@ -0,0 +1,47 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import java.util.function.UnaryOperator; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderWorld; +import com.simibubi.create.foundation.ponder.Selection; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; + +public class ReplaceBlocksInstruction extends WorldModifyInstruction { + + private UnaryOperator stateToUse; + private boolean replaceAir; + private boolean spawnParticles; + + public ReplaceBlocksInstruction(Selection selection, UnaryOperator stateToUse, boolean replaceAir, + boolean spawnParticles) { + super(selection); + this.stateToUse = stateToUse; + this.replaceAir = replaceAir; + this.spawnParticles = spawnParticles; + } + + @Override + protected void runModification(Selection selection, PonderScene scene) { + PonderWorld world = scene.getWorld(); + selection.forEach(pos -> { + if (!world.getBounds() + .isVecInside(pos)) + return; + BlockState prevState = world.getBlockState(pos); + if (!replaceAir && prevState == Blocks.AIR.getDefaultState()) + return; + if (spawnParticles) + world.addBlockDestroyEffects(pos, prevState); + world.setBlockState(pos, stateToUse.apply(prevState)); + }); + } + + @Override + protected boolean needsRedraw() { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/RotateSceneInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/RotateSceneInstruction.java new file mode 100644 index 000000000..9edec76fc --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/RotateSceneInstruction.java @@ -0,0 +1,34 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderInstruction; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderScene.SceneTransform; +import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; + +public class RotateSceneInstruction extends PonderInstruction { + + private float xRot; + private float yRot; + private boolean relative; + + public RotateSceneInstruction(float xRot, float yRot, boolean relative) { + this.xRot = xRot; + this.yRot = yRot; + this.relative = relative; + } + + @Override + public boolean isComplete() { + return true; + } + + @Override + public void tick(PonderScene scene) { + SceneTransform transform = scene.getTransform(); + float targetX = relative ? transform.xRotation.getChaseTarget() + xRot : xRot; + float targetY = relative ? transform.yRotation.getChaseTarget() + yRot : yRot; + transform.xRotation.chase(targetX, .1f, Chaser.EXP); + transform.yRotation.chase(targetY, .1f, Chaser.EXP); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/ShowInputInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/ShowInputInstruction.java new file mode 100644 index 000000000..4a1864478 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/ShowInputInstruction.java @@ -0,0 +1,31 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; + +public class ShowInputInstruction extends FadeInOutInstruction { + + private InputWindowElement element; + + public ShowInputInstruction(InputWindowElement element, int ticks) { + super(ticks); + this.element = element; + } + + @Override + protected void show(PonderScene scene) { + scene.addElement(element); + element.setVisible(true); + } + + @Override + protected void hide(PonderScene scene) { + element.setVisible(false); + } + + @Override + protected void applyFade(PonderScene scene, float fade) { + element.setFade(fade); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/TextInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/TextInstruction.java new file mode 100644 index 000000000..d0380cc81 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/TextInstruction.java @@ -0,0 +1,56 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.OutlinerElement; +import com.simibubi.create.foundation.ponder.elements.TextWindowElement; + +public class TextInstruction extends FadeInOutInstruction { + + private TextWindowElement element; + private OutlinerElement outline; + + public TextInstruction(TextWindowElement element, int duration) { + super(duration); + this.element = element; + } + + public TextInstruction(TextWindowElement element, int duration, Selection selection) { + this(element, duration); + outline = new OutlinerElement(o -> selection.makeOutline(o) + .lineWidth(1 / 16f)); + } + + @Override + public void tick(PonderScene scene) { + super.tick(scene); + if (outline != null) + outline.setColor(element.getColor()); + } + + @Override + protected void show(PonderScene scene) { + scene.addElement(element); + element.setVisible(true); + if (outline != null) { + scene.addElement(outline); + outline.setFade(1); + outline.setVisible(true); + } + } + + @Override + protected void hide(PonderScene scene) { + element.setVisible(false); + if (outline != null) { + outline.setFade(0); + outline.setVisible(false); + } + } + + @Override + protected void applyFade(PonderScene scene, float fade) { + element.setFade(fade); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/TickingInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/TickingInstruction.java new file mode 100644 index 000000000..93f2b5a03 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/TickingInstruction.java @@ -0,0 +1,50 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderInstruction; +import com.simibubi.create.foundation.ponder.PonderScene; + +public abstract class TickingInstruction extends PonderInstruction { + + private boolean blocking; + protected int totalTicks; + protected int remainingTicks; + + public TickingInstruction(boolean blocking, int ticks) { + this.blocking = blocking; + remainingTicks = totalTicks = ticks; + } + + @Override + public void reset(PonderScene scene) { + super.reset(scene); + remainingTicks = totalTicks; + } + + protected void firstTick(PonderScene scene) {} + + @Override + public void onScheduled(PonderScene scene) { + super.onScheduled(scene); + if (isBlocking()) + scene.addToSceneTime(totalTicks); + } + + @Override + public void tick(PonderScene scene) { + if (remainingTicks == totalTicks) + firstTick(scene); + if (remainingTicks > 0) + remainingTicks--; + } + + @Override + public boolean isComplete() { + return remainingTicks == 0; + } + + @Override + public boolean isBlocking() { + return blocking; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/TileEntityDataInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/TileEntityDataInstruction.java new file mode 100644 index 000000000..c02751d5d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/TileEntityDataInstruction.java @@ -0,0 +1,51 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import java.util.function.UnaryOperator; + +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.PonderWorld; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.tileEntity.SyncedTileEntity; + +import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntity; + +public class TileEntityDataInstruction extends WorldModifyInstruction { + + private boolean redraw; + private UnaryOperator data; + private Class type; + + public TileEntityDataInstruction(Selection selection, Class type, + UnaryOperator data, boolean redraw) { + super(selection); + this.type = type; + this.data = data; + this.redraw = redraw; + } + + @Override + protected void runModification(Selection selection, PonderScene scene) { + PonderWorld world = scene.getWorld(); + selection.forEach(pos -> { + if (!world.getBounds() + .isVecInside(pos)) + return; + TileEntity tileEntity = world.getTileEntity(pos); + if (!type.isInstance(tileEntity)) + return; + CompoundNBT apply = data.apply(tileEntity.write(new CompoundNBT())); + BlockState state = world.getBlockState(pos); + tileEntity.fromTag(state, apply); + if (tileEntity instanceof SyncedTileEntity) + ((SyncedTileEntity) tileEntity).readClientUpdate(state, apply); + }); + } + + @Override + protected boolean needsRedraw() { + return redraw; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instructions/WorldModifyInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instructions/WorldModifyInstruction.java new file mode 100644 index 000000000..583514b67 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/instructions/WorldModifyInstruction.java @@ -0,0 +1,32 @@ +package com.simibubi.create.foundation.ponder.instructions; + +import com.simibubi.create.foundation.ponder.PonderInstruction; +import com.simibubi.create.foundation.ponder.PonderScene; +import com.simibubi.create.foundation.ponder.Selection; +import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; + +public abstract class WorldModifyInstruction extends PonderInstruction { + + private Selection selection; + + public WorldModifyInstruction(Selection selection) { + this.selection = selection; + } + + @Override + public boolean isComplete() { + return true; + } + + @Override + public void tick(PonderScene scene) { + runModification(selection, scene); + if (needsRedraw()) + scene.forEach(WorldSectionElement.class, WorldSectionElement::queueRedraw); + } + + protected abstract void runModification(Selection selection, PonderScene scene); + + protected abstract boolean needsRedraw(); + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/ui/ChapterLabel.java b/src/main/java/com/simibubi/create/foundation/ponder/ui/ChapterLabel.java new file mode 100644 index 000000000..f8c5bad15 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/ui/ChapterLabel.java @@ -0,0 +1,47 @@ +package com.simibubi.create.foundation.ponder.ui; + +import java.util.function.BiConsumer; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget; +import com.simibubi.create.foundation.ponder.content.PonderChapter; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.client.Minecraft; + +import javax.annotation.Nonnull; + +public class ChapterLabel extends AbstractSimiWidget { + + private final PonderChapter chapter; + private final PonderButton button; + + public ChapterLabel(PonderChapter chapter, int x, int y, BiConsumer onClick) { + super(x, y, 175, 38); + + this.button = new PonderButton(x + 4, y + 4, onClick, 30, 30).showing(chapter); + this.button.fade(1); + + this.chapter = chapter; + } + + @Override + public void render(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + UIRenderHelper.streak(ms, 0, x, y + height / 2, height - 2, width, 0x101010); + Minecraft.getInstance().fontRenderer.draw(ms, Lang.translate("ponder.chapter." + chapter.getId()), x + 50, + y + 20, 0xffddeeff); + + button.renderButton(ms, mouseX, mouseY, partialTicks); + super.render(ms, mouseX, mouseY, partialTicks); + } + + @Override + public void onClick(double x, double y) { + if (!button.isMouseOver(x, y)) + return; + + button.runCallback(x, y); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/ui/LayoutHelper.java b/src/main/java/com/simibubi/create/foundation/ponder/ui/LayoutHelper.java new file mode 100644 index 000000000..32ca1df1d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/ui/LayoutHelper.java @@ -0,0 +1,118 @@ +package com.simibubi.create.foundation.ponder.ui; + +import net.minecraft.client.renderer.Rectangle2d; + +public interface LayoutHelper { + + static LayoutHelper centeredHorizontal(int itemCount, int rows, int width, int height, int spacing) { + return new CenteredHorizontalLayoutHelper(itemCount, rows, width, height, spacing); + } + + int getX(); + + int getY(); + + void next(); + + int getTotalWidth(); + + int getTotalHeight(); + + default Rectangle2d getArea() { + int lWidth = getTotalWidth(); + int lHeight = getTotalHeight(); + return new Rectangle2d(-lWidth / 2, -lHeight / 2, lWidth, lHeight); + } + + class CenteredHorizontalLayoutHelper implements LayoutHelper { + + int itemCount; + int rows; + int width; + int height; + int spacing; + + int currentColumn = 0; + int currentRow = 0; + int[] rowCounts; + int x = 0, y = 0; + + CenteredHorizontalLayoutHelper(int itemCount, int rows, int width, int height, int spacing) { + this.itemCount = itemCount; + this.rows = rows; + this.width = width; + this.height = height; + this.spacing = spacing; + + rowCounts = new int[rows]; + int itemsPerRow = itemCount / rows; + int itemDiff = itemCount - itemsPerRow * rows; + for (int i = 0; i < rows; i++) { + rowCounts[i] = itemsPerRow; + if (itemDiff > 0) { + rowCounts[i]++; + itemDiff--; + } + } + + init(); + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return y; + } + + @Override + public void next() { + currentColumn++; + if (currentColumn >= rowCounts[currentRow]) { + // nextRow + if (++currentRow >= rows) { + x = 0; + y = 0; + return; + } + + currentColumn = 0; + prepareX(); + y += height + spacing; + return; + } + + x += width + spacing; + } + + private void init() { + prepareX(); + prepareY(); + } + + private void prepareX() { + int rowWidth = rowCounts[currentRow] * width + (rowCounts[currentRow] - 1) * spacing; + x = -(rowWidth / 2); + } + + private void prepareY() { + int totalHeight = rows * height + (rows > 1 ? ((rows - 1) * spacing) : 0); + y = -(totalHeight / 2); + } + + @Override + public int getTotalWidth() { + return rowCounts[0] * width + (rowCounts[0] - 1) * spacing; + } + + @Override + public int getTotalHeight() { + return rows * height + (rows > 1 ? ((rows - 1) * spacing) : 0); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/ui/PonderButton.java b/src/main/java/com/simibubi/create/foundation/ponder/ui/PonderButton.java new file mode 100644 index 000000000..fed1e3035 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/ui/PonderButton.java @@ -0,0 +1,173 @@ +package com.simibubi.create.foundation.ponder.ui; + +import java.util.function.BiConsumer; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.gui.GuiGameElement; +import com.simibubi.create.foundation.gui.IScreenRenderable; +import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget; +import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.item.ItemStack; + +public class PonderButton extends AbstractSimiWidget { + + private IScreenRenderable icon; + private ItemStack item; + protected boolean pressed; + private BiConsumer onClick; + private int xFadeModifier; + private int yFadeModifier; + private float fade; + private KeyBinding shortcut; + private LerpedFloat flash; + private boolean noClickEvent; + + public static final int SIZE = 20; + + public PonderButton(int x, int y, BiConsumer onClick, int width, int height) { + super(x, y, width, height); + this.onClick = onClick; + flash = LerpedFloat.linear() + .startWithValue(0); + } + + public PonderButton(int x, int y, BiConsumer onClick) { + this(x, y, onClick, SIZE, SIZE); + } + + public PonderButton(int x, int y, Runnable onClick) { + this(x, y, ($, $$) -> onClick.run()); + } + + public PonderButton showing(IScreenRenderable icon) { + this.icon = icon; + return this; + } + + public PonderButton showing(ItemStack item) { + this.item = item; + return this; + } + + public PonderButton noClickEvent() { + this.noClickEvent = true; + return this; + } + + public PonderButton shortcut(KeyBinding key) { + this.shortcut = key; + return this; + } + + public PonderButton fade(int xModifier, int yModifier) { + this.xFadeModifier = xModifier; + this.yFadeModifier = yModifier; + return this; + } + + public void fade(float fade) { + this.fade = fade; + } + + public void flash() { + float value = flash.getValue(); + flash.setValue(value + (1 - value) * .2f); + } + + public void dim() { + float value = flash.getValue(); + flash.setValue(value * .5f); + } + + @Override + public void renderButton(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + if (!visible) + return; + if (fade < .1f) + return; + + hovered = isMouseOver(mouseX, mouseY) && fade > .75f; + + RenderSystem.pushMatrix(); + RenderSystem.disableDepthTest(); + if (fade < 1) + RenderSystem.translated((1 - fade) * -5 * xFadeModifier, (1 - fade) * -5 * yFadeModifier, 0); + + float flashValue = flash.getValue(partialTicks); + if (flashValue > .1f) + fade *= 3 * flashValue + Math.sin((PonderUI.ponderTicks + partialTicks) / 6); + + int backgroundColor = ColorHelper.applyAlpha(0xdd000000, fade); + int borderColorStart = + ColorHelper.applyAlpha(noClickEvent ? 0x70984500 : hovered ? 0x70ffffff : 0x40aa9999, fade); + int borderColorEnd = + ColorHelper.applyAlpha(noClickEvent ? 0x70692400 : hovered ? 0x30ffffff : 0x20aa9999, fade); + + PonderUI.renderBox(ms, x, y, width, height, backgroundColor, borderColorStart, borderColorEnd); + RenderSystem.translated(0, 0, 800); + + if (icon != null) { + RenderSystem.enableBlend(); + RenderSystem.color4f(1, 1, 1, fade); + RenderSystem.pushMatrix(); + RenderSystem.translated(x + 2, y + 2, 0); + RenderSystem.scaled((width - 4) / 16d, (height - 4) / 16d, 1); + icon.draw(ms, this, 0, 0); + RenderSystem.popMatrix(); + } + if (item != null) { + RenderSystem.pushMatrix(); + RenderSystem.translated(0, 0, -800); + GuiGameElement.of(item) + .at(x - 2, y - 2) + .scale(1.5f) + .render(ms); + RenderSystem.popMatrix(); + } + if (shortcut != null) + drawCenteredText(ms, Minecraft.getInstance().fontRenderer, shortcut.getBoundKeyLocalizedText(), x + width / 2 + 8, + y + height - 6, ColorHelper.applyAlpha(0xff606060, fade)); + + RenderSystem.popMatrix(); + } + + public void runCallback(double mouseX, double mouseY) { + onClick.accept((int) mouseX, (int) mouseY); + } + + @Override + public void onClick(double p_onClick_1_, double p_onClick_3_) { + super.onClick(p_onClick_1_, p_onClick_3_); + this.pressed = true; + } + + @Override + public void onRelease(double p_onRelease_1_, double p_onRelease_3_) { + super.onRelease(p_onRelease_1_, p_onRelease_3_); + this.pressed = false; + } + + /*public void setToolTip(String text) { + toolTip.clear(); + toolTip.add(text); + }*/ + + public ItemStack getItem() { + return item; + } + + @Override + public boolean isMouseOver(double x, double y) { + double m = 4; + x = Math.floor(x); + y = Math.floor(y); + return active && visible + && !(x < this.x - m || x > this.x + width + m - 1 || y < this.y - m || y > this.y + height + m - 1); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java b/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java index b5d5e991a..485eb3889 100644 --- a/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java +++ b/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java @@ -9,7 +9,9 @@ import com.simibubi.create.content.contraptions.components.actors.ActorVertexAtt import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionProgram; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionVertexAttributes; import com.simibubi.create.content.contraptions.relays.belt.BeltVertexAttributes; +import com.simibubi.create.content.logistics.block.FlapVertexAttributes; import com.simibubi.create.foundation.render.backend.gl.BasicProgram; +import com.simibubi.create.foundation.render.backend.gl.attrib.InstanceVertexAttributes; import com.simibubi.create.foundation.render.backend.gl.attrib.ModelVertexAttributes; import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec; import com.simibubi.create.foundation.render.backend.gl.shader.ShaderConstants; @@ -17,12 +19,23 @@ import com.simibubi.create.foundation.render.backend.gl.shader.ShaderConstants; import net.minecraft.util.ResourceLocation; public class AllProgramSpecs { + public static void init() { + // noop, make sure the static field are loaded. + } + + public static final ProgramSpec MODEL = register(ProgramSpec.builder("model", BasicProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(InstanceVertexAttributes.class) + .setVert(Locations.MODEL_VERT) + .setFrag(Locations.MODEL_FRAG) + .createProgramSpec()); + public static final ProgramSpec ROTATING = register(ProgramSpec.builder("rotating", BasicProgram::new) .addAttributes(ModelVertexAttributes.class) .addAttributes(KineticVertexAttributes.class) .addAttributes(RotatingVertexAttributes.class) .setVert(Locations.ROTATING) - .setFrag(Locations.INSTANCED) + .setFrag(Locations.MODEL_FRAG) .createProgramSpec()); public static final ProgramSpec BELT = register(ProgramSpec.builder("belt", BasicProgram::new) @@ -30,52 +43,72 @@ public class AllProgramSpecs { .addAttributes(KineticVertexAttributes.class) .addAttributes(BeltVertexAttributes.class) .setVert(Locations.BELT) - .setFrag(Locations.INSTANCED) + .setFrag(Locations.MODEL_FRAG) .createProgramSpec()); - public static final ProgramSpec CONTRAPTION_STRUCTURE = register(ProgramSpec.builder("contraption_structure", ContraptionProgram::new) - .addAttributes(ContraptionVertexAttributes.class) - .setVert(Locations.CONTRAPTION_STRUCTURE) - .setFrag(Locations.CONTRAPTION) - .createProgramSpec()); + public static final ProgramSpec FLAPS = register(ProgramSpec.builder("flap", BasicProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(FlapVertexAttributes.class) + .setVert(Locations.FLAP) + .setFrag(Locations.MODEL_FRAG) + .createProgramSpec()); + public static final ProgramSpec C_STRUCTURE = register(ProgramSpec.builder("contraption_structure", ContraptionProgram::new) + .addAttributes(ContraptionVertexAttributes.class) + .setVert(Locations.CONTRAPTION_STRUCTURE) + .setFrag(Locations.CONTRAPTION) + .createProgramSpec()); + public static final ProgramSpec C_MODEL = register(ProgramSpec.builder("contraption_model", ContraptionProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(InstanceVertexAttributes.class) + .setVert(Locations.MODEL_VERT) + .setFrag(Locations.CONTRAPTION) + .setDefines(ShaderConstants.define("CONTRAPTION")) + .createProgramSpec()); + public static final ProgramSpec C_ROTATING = register(ProgramSpec.builder("contraption_rotating", ContraptionProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(KineticVertexAttributes.class) + .addAttributes(RotatingVertexAttributes.class) + .setVert(Locations.ROTATING) + .setFrag(Locations.CONTRAPTION) + .setDefines(ShaderConstants.define("CONTRAPTION")) + .createProgramSpec()); + public static final ProgramSpec C_BELT = register(ProgramSpec.builder("contraption_belt", ContraptionProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(KineticVertexAttributes.class) + .addAttributes(BeltVertexAttributes.class) + .setVert(Locations.BELT) + .setFrag(Locations.CONTRAPTION) + .setDefines(ShaderConstants.define("CONTRAPTION")) + .createProgramSpec()); + public static final ProgramSpec C_FLAPS = register(ProgramSpec.builder("contraption_flap", ContraptionProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(FlapVertexAttributes.class) + .setVert(Locations.FLAP) + .setFrag(Locations.CONTRAPTION) + .setDefines(ShaderConstants.define("CONTRAPTION")) + .createProgramSpec()); + public static final ProgramSpec C_ACTOR = register(ProgramSpec.builder("contraption_actor", ContraptionProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(ActorVertexAttributes.class) + .setVert(Locations.CONTRAPTION_ACTOR) + .setFrag(Locations.CONTRAPTION) + .createProgramSpec()); - public static final ProgramSpec CONTRAPTION_ROTATING = register(ProgramSpec.builder("contraption_rotating", ContraptionProgram::new) - .addAttributes(ModelVertexAttributes.class) - .addAttributes(KineticVertexAttributes.class) - .addAttributes(RotatingVertexAttributes.class) - .setVert(Locations.ROTATING) - .setFrag(Locations.CONTRAPTION) - .setDefines(ShaderConstants.define("CONTRAPTION")) - .createProgramSpec()); - - public static final ProgramSpec CONTRAPTION_BELT = register(ProgramSpec.builder("contraption_belt", ContraptionProgram::new) - .addAttributes(ModelVertexAttributes.class) - .addAttributes(KineticVertexAttributes.class) - .addAttributes(BeltVertexAttributes.class) - .setVert(Locations.BELT) - .setFrag(Locations.CONTRAPTION) - .setDefines(ShaderConstants.define("CONTRAPTION")) - .createProgramSpec()); - - public static final ProgramSpec CONTRAPTION_ACTOR = register(ProgramSpec.builder("contraption_actor", ContraptionProgram::new) - .addAttributes(ModelVertexAttributes.class) - .addAttributes(ActorVertexAttributes.class) - .setVert(Locations.CONTRAPTION_ACTOR) - .setFrag(Locations.CONTRAPTION) - .createProgramSpec()); public static class Locations { - public static final ResourceLocation INSTANCED = loc("instanced.frag"); + public static final ResourceLocation MODEL_FRAG = loc("model.frag"); + public static final ResourceLocation MODEL_VERT = loc("model.vert"); public static final ResourceLocation CONTRAPTION = loc("contraption.frag"); public static final ResourceLocation ROTATING = loc("rotating.vert"); public static final ResourceLocation BELT = loc("belt.vert"); + public static final ResourceLocation FLAP = loc("flap.vert"); public static final ResourceLocation CONTRAPTION_STRUCTURE = loc("contraption_structure.vert"); public static final ResourceLocation CONTRAPTION_ACTOR = loc("contraption_actor.vert"); private static ResourceLocation loc(String name) { - return new ResourceLocation(Create.ID, "shader/" + name); + return new ResourceLocation(Create.ID, name); } } } diff --git a/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java index 3572f1c7e..e092ffba5 100644 --- a/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java @@ -5,16 +5,18 @@ import java.util.ArrayList; import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; import com.simibubi.create.content.contraptions.base.RotatingInstancedModel; import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel; +import com.simibubi.create.content.logistics.block.FlapInstancedModel; +import com.simibubi.create.foundation.render.backend.RenderMaterials; import com.simibubi.create.foundation.render.backend.gl.BasicProgram; import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; -import net.minecraft.client.Minecraft; +import com.simibubi.create.foundation.render.backend.instancing.impl.BasicInstancedModel; import net.minecraft.client.renderer.RenderType; -import net.minecraft.entity.Entity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Matrix4f; public class KineticRenderer extends InstancedTileRenderer { @@ -24,8 +26,11 @@ public class KineticRenderer extends InstancedTileRenderer { @Override public void registerMaterials() { + materials.put(RenderMaterials.MODELS, new RenderMaterial<>(this, AllProgramSpecs.MODEL, BasicInstancedModel::new)); + materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(this, AllProgramSpecs.BELT, BeltInstancedModel::new)); materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.ROTATING, RotatingInstancedModel::new)); + materials.put(KineticRenderMaterials.FLAPS, new RenderMaterial<>(this, AllProgramSpecs.FLAPS, FlapInstancedModel::new)); } @Override @@ -34,30 +39,27 @@ public class KineticRenderer extends InstancedTileRenderer { } @Override - public void tick() { - super.tick(); + public void beginFrame(double cameraX, double cameraY, double cameraZ) { + int cX = MathHelper.floor(cameraX); + int cY = MathHelper.floor(cameraY); + int cZ = MathHelper.floor(cameraZ); - Minecraft mc = Minecraft.getInstance(); - Entity renderViewEntity = mc.renderViewEntity; - - if (renderViewEntity == null) return; - - BlockPos renderViewPosition = renderViewEntity.getBlockPos(); - - int dX = Math.abs(renderViewPosition.getX() - originCoordinate.getX()); - int dY = Math.abs(renderViewPosition.getY() - originCoordinate.getY()); - int dZ = Math.abs(renderViewPosition.getZ() - originCoordinate.getZ()); + int dX = Math.abs(cX - originCoordinate.getX()); + int dY = Math.abs(cY - originCoordinate.getY()); + int dZ = Math.abs(cZ - originCoordinate.getZ()); if (dX > MAX_ORIGIN_DISTANCE || dY > MAX_ORIGIN_DISTANCE || dZ > MAX_ORIGIN_DISTANCE) { - originCoordinate = renderViewPosition; + originCoordinate = new BlockPos(cX, cY, cZ); ArrayList instancedTiles = new ArrayList<>(instances.keySet()); invalidate(); instancedTiles.forEach(this::add); } + + super.beginFrame(cameraX, cameraY, cameraZ); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/render/RenderMath.java b/src/main/java/com/simibubi/create/foundation/render/RenderMath.java deleted file mode 100644 index 3839ff718..000000000 --- a/src/main/java/com/simibubi/create/foundation/render/RenderMath.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.simibubi.create.foundation.render; - -public class RenderMath { - public static int nextPowerOf2(int a) { - int h = Integer.highestOneBit(a); - return (h == a) ? h : (h << 1); - } - - public static boolean isPowerOf2(int n) { - int b = n & (n - 1); - return b == 0 && n != 0; - } -} diff --git a/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java b/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java index 4e742e7bf..d15aa0bcd 100644 --- a/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java @@ -8,6 +8,7 @@ import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.block.render.SpriteShiftEntry; +import com.simibubi.create.foundation.utility.MatrixStacker; import it.unimi.dsi.fastutil.longs.Long2DoubleMap; import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap; import net.minecraft.client.Minecraft; @@ -15,10 +16,7 @@ import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.vector.Matrix3f; -import net.minecraft.util.math.vector.Matrix4f; -import net.minecraft.util.math.vector.Vector3f; -import net.minecraft.util.math.vector.Vector4f; +import net.minecraft.util.math.vector.*; import net.minecraft.world.LightType; import net.minecraft.world.World; import net.minecraftforge.client.model.pipeline.LightUtil; @@ -107,13 +105,16 @@ public class SuperByteBuffer extends TemplateBuffer { float staticDiffuse = LightUtil.diffuseLight(normalX, normalY, normalZ); normal.set(normalX, normalY, normalZ); normal.transform(normalMat); - float instanceDiffuse = LightUtil.diffuseLight(normal.getX(), normal.getY(), normal.getZ()); + float nx = normal.getX(); + float ny = normal.getY(); + float nz = normal.getZ(); + float instanceDiffuse = LightUtil.diffuseLight(nx, ny, nz); pos.set(x, y, z, 1F); pos.transform(modelMat); builder.vertex(pos.getX(), pos.getY(), pos.getZ()); - //builder.color((byte) Math.max(0, normal.getX() * 255), (byte) Math.max(0, normal.getY() * 255), (byte) Math.max(0, normal.getZ() * 255), a); + //builder.color((byte) Math.max(0, nx * 255), (byte) Math.max(0, ny * 255), (byte) Math.max(0, nz * 255), a); if (shouldColor) { //float lum = (r < 0 ? 255 + r : r) / 256f; int colorR = Math.min(255, (int) (((float) this.r) * instanceDiffuse)); @@ -152,7 +153,7 @@ public class SuperByteBuffer extends TemplateBuffer { } else builder.light(getLight(buffer, i)); - builder.normal(normal.getX(), normal.getY(), normal.getZ()) + builder.normal(nx, ny, nz) .endVertex(); } @@ -164,6 +165,14 @@ public class SuperByteBuffer extends TemplateBuffer { otherBlockLight = -1; } + public MatrixStacker matrixStacker() { + return MatrixStacker.of(transforms); + } + + public SuperByteBuffer translate(Vector3d vec) { + return translate(vec.x, vec.y, vec.z); + } + public SuperByteBuffer translate(double x, double y, double z) { return translate((float) x, (float) y, (float) z); } @@ -173,6 +182,12 @@ public class SuperByteBuffer extends TemplateBuffer { return this; } + public SuperByteBuffer transform(MatrixStack stack) { + transforms.peek().getModel().multiply(stack.peek().getModel()); + transforms.peek().getNormal().multiply(stack.peek().getNormal()); + return this; + } + public SuperByteBuffer rotate(Direction axis, float radians) { if (radians == 0) return this; diff --git a/src/main/java/com/simibubi/create/foundation/render/SuperByteBufferCache.java b/src/main/java/com/simibubi/create/foundation/render/SuperByteBufferCache.java index ef25a5e2d..0ebf74157 100644 --- a/src/main/java/com/simibubi/create/foundation/render/SuperByteBufferCache.java +++ b/src/main/java/com/simibubi/create/foundation/render/SuperByteBufferCache.java @@ -78,6 +78,11 @@ public class SuperByteBufferCache { return null; } } + + public void invalidate(Compartment compartment, T key) { + Cache compartmentCache = this.cache.get(compartment); + compartmentCache.invalidate(key); + } public void registerCompartment(Compartment instance) { cache.put(instance, CacheBuilder.newBuilder() diff --git a/src/main/java/com/simibubi/create/foundation/render/TileEntityRenderHelper.java b/src/main/java/com/simibubi/create/foundation/render/TileEntityRenderHelper.java index a4000218f..0384ab8fd 100644 --- a/src/main/java/com/simibubi/create/foundation/render/TileEntityRenderHelper.java +++ b/src/main/java/com/simibubi/create/foundation/render/TileEntityRenderHelper.java @@ -7,6 +7,7 @@ import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.Debug; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; @@ -24,13 +25,23 @@ public class TileEntityRenderHelper { public static void renderTileEntities(World world, Iterable customRenderTEs, MatrixStack ms, MatrixStack localTransform, IRenderTypeBuffer buffer) { - renderTileEntities(world, null, customRenderTEs, ms, localTransform, buffer); } + + public static void renderTileEntities(World world, Iterable customRenderTEs, MatrixStack ms, + MatrixStack localTransform, IRenderTypeBuffer buffer, float pt) { + renderTileEntities(world, null, customRenderTEs, ms, localTransform, buffer, pt); + } - public static void renderTileEntities(World world, PlacementSimulationWorld renderWorld, Iterable customRenderTEs, MatrixStack ms, - MatrixStack localTransform, IRenderTypeBuffer buffer) { - float pt = AnimationTickHolder.getPartialTicks(); + public static void renderTileEntities(World world, PlacementSimulationWorld renderWorld, + Iterable customRenderTEs, MatrixStack ms, MatrixStack localTransform, IRenderTypeBuffer buffer) { + renderTileEntities(world, renderWorld, customRenderTEs, ms, localTransform, buffer, + AnimationTickHolder.getPartialTicks()); + } + + public static void renderTileEntities(World world, PlacementSimulationWorld renderWorld, + Iterable customRenderTEs, MatrixStack ms, MatrixStack localTransform, IRenderTypeBuffer buffer, + float pt) { Matrix4f matrix = localTransform.peek() .getModel(); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java index 6b57a970a..3c3891c17 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java @@ -1,59 +1,45 @@ package com.simibubi.create.foundation.render.backend; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; import java.nio.FloatBuffer; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Predicate; +import com.simibubi.create.foundation.render.backend.gl.GlFog; +import com.simibubi.create.foundation.render.backend.gl.shader.*; +import com.simibubi.create.foundation.render.backend.gl.versioned.GlFeatureCompat; +import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld; +import net.minecraft.world.World; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GLCapabilities; import org.lwjgl.system.MemoryUtil; import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.render.backend.gl.shader.GlProgram; -import com.simibubi.create.foundation.render.backend.gl.shader.GlShader; -import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec; -import com.simibubi.create.foundation.render.backend.gl.shader.ShaderType; -import com.simibubi.create.foundation.render.backend.gl.versioned.GlVersioned; -import com.simibubi.create.foundation.render.backend.gl.versioned.MapBuffer; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.TextureUtil; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.resource.IResourceType; import net.minecraftforge.resource.ISelectiveResourceReloadListener; -import net.minecraftforge.resource.VanillaResourceType; public class Backend { + public static final Boolean SHADER_DEBUG_OUTPUT = true; + public static final Logger log = LogManager.getLogger(Backend.class); public static final FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16); - private static final Map> registry = new HashMap<>(); - private static final Map, GlProgram> programs = new HashMap<>(); + static final Map> registry = new HashMap<>(); + static final Map, ProgramGroup> programs = new HashMap<>(); private static boolean enabled; public static GLCapabilities capabilities; - private static MapBuffer mapBuffer; + public static GlFeatureCompat compat; public Backend() { throw new IllegalStateException(); } - public static void mapBuffer(int target, int offset, int length, Consumer upload) { - mapBuffer.mapBuffer(target, offset, length, upload); - } - /** * Register a shader program. TODO: replace with forge registry? */ @@ -68,47 +54,25 @@ public class Backend { @SuppressWarnings("unchecked") public static

> P getProgram(S spec) { - return (P) programs.get(spec); + return (P) programs.get(spec).get(GlFog.getFogMode()); } - /** - * Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order. - * - * @param clazz The class of the versioning enum. - * @param The type of the versioning enum. - * @return The first defined enum variant to return true. - */ - public static & GlVersioned> V getLatest(Class clazz) { - return getLatest(clazz, capabilities); - } - - /** - * Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order. - * - * @param clazz The class of the versioning enum. - * @param caps The current system's supported features. - * @param The type of the versioning enum. - * @return The first defined enum variant to return true. - */ - public static & GlVersioned> V getLatest(Class clazz, GLCapabilities caps) { - V[] constants = clazz.getEnumConstants(); - V last = constants[constants.length - 1]; - if (!last.supported(caps)) { - throw new IllegalStateException(""); - } - - return Arrays.stream(constants).filter(it -> it.supported(caps)).findFirst().orElse(last); - } - - public static boolean canUseInstancing() { - return enabled && gl33(); - } - - public static boolean canUseVBOs() { - return enabled && gl20(); + public static boolean isFlywheelWorld(World world) { + return world == Minecraft.getInstance().world || (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel()); } public static boolean available() { + return canUseVBOs(); + } + + public static boolean canUseInstancing() { + return enabled && + compat.vertexArrayObjectsSupported() && + compat.drawInstancedSupported() && + compat.instancedArraysSupported(); + } + + public static boolean canUseVBOs() { return enabled && gl20(); } @@ -128,67 +92,13 @@ public class Backend { IResourceManager manager = mc.getResourceManager(); if (manager instanceof IReloadableResourceManager) { - ISelectiveResourceReloadListener listener = Backend::onResourceManagerReload; + ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload; ((IReloadableResourceManager) manager).addReloadListener(listener); } } - private static void onResourceManagerReload(IResourceManager manager, Predicate predicate) { - if (predicate.test(VanillaResourceType.SHADERS)) { - capabilities = GL.createCapabilities(); - mapBuffer = getLatest(MapBuffer.class); - - OptifineHandler.refresh(); - refresh(); - - if (gl20()) { - - programs.values().forEach(GlProgram::delete); - programs.clear(); - for (ProgramSpec shader : registry.values()) { - loadProgram(manager, shader); - } - } - } - } - public static void refresh() { enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders(); } - private static

> void loadProgram(IResourceManager manager, S programSpec) { - GlShader vert = null; - GlShader frag = null; - try { - vert = loadShader(manager, programSpec.getVert(), ShaderType.VERTEX, programSpec.defines); - frag = loadShader(manager, programSpec.getFrag(), ShaderType.FRAGMENT, programSpec.defines); - - GlProgram.Builder builder = GlProgram.builder(programSpec.name).attachShader(vert).attachShader(frag); - - programSpec.attributes.forEach(builder::addAttribute); - - P program = builder.build(programSpec.factory); - - programs.put(programSpec, program); - - log.info("Loaded program {}", programSpec.name); - } catch (IOException ex) { - log.error("Failed to load program {}", programSpec.name, ex); - } finally { - if (vert != null) vert.delete(); - if (frag != null) frag.delete(); - } - } - - private static GlShader loadShader(IResourceManager manager, ResourceLocation name, ShaderType type, GlShader.PreProcessor preProcessor) throws IOException { - try (InputStream is = new BufferedInputStream(manager.getResource(name).getInputStream())) { - String source = TextureUtil.readAllToString(is); - - if (source == null) { - throw new IOException("Could not load program " + name); - } else { - return new GlShader(type, name, source, preProcessor); - } - } - } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/BufferedModel.java b/src/main/java/com/simibubi/create/foundation/render/backend/BufferedModel.java index 79e4e4d2f..1050da53c 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/BufferedModel.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/BufferedModel.java @@ -14,11 +14,10 @@ import net.minecraft.client.renderer.BufferBuilder; public abstract class BufferedModel extends TemplateBuffer { - protected GlBuffer ebo; protected GlBuffer modelVBO; protected boolean removed; - public BufferedModel(BufferBuilder buf) { + protected BufferedModel(BufferBuilder buf) { super(buf); if (vertexCount > 0) init(); } @@ -28,8 +27,6 @@ public abstract class BufferedModel extends TemplateBuffer { modelVBO = new GlBuffer(GL20.GL_ARRAY_BUFFER); modelVBO.with(vbo -> initModel()); - - ebo = createEBO(); } protected void initModel() { @@ -47,25 +44,6 @@ public abstract class BufferedModel extends TemplateBuffer { }); } - protected final GlBuffer createEBO() { - GlBuffer ebo = new GlBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER); - - int indicesSize = vertexCount * GlPrimitiveType.USHORT.getSize(); - - ebo.bind(); - - GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesSize, GL15.GL_STATIC_DRAW); - ebo.map(indicesSize, indices -> { - for (int i = 0; i < vertexCount; i++) { - indices.putShort((short) i); - } - }); - - ebo.unbind(); - - return ebo; - } - protected abstract void copyVertex(ByteBuffer to, int index); protected abstract VertexFormat getModelFormat(); @@ -75,7 +53,7 @@ public abstract class BufferedModel extends TemplateBuffer { } /** - * Renders this model, checking first if it should actually be rendered. + * Renders this model, checking first if there is anything to render. */ public final void render() { if (vertexCount == 0 || removed) return; @@ -84,23 +62,9 @@ public abstract class BufferedModel extends TemplateBuffer { } /** - * Override this. + * Set up any state and make the draw calls. */ - protected void doRender() { - modelVBO.bind(); - ebo.bind(); - - setupAttributes(); - GL20.glDrawElements(GL20.GL_QUADS, vertexCount, GlPrimitiveType.USHORT.getGlConstant(), 0); - - int numAttributes = getTotalShaderAttributeCount(); - for (int i = 0; i <= numAttributes; i++) { - GL20.glDisableVertexAttribArray(i); - } - - ebo.unbind(); - modelVBO.unbind(); - } + protected abstract void doRender(); protected void setupAttributes() { int numAttributes = getTotalShaderAttributeCount(); @@ -111,7 +75,7 @@ public abstract class BufferedModel extends TemplateBuffer { getModelFormat().vertexAttribPointers(0); } - public void delete() { + public final void delete() { removed = true; if (vertexCount > 0) { RenderWork.enqueue(this::deleteInternal); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java index 2e2b013bf..e1d79b7f3 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java @@ -2,13 +2,11 @@ package com.simibubi.create.foundation.render.backend; import java.util.concurrent.ConcurrentHashMap; -import org.lwjgl.opengl.GL11; +import com.simibubi.create.foundation.render.KineticRenderer; import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.KineticDebugger; -import com.simibubi.create.content.schematics.SchematicWorld; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.WorldAttached; @@ -41,14 +39,15 @@ public class FastRenderDispatcher { public static void tick() { ClientWorld world = Minecraft.getInstance().world; - CreateClient.kineticRenderer.tick(); + KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world); + kineticRenderer.tick(); ConcurrentHashMap.KeySetView map = queuedUpdates.get(world); map .forEach(te -> { map.remove(te); - CreateClient.kineticRenderer.update(te); + kineticRenderer.update(te); }); } @@ -57,7 +56,7 @@ public class FastRenderDispatcher { } public static boolean available(World world) { - return Backend.canUseInstancing() && !(world instanceof SchematicWorld); + return Backend.canUseInstancing() && Backend.isFlywheelWorld(world); } public static int getDebugMode() { @@ -71,9 +70,12 @@ public class FastRenderDispatcher { public static void renderLayer(RenderType layer, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) { if (!Backend.canUseInstancing()) return; + ClientWorld world = Minecraft.getInstance().world; + KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world); + layer.startDrawing(); - CreateClient.kineticRenderer.render(layer, viewProjection, cameraX, cameraY, cameraZ); + kineticRenderer.render(layer, viewProjection, cameraX, cameraY, cameraZ); layer.endDrawing(); } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/RenderMaterials.java b/src/main/java/com/simibubi/create/foundation/render/backend/RenderMaterials.java new file mode 100644 index 000000000..b1a09fc0a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/RenderMaterials.java @@ -0,0 +1,9 @@ +package com.simibubi.create.foundation.render.backend; + +import com.simibubi.create.foundation.render.backend.instancing.MaterialType; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; + +public class RenderMaterials { + public static final MaterialType> MODELS = new MaterialType<>(); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/RenderUtil.java b/src/main/java/com/simibubi/create/foundation/render/backend/RenderUtil.java new file mode 100644 index 000000000..af4a78175 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/RenderUtil.java @@ -0,0 +1,55 @@ +package com.simibubi.create.foundation.render.backend; + +import net.minecraft.util.math.vector.Matrix3f; +import net.minecraft.util.math.vector.Matrix4f; + +import java.nio.ByteBuffer; + +public class RenderUtil { + public static int nextPowerOf2(int a) { + int h = Integer.highestOneBit(a); + return (h == a) ? h : (h << 1); + } + + public static boolean isPowerOf2(int n) { + int b = n & (n - 1); + return b == 0 && n != 0; + } + + // GPUs want matrices in column major order. + + public static void writeMat3(ByteBuffer buf, Matrix3f mat) { + buf.putFloat(mat.a00); + buf.putFloat(mat.a10); + buf.putFloat(mat.a20); + buf.putFloat(mat.a01); + buf.putFloat(mat.a11); + buf.putFloat(mat.a21); + buf.putFloat(mat.a02); + buf.putFloat(mat.a12); + buf.putFloat(mat.a22); + } + + public static void writeMat4(ByteBuffer buf, Matrix4f mat) { + buf.putFloat(mat.a00); + buf.putFloat(mat.a10); + buf.putFloat(mat.a20); + buf.putFloat(mat.a30); + buf.putFloat(mat.a01); + buf.putFloat(mat.a11); + buf.putFloat(mat.a21); + buf.putFloat(mat.a31); + buf.putFloat(mat.a02); + buf.putFloat(mat.a12); + buf.putFloat(mat.a22); + buf.putFloat(mat.a32); + buf.putFloat(mat.a03); + buf.putFloat(mat.a13); + buf.putFloat(mat.a23); + buf.putFloat(mat.a33); + + + + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java b/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java new file mode 100644 index 000000000..a9a4119e5 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java @@ -0,0 +1,202 @@ +package com.simibubi.create.foundation.render.backend; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.render.backend.gl.GlFogMode; +import com.simibubi.create.foundation.render.backend.gl.shader.*; +import com.simibubi.create.foundation.render.backend.gl.versioned.GlFeatureCompat; +import net.minecraft.resources.IResource; +import net.minecraft.resources.IResourceManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.resource.IResourceType; +import net.minecraftforge.resource.VanillaResourceType; +import org.lwjgl.opengl.GL; +import org.lwjgl.system.MemoryUtil; + +import java.io.*; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.util.*; +import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ShaderLoader { + public static final String SHADER_DIR = "flywheel/shaders/"; + public static final ArrayList EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl"); + + static final Map shaderSource = new HashMap<>(); + + static void onResourceManagerReload(IResourceManager manager, Predicate predicate) { + if (predicate.test(VanillaResourceType.SHADERS)) { + Backend.capabilities = GL.createCapabilities(); + Backend.compat = new GlFeatureCompat(Backend.capabilities); + + OptifineHandler.refresh(); + Backend.refresh(); + + if (Backend.gl20()) { + shaderSource.clear(); + loadShaderSources(manager); + + Backend.programs.values().forEach(ProgramGroup::delete); + Backend.programs.clear(); + Backend.registry.values().forEach(ShaderLoader::loadProgram); + + Backend.log.info("Loaded all shader programs."); + } + } + } + + private static void loadShaderSources(IResourceManager manager){ + Collection allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> { + for (String ext : EXTENSIONS) { + if (s.endsWith(ext)) return true; + } + return false; + }); + + for (ResourceLocation location : allShaders) { + try { + IResource resource = manager.getResource(location); + + String file = readToString(resource.getInputStream()); + + ResourceLocation name = new ResourceLocation(location.getNamespace(), + location.getPath().substring(SHADER_DIR.length())); + + shaderSource.put(name, file); + } catch (IOException e) { + + } + } + } + + static

> void loadProgram(S programSpec) { + Map programGroup = new EnumMap<>(GlFogMode.class); + + for (GlFogMode fogMode : GlFogMode.values()) { + programGroup.put(fogMode, loadProgram(programSpec, fogMode)); + } + + Backend.programs.put(programSpec, new ProgramGroup<>(programGroup)); + + Backend.log.debug("Loaded program {}", programSpec.name); + } + + private static

> P loadProgram(S programSpec, GlFogMode fogMode) { + GlShader vert = null; + GlShader frag = null; + try { + ShaderConstants defines = new ShaderConstants(programSpec.defines); + + defines.defineAll(fogMode.getDefines()); + + vert = loadShader(programSpec.getVert(), ShaderType.VERTEX, defines); + frag = loadShader(programSpec.getFrag(), ShaderType.FRAGMENT, defines); + + GlProgram.Builder builder = GlProgram.builder(programSpec.name, fogMode).attachShader(vert).attachShader(frag); + + programSpec.attributes.forEach(builder::addAttribute); + + return builder.build(programSpec.factory); + + } finally { + if (vert != null) vert.delete(); + if (frag != null) frag.delete(); + } + } + + private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">"); + + private static String processIncludes(ResourceLocation baseName, String source) { + HashSet seen = new HashSet<>(); + seen.add(baseName); + + return includeRecursive(source, seen).collect(Collectors.joining("\n")); + } + + private static Stream includeRecursive(String source, Set seen) { + return new BufferedReader(new StringReader(source)).lines().flatMap(line -> { + + Matcher matcher = includePattern.matcher(line); + + if (matcher.find()) { + String includeName = matcher.group(1); + + ResourceLocation include = new ResourceLocation(includeName); + + if (seen.add(include)) { + String includeSource = shaderSource.get(include); + + if (includeSource != null) { + return includeRecursive(includeSource, seen); + } + } + } + + return Stream.of(line); + }); + } + + private static GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) { + String source = shaderSource.get(name); + + source = processIncludes(name, source); + + if (defines != null) + source = defines.process(source); + + + return new GlShader(type, name, source); + } + + public static String readToString(InputStream is) { + RenderSystem.assertThread(RenderSystem::isOnRenderThread); + ByteBuffer bytebuffer = null; + + try { + bytebuffer = readToBuffer(is); + int i = bytebuffer.position(); + ((Buffer)bytebuffer).rewind(); + return MemoryUtil.memASCII(bytebuffer, i); + } catch (IOException e) { + + } finally { + if (bytebuffer != null) { + MemoryUtil.memFree(bytebuffer); + } + + } + + return null; + } + + public static ByteBuffer readToBuffer(InputStream is) throws IOException { + ByteBuffer bytebuffer; + if (is instanceof FileInputStream) { + FileInputStream fileinputstream = (FileInputStream)is; + FileChannel filechannel = fileinputstream.getChannel(); + bytebuffer = MemoryUtil.memAlloc((int)filechannel.size() + 1); + + while (filechannel.read(bytebuffer) != -1) { } + } else { + bytebuffer = MemoryUtil.memAlloc(8192); + ReadableByteChannel readablebytechannel = Channels.newChannel(is); + + while (readablebytechannel.read(bytebuffer) != -1) { + if (bytebuffer.remaining() == 0) { + bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2); + } + } + } + + return bytebuffer; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoadingException.java b/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoadingException.java new file mode 100644 index 000000000..50b1c916a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoadingException.java @@ -0,0 +1,23 @@ +package com.simibubi.create.foundation.render.backend; + +public class ShaderLoadingException extends RuntimeException { + + public ShaderLoadingException() { + } + + public ShaderLoadingException(String message) { + super(message); + } + + public ShaderLoadingException(String message, Throwable cause) { + super(message, cause); + } + + public ShaderLoadingException(Throwable cause) { + super(cause); + } + + public ShaderLoadingException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java index 87310a2c1..01475f2fb 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java @@ -1,5 +1,6 @@ package com.simibubi.create.foundation.render.backend.gl; +import com.simibubi.create.foundation.render.backend.gl.shader.ProgramFogMode; import org.lwjgl.opengl.GL20; import com.simibubi.create.foundation.render.backend.Backend; @@ -14,20 +15,20 @@ public class BasicProgram extends GlProgram { protected final int uViewProjection; protected final int uDebug; protected final int uCameraPos; - protected final int uFogRange; - protected final int uFogColor; + + protected final ProgramFogMode fogMode; protected int uBlockAtlas; protected int uLightMap; - public BasicProgram(ResourceLocation name, int handle) { + public BasicProgram(ResourceLocation name, int handle, ProgramFogMode.Factory fogFactory) { super(name, handle); uTime = getUniformLocation("uTime"); uViewProjection = getUniformLocation("uViewProjection"); uDebug = getUniformLocation("uDebug"); uCameraPos = getUniformLocation("uCameraPos"); - uFogRange = getUniformLocation("uFogRange"); - uFogColor = getUniformLocation("uFogColor"); + + fogMode = fogFactory.create(this); bind(); registerSamplers(); @@ -43,13 +44,12 @@ public class BasicProgram extends GlProgram { super.bind(); GL20.glUniform1i(uDebug, debugMode); - GL20.glUniform1f(uTime, AnimationTickHolder.getRenderTick()); + GL20.glUniform1f(uTime, AnimationTickHolder.getRenderTime()); uploadMatrixUniform(uViewProjection, viewProjection); GL20.glUniform3f(uCameraPos, (float) camX, (float) camY, (float) camZ); - GL20.glUniform2f(uFogRange, GlFog.getFogStart(), GlFog.getFogEnd()); - GL20.glUniform4fv(uFogColor, GlFog.FOG_COLOR); + fogMode.bind(); } protected static void uploadMatrixUniform(int uniform, Matrix4f mat) { diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java index 42a72736b..1dbd256e5 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java @@ -3,9 +3,8 @@ package com.simibubi.create.foundation.render.backend.gl; import java.nio.ByteBuffer; import java.util.function.Consumer; -import org.lwjgl.opengl.GL20; - import com.simibubi.create.foundation.render.backend.Backend; +import org.lwjgl.opengl.GL20; public class GlBuffer extends GlObject { @@ -35,11 +34,11 @@ public class GlBuffer extends GlObject { } public void map(int length, Consumer upload) { - Backend.mapBuffer(bufferType, 0, length, upload); + Backend.compat.mapBuffer(bufferType, 0, length, upload); } public void map(int offset, int length, Consumer upload) { - Backend.mapBuffer(bufferType, offset, length, upload); + Backend.compat.mapBuffer(bufferType, offset, length, upload); } protected void deleteInternal(int handle) { diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFog.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFog.java index de7958b8c..c56a789a8 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFog.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFog.java @@ -1,6 +1,7 @@ package com.simibubi.create.foundation.render.backend.gl; import com.mojang.blaze3d.platform.GlStateManager; +import org.lwjgl.opengl.GL11; public class GlFog { public static float[] FOG_COLOR = new float[] {0, 0, 0, 0}; @@ -9,7 +10,7 @@ public class GlFog { return GlStateManager.FOG.field_179049_a.field_179201_b; } - public static int getFogMode() { + public static int getFogModeGlEnum() { return GlStateManager.FOG.field_179047_b; } @@ -24,4 +25,22 @@ public class GlFog { public static float getFogStart() { return GlStateManager.FOG.field_179045_d; } + + public static GlFogMode getFogMode() { + if (!fogEnabled()) { + return GlFogMode.NONE; + } + + int mode = getFogModeGlEnum(); + + switch (mode) { + case GL11.GL_EXP2: + case GL11.GL_EXP: + return GlFogMode.EXP2; + case GL11.GL_LINEAR: + return GlFogMode.LINEAR; + default: + throw new UnsupportedOperationException("Unknown fog mode: " + mode); + } + } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFogMode.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFogMode.java new file mode 100644 index 000000000..996763bab --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFogMode.java @@ -0,0 +1,39 @@ +package com.simibubi.create.foundation.render.backend.gl; + +import com.google.common.collect.Lists; +import com.simibubi.create.foundation.render.backend.gl.shader.GlShader; +import com.simibubi.create.foundation.render.backend.gl.shader.ProgramFogMode; +import org.lwjgl.opengl.GL11; + +import java.util.Collections; +import java.util.List; + +public enum GlFogMode { + NONE(ProgramFogMode.None::new), + LINEAR(ProgramFogMode.Linear::new, "USE_FOG_LINEAR"), + EXP2(ProgramFogMode.Exp2::new, "USE_FOG_EXP2"), + ; + + public static final String USE_FOG = "USE_FOG"; + + private final ProgramFogMode.Factory fogFactory; + private final List defines; + + GlFogMode(ProgramFogMode.Factory fogFactory) { + this.fogFactory = fogFactory; + this.defines = Collections.emptyList(); + } + + GlFogMode(ProgramFogMode.Factory fogFactory, String name) { + this.fogFactory = fogFactory; + this.defines = Lists.newArrayList(USE_FOG, name); + } + + public List getDefines() { + return defines; + } + + public ProgramFogMode.Factory getFogFactory() { + return fogFactory; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlPrimitiveType.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlPrimitiveType.java index 5e069fabf..c82b02a00 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlPrimitiveType.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlPrimitiveType.java @@ -2,25 +2,27 @@ package com.simibubi.create.foundation.render.backend.gl; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; @OnlyIn(Dist.CLIENT) public enum GlPrimitiveType { - FLOAT(4, "float", 5126), - UBYTE(1, "ubyte", 5121), - BYTE(1, "byte", 5120), - USHORT(2, "ushort", 5123), - SHORT(2, "short", 5122), - UINT(4, "uint", 5125), - INT(4, "int", 5124); + FLOAT(4, "float", GL11.GL_FLOAT), + UBYTE(1, "ubyte", GL11.GL_UNSIGNED_BYTE), + BYTE(1, "byte", GL11.GL_BYTE), + USHORT(2, "ushort", GL11.GL_UNSIGNED_SHORT), + SHORT(2, "short", GL11.GL_SHORT), + UINT(4, "uint", GL11.GL_UNSIGNED_INT), + INT(4, "int", GL11.GL_INT); private final int size; private final String displayName; private final int glConstant; - GlPrimitiveType(int p_i46095_3_, String p_i46095_4_, int p_i46095_5_) { - this.size = p_i46095_3_; - this.displayName = p_i46095_4_; - this.glConstant = p_i46095_5_; + GlPrimitiveType(int bytes, String name, int glEnum) { + this.size = bytes; + this.displayName = name; + this.glConstant = glEnum; } public int getSize() { diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java index 33ff7461b..e4854990e 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java @@ -2,19 +2,19 @@ package com.simibubi.create.foundation.render.backend.gl; import java.util.function.Consumer; -import org.lwjgl.opengl.GL30; +import com.simibubi.create.foundation.render.backend.Backend; public class GlVertexArray extends GlObject { public GlVertexArray() { - setHandle(GL30.glGenVertexArrays()); + setHandle(Backend.compat.genVertexArrays()); } public void bind() { - GL30.glBindVertexArray(handle()); + Backend.compat.bindVertexArray(handle()); } public void unbind() { - GL30.glBindVertexArray(0); + Backend.compat.bindVertexArray(0); } public void with(Consumer action) { @@ -24,6 +24,6 @@ public class GlVertexArray extends GlObject { } protected void deleteInternal(int handle) { - GL30.glDeleteVertexArrays(handle); + Backend.compat.deleteVertexArrays(handle); } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/CommonAttributes.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/CommonAttributes.java index d3fd9d48e..acc24f822 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/CommonAttributes.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/CommonAttributes.java @@ -4,12 +4,12 @@ import com.simibubi.create.foundation.render.backend.gl.GlPrimitiveType; public class CommonAttributes { - public static final VertexAttribSpec MAT4 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 16); public static final VertexAttribSpec VEC4 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 4); public static final VertexAttribSpec VEC3 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 3); public static final VertexAttribSpec VEC2 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2); public static final VertexAttribSpec FLOAT = new VertexAttribSpec(GlPrimitiveType.FLOAT, 1); + public static final VertexAttribSpec QUATERNION = new VertexAttribSpec(GlPrimitiveType.FLOAT, 4); public static final VertexAttribSpec NORMAL = new VertexAttribSpec(GlPrimitiveType.BYTE, 3, true); public static final VertexAttribSpec UV = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IAttribSpec.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IAttribSpec.java new file mode 100644 index 000000000..f16d1deb1 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IAttribSpec.java @@ -0,0 +1,12 @@ +package com.simibubi.create.foundation.render.backend.gl.attrib; + +import org.lwjgl.opengl.GL20; + +public interface IAttribSpec { + + void vertexAttribPointer(int stride, int index, int pointer); + + int getSize(); + + int getAttributeCount(); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IVertexAttrib.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IVertexAttrib.java index 5c77620f9..ee122db00 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IVertexAttrib.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IVertexAttrib.java @@ -4,7 +4,7 @@ public interface IVertexAttrib { String attribName(); - VertexAttribSpec attribSpec(); + IAttribSpec attribSpec(); int getDivisor(); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/InstanceVertexAttributes.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/InstanceVertexAttributes.java new file mode 100644 index 000000000..dacecf161 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/InstanceVertexAttributes.java @@ -0,0 +1,37 @@ +package com.simibubi.create.foundation.render.backend.gl.attrib; + +public enum InstanceVertexAttributes implements IVertexAttrib { + TRANSFORM("aTransform", MatrixAttributes.MAT4), + NORMAL_MAT("aNormalMat", MatrixAttributes.MAT3), + LIGHT("aLight", CommonAttributes.LIGHT), + COLOR("aColor", CommonAttributes.RGBA), + ; + + private final String name; + private final IAttribSpec spec; + + InstanceVertexAttributes(String name, IAttribSpec spec) { + this.name = name; + this.spec = spec; + } + + @Override + public String attribName() { + return name; + } + + @Override + public IAttribSpec attribSpec() { + return spec; + } + + @Override + public int getDivisor() { + return 0; + } + + @Override + public int getBufferIndex() { + return 0; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/MatrixAttributes.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/MatrixAttributes.java new file mode 100644 index 000000000..f7eb4d85f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/MatrixAttributes.java @@ -0,0 +1,36 @@ +package com.simibubi.create.foundation.render.backend.gl.attrib; + +import com.simibubi.create.foundation.render.backend.gl.GlPrimitiveType; +import org.lwjgl.opengl.GL20; + +public enum MatrixAttributes implements IAttribSpec { + MAT3(3, 3), + MAT4(4, 4), + ; + + private final int rows; + private final int cols; + + MatrixAttributes(int rows, int cols) { + this.rows = rows; + this.cols = cols; + } + + @Override + public void vertexAttribPointer(int stride, int index, int pointer) { + for (int i = 0; i < rows; i++) { + long attribPointer = pointer + (long) i * cols * GlPrimitiveType.FLOAT.getSize(); + GL20.glVertexAttribPointer(index + i, cols, GlPrimitiveType.FLOAT.getGlConstant(), false, stride, attribPointer); + } + } + + @Override + public int getSize() { + return GlPrimitiveType.FLOAT.getSize() * rows * cols; + } + + @Override + public int getAttributeCount() { + return rows; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/ModelVertexAttributes.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/ModelVertexAttributes.java index 960289fd6..5fec24349 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/ModelVertexAttributes.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/ModelVertexAttributes.java @@ -20,7 +20,7 @@ public enum ModelVertexAttributes implements IVertexAttrib { } @Override - public VertexAttribSpec attribSpec() { + public IAttribSpec attribSpec() { return spec; } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexAttribSpec.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexAttribSpec.java index 1af7dc3a6..82cdac6fc 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexAttribSpec.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexAttribSpec.java @@ -4,7 +4,7 @@ import org.lwjgl.opengl.GL20; import com.simibubi.create.foundation.render.backend.gl.GlPrimitiveType; -public class VertexAttribSpec { +public class VertexAttribSpec implements IAttribSpec { private final GlPrimitiveType type; private final int count; @@ -24,14 +24,17 @@ public class VertexAttribSpec { this.normalized = normalized; } + @Override public void vertexAttribPointer(int stride, int index, int pointer) { GL20.glVertexAttribPointer(index, count, type.getGlConstant(), normalized, stride, pointer); } + @Override public int getSize() { return size; } + @Override public int getAttributeCount() { return attributeCount; } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexFormat.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexFormat.java index 3929e3354..4541a9205 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexFormat.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexFormat.java @@ -15,7 +15,7 @@ public class VertexFormat { int numAttributes = 0, stride = 0; for (IVertexAttrib attrib : allAttributes) { - VertexAttribSpec spec = attrib.attribSpec(); + IAttribSpec spec = attrib.attribSpec(); numAttributes += spec.getAttributeCount(); stride += spec.getSize(); } @@ -34,7 +34,7 @@ public class VertexFormat { public void vertexAttribPointers(int index) { int offset = 0; for (IVertexAttrib attrib : this.allAttributes) { - VertexAttribSpec spec = attrib.attribSpec(); + IAttribSpec spec = attrib.attribSpec(); spec.vertexAttribPointer(stride, index, offset); index += spec.getAttributeCount(); offset += spec.getSize(); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java index c911eea5f..0b550b448 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java @@ -1,5 +1,6 @@ package com.simibubi.create.foundation.render.backend.gl.shader; +import com.simibubi.create.foundation.render.backend.gl.GlFogMode; import org.lwjgl.opengl.GL20; import com.simibubi.create.foundation.render.backend.Backend; @@ -17,8 +18,8 @@ public abstract class GlProgram extends GlObject { this.name = name; } - public static Builder builder(ResourceLocation name) { - return new Builder(name); + public static Builder builder(ResourceLocation name, GlFogMode fogMode) { + return new Builder(name, fogMode); } public void bind() { @@ -37,8 +38,8 @@ public abstract class GlProgram extends GlObject { public int getUniformLocation(String uniform) { int index = GL20.glGetUniformLocation(this.handle(), uniform); - if (index < 0) { - Backend.log.warn("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name); + if (index < 0 && Backend.SHADER_DEBUG_OUTPUT) { + Backend.log.debug("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name); } return index; @@ -69,12 +70,14 @@ public abstract class GlProgram extends GlObject { public static class Builder { private final ResourceLocation name; private final int program; + private final GlFogMode fogMode; private int attributeIndex; - public Builder(ResourceLocation name) { + public Builder(ResourceLocation name, GlFogMode fogMode) { this.name = name; this.program = GL20.glCreateProgram(); + this.fogMode = fogMode; } public Builder attachShader(GlShader shader) { @@ -103,8 +106,8 @@ public abstract class GlProgram extends GlObject { String log = GL20.glGetProgramInfoLog(this.program); - if (!log.isEmpty()) { - Backend.log.warn("Program link log for " + this.name + ": " + log); + if (!log.isEmpty() && Backend.SHADER_DEBUG_OUTPUT) { + Backend.log.debug("Program link log for " + this.name + ": " + log); } int result = GL20.glGetProgrami(this.program, GL20.GL_LINK_STATUS); @@ -113,12 +116,12 @@ public abstract class GlProgram extends GlObject { throw new RuntimeException("Shader program linking failed, see log for details"); } - return factory.create(this.name, this.program); + return factory.create(this.name, this.program, this.fogMode.getFogFactory()); } } @FunctionalInterface public interface ProgramFactory

{ - P create(ResourceLocation name, int handle); + P create(ResourceLocation name, int handle, ProgramFogMode.Factory fogFactory); } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java index 8ef265920..922b81b47 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java @@ -12,27 +12,22 @@ public class GlShader extends GlObject { public final ResourceLocation name; public final ShaderType type; - public GlShader(ShaderType type, ResourceLocation name, String source, PreProcessor preProcessor) { + public GlShader(ShaderType type, ResourceLocation name, String source) { this.type = type; this.name = name; int handle = GL20.glCreateShader(type.glEnum); - if (preProcessor != null) { - source = preProcessor.process(source); - Backend.log.info("Preprocessor run on " + name);// + ":\n" + source); - } - GL20.glShaderSource(handle, source); GL20.glCompileShader(handle); String log = GL20.glGetShaderInfoLog(handle); if (!log.isEmpty()) { - Backend.log.warn("Shader compilation log for " + name + ": " + log); + Backend.log.error("Shader compilation log for " + name + ": " + log); } if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) { - throw new RuntimeException("Could not compile shader"); + throw new RuntimeException("Could not compile shader. See log for details."); } setHandle(handle); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramFogMode.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramFogMode.java new file mode 100644 index 000000000..804aa5073 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramFogMode.java @@ -0,0 +1,57 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +import com.simibubi.create.foundation.render.backend.gl.GlFog; +import org.lwjgl.opengl.GL20; + +public abstract class ProgramFogMode { + + public abstract void bind(); + + public static class None extends ProgramFogMode { + + public None(GlProgram program) { + + } + + @Override + public void bind() { + + } + } + + public static class Linear extends ProgramFogMode { + private final int uFogColor; + private final int uFogRange; + + public Linear(GlProgram program) { + this.uFogColor = program.getUniformLocation("uFogColor"); + this.uFogRange = program.getUniformLocation("uFogRange"); + } + + @Override + public void bind() { + GL20.glUniform2f(uFogRange, GlFog.getFogStart(), GlFog.getFogEnd()); + GL20.glUniform4fv(uFogColor, GlFog.FOG_COLOR); + } + } + + public static class Exp2 extends ProgramFogMode { + private final int uFogColor; + private final int uFogDensity; + + public Exp2(GlProgram program) { + this.uFogColor = program.getUniformLocation("uFogColor"); + this.uFogDensity = program.getUniformLocation("uFogDensity"); + } + + @Override + public void bind() { + GL20.glUniform1f(uFogDensity, GlFog.getFogDensity()); + GL20.glUniform4fv(uFogColor, GlFog.FOG_COLOR); + } + } + + public interface Factory { + ProgramFogMode create(GlProgram program); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramGroup.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramGroup.java new file mode 100644 index 000000000..b31ae0237 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramGroup.java @@ -0,0 +1,22 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +import com.simibubi.create.foundation.render.backend.gl.GlFogMode; + +import java.util.Map; + +public class ProgramGroup

{ + + private final Map programs; + + public ProgramGroup(Map programs) { + this.programs = programs; + } + + public P get(GlFogMode fogMode) { + return programs.get(fogMode); + } + + public void delete() { + programs.values().forEach(GlProgram::delete); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java index 7c2a2ca93..a7bc130af 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java @@ -50,7 +50,7 @@ public class ProgramSpec

{ public static class Builder

{ private ResourceLocation vert; private ResourceLocation frag; - private ShaderConstants defines = null; + private ShaderConstants defines = ShaderConstants.EMPTY; private final ResourceLocation name; private final GlProgram.ProgramFactory

factory; diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderConstants.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderConstants.java index 3f1ed6c09..9c509cc7d 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderConstants.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderConstants.java @@ -1,12 +1,16 @@ package com.simibubi.create.foundation.render.backend.gl.shader; +import com.google.common.collect.Lists; + import java.io.BufferedReader; import java.io.StringReader; import java.util.ArrayList; +import java.util.Collection; import java.util.stream.Collectors; import java.util.stream.Stream; public class ShaderConstants implements GlShader.PreProcessor { + public static final ShaderConstants EMPTY = new ShaderConstants(); private final ArrayList defines; @@ -14,6 +18,10 @@ public class ShaderConstants implements GlShader.PreProcessor { defines = new ArrayList<>(); } + public ShaderConstants(ShaderConstants other) { + this.defines = Lists.newArrayList(other.defines); + } + public static ShaderConstants define(String def) { return new ShaderConstants().def(def); } @@ -23,6 +31,11 @@ public class ShaderConstants implements GlShader.PreProcessor { return this; } + public ShaderConstants defineAll(Collection defines) { + this.defines.addAll(defines); + return this; + } + public ArrayList getDefines() { return defines; } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/DrawInstanced.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/DrawInstanced.java new file mode 100644 index 000000000..4c206581d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/DrawInstanced.java @@ -0,0 +1,54 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.*; + +public enum DrawInstanced implements GlVersioned { + GL31_DRAW_INSTANCED { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL31; + } + + @Override + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + GL31.glDrawArraysInstanced(mode, first, count, primcount); + } + }, + ARB_DRAW_INSTANCED { + @Override + public boolean supported(GLCapabilities caps) { + return caps.GL_ARB_draw_instanced; + } + + @Override + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + ARBDrawInstanced.glDrawArraysInstancedARB(mode, first, count, primcount); + } + }, + EXT_DRAW_INSTANCED { + @Override + public boolean supported(GLCapabilities caps) { + return caps.GL_EXT_draw_instanced; + } + + @Override + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + EXTDrawInstanced.glDrawArraysInstancedEXT(mode, first, count, primcount); + } + }, + UNSUPPORTED { + @Override + public boolean supported(GLCapabilities caps) { + return true; + } + + @Override + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + throw new UnsupportedOperationException(); + } + } + + ; + + public abstract void drawArraysInstanced(int mode, int first, int count, int primcount); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlFeatureCompat.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlFeatureCompat.java new file mode 100644 index 000000000..b2eba08e1 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlFeatureCompat.java @@ -0,0 +1,89 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.GLCapabilities; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.function.Consumer; + +/** + * An instance of this class stores information + * about what OpenGL features are available. + * + * Each field stores an enum variant that provides access to the + * most appropriate version of a feature for the current system. + */ +public class GlFeatureCompat { + public final MapBuffer mapBuffer; + + public final VertexArrayObject vertexArrayObject; + public final InstancedArrays instancedArrays; + public final DrawInstanced drawInstanced; + + public final RGPixelFormat pixelFormat; + + public GlFeatureCompat(GLCapabilities caps) { + mapBuffer = getLatest(MapBuffer.class, caps); + + vertexArrayObject = getLatest(VertexArrayObject.class, caps); + instancedArrays = getLatest(InstancedArrays.class, caps); + drawInstanced = getLatest(DrawInstanced.class, caps); + + pixelFormat = getLatest(RGPixelFormat.class, caps); + } + + public void mapBuffer(int target, int offset, int length, Consumer upload) { + mapBuffer.mapBuffer(target, offset, length, upload); + } + + public void vertexAttribDivisor(int index, int divisor) { + instancedArrays.vertexAttribDivisor(index, divisor); + } + + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + drawInstanced.drawArraysInstanced(mode, first, count, primcount); + } + + public int genVertexArrays() { + return vertexArrayObject.genVertexArrays(); + } + + public void deleteVertexArrays(int array) { + vertexArrayObject.deleteVertexArrays(array); + } + + public void bindVertexArray(int array) { + vertexArrayObject.bindVertexArray(array); + } + + public boolean vertexArrayObjectsSupported() { + return vertexArrayObject != VertexArrayObject.UNSUPPORTED; + } + + public boolean instancedArraysSupported() { + return instancedArrays != InstancedArrays.UNSUPPORTED; + } + + public boolean drawInstancedSupported() { + return drawInstanced != DrawInstanced.UNSUPPORTED; + } + + /** + * Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order. + * + * @param clazz The class of the versioning enum. + * @param caps The current system's supported features. + * @param The type of the versioning enum. + * @return The first defined enum variant to return true. + */ + public static & GlVersioned> V getLatest(Class clazz, GLCapabilities caps) { + V[] constants = clazz.getEnumConstants(); + V last = constants[constants.length - 1]; + if (!last.supported(caps)) { + throw new IllegalStateException(""); + } + + return Arrays.stream(constants).filter(it -> it.supported(caps)).findFirst().get(); + } +} + diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java index 53d929ea0..6f456c802 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java @@ -2,7 +2,15 @@ package com.simibubi.create.foundation.render.backend.gl.versioned; import org.lwjgl.opengl.GLCapabilities; - +/** + * This interface should be implemented by enums such that the + * last defined variant always returns true. + */ public interface GlVersioned { + /** + * Queries whether this variant is supported by the current system. + * @param caps The {@link GLCapabilities} reported by the current system. + * @return true if this variant is supported, or if this is the last defined variant. + */ boolean supported(GLCapabilities caps); } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/InstancedArrays.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/InstancedArrays.java new file mode 100644 index 000000000..1c000a37d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/InstancedArrays.java @@ -0,0 +1,43 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.*; + +public enum InstancedArrays implements GlVersioned { + GL33_INSTANCED_ARRAYS { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL33; + } + + @Override + public void vertexAttribDivisor(int index, int divisor) { + GL33.glVertexAttribDivisor(index, divisor); + } + }, + ARB_INSTANCED_ARRAYS { + @Override + public boolean supported(GLCapabilities caps) { + return caps.GL_ARB_instanced_arrays; + } + + @Override + public void vertexAttribDivisor(int index, int divisor) { + ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor); + } + }, + UNSUPPORTED { + @Override + public boolean supported(GLCapabilities caps) { + return true; + } + + @Override + public void vertexAttribDivisor(int index, int divisor) { + throw new UnsupportedOperationException(); + } + } + + ; + + public abstract void vertexAttribDivisor(int index, int divisor); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/RGPixelFormat.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/RGPixelFormat.java new file mode 100644 index 000000000..9cf035535 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/RGPixelFormat.java @@ -0,0 +1,75 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.*; + +public enum RGPixelFormat implements GlVersioned { + GL30_RG { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL30; + } + + @Override + public int internalFormat() { + return GL30.GL_RG8; + } + + @Override + public int format() { + return GL30.GL_RG; + } + + @Override + public int byteCount() { + return 2; + } + }, + GL11_RGB { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL11; + } + + @Override + public int internalFormat() { + return GL11.GL_RGB8; + } + + @Override + public int format() { + return GL11.GL_RGB; + } + + @Override + public int byteCount() { + return 3; + } + }, + UNSUPPORTED { + @Override + public boolean supported(GLCapabilities caps) { + return true; + } + + @Override + public int internalFormat() { + throw new UnsupportedOperationException(); + } + + @Override + public int format() { + throw new UnsupportedOperationException(); + } + + @Override + public int byteCount() { + throw new UnsupportedOperationException(); + } + } + + ; + + public abstract int internalFormat(); + public abstract int format(); + public abstract int byteCount(); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/VertexArrayObject.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/VertexArrayObject.java new file mode 100644 index 000000000..58b9f0fc8 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/VertexArrayObject.java @@ -0,0 +1,77 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.*; + +public enum VertexArrayObject implements GlVersioned { + GL30_VAO { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL30; + } + + @Override + public int genVertexArrays() { + return GL30.glGenVertexArrays(); + } + + @Override + public void bindVertexArray(int array) { + GL30.glBindVertexArray(array); + } + + @Override + public void deleteVertexArrays(int array) { + GL30.glDeleteVertexArrays(array); + } + }, + ARB_VAO { + @Override + public boolean supported(GLCapabilities caps) { + return caps.GL_ARB_vertex_array_object; + } + + @Override + public int genVertexArrays() { + return ARBVertexArrayObject.glGenVertexArrays(); + } + + @Override + public void bindVertexArray(int array) { + ARBVertexArrayObject.glBindVertexArray(array); + } + + @Override + public void deleteVertexArrays(int array) { + ARBVertexArrayObject.glDeleteVertexArrays(array); + } + }, + UNSUPPORTED { + @Override + public boolean supported(GLCapabilities caps) { + return true; + } + + @Override + public int genVertexArrays() { + throw new UnsupportedOperationException(); + } + + @Override + public void bindVertexArray(int array) { + throw new UnsupportedOperationException(); + } + + @Override + public void deleteVertexArrays(int array) { + throw new UnsupportedOperationException(); + } + } + + ; + + public abstract int genVertexArrays(); + + public abstract void bindVertexArray(int array); + + public abstract void deleteVertexArrays(int array); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IFlywheelWorld.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IFlywheelWorld.java new file mode 100644 index 000000000..91684c428 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IFlywheelWorld.java @@ -0,0 +1,13 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +/** + * A marker interface custom worlds can override to indicate + * that tiles inside the world should render with Flywheel. + * + * Minecraft.getInstance().world will always support Flywheel. + */ +public interface IFlywheelWorld { + default boolean supportsFlywheel() { + return true; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IInstanceRendered.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IInstanceRendered.java index a1558446f..05f3f35b5 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IInstanceRendered.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IInstanceRendered.java @@ -1,8 +1,6 @@ package com.simibubi.create.foundation.render.backend.instancing; -import com.simibubi.create.foundation.render.backend.light.ILightListener; - -public interface IInstanceRendered extends ILightListener { +public interface IInstanceRendered { default boolean shouldRenderAsTE() { return false; } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IRendererFactory.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IRendererFactory.java index 196e029d8..f1ec0d323 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IRendererFactory.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IRendererFactory.java @@ -4,5 +4,5 @@ import net.minecraft.tileentity.TileEntity; @FunctionalInterface public interface IRendererFactory { - TileEntityInstance create(InstancedTileRenderer manager, T te); + TileEntityInstance create(InstancedTileRenderer manager, T te); } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ITickableInstance.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ITickableInstance.java new file mode 100644 index 000000000..4d79545a4 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ITickableInstance.java @@ -0,0 +1,8 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +public interface ITickableInstance { + /** + * Called every frame, this can be used to make more dynamic animations. + */ + void tick(); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceKey.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceKey.java index 166bf8e56..6a3ec6d1e 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceKey.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceKey.java @@ -21,8 +21,8 @@ public class InstanceKey { return index != INVALID; } - public void modifyInstance(Consumer edit) { - model.modifyInstance(this, edit); + public D getInstance() { + return model.getInstance(this); } public void delete() { diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java index b18cffcc4..b3f6aa49e 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java @@ -2,16 +2,15 @@ package com.simibubi.create.foundation.render.backend.instancing; import java.nio.ByteBuffer; -import java.util.ArrayList; +import java.util.*; import java.util.function.Consumer; +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.RenderUtil; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL20; -import org.lwjgl.opengl.GL31; -import org.lwjgl.opengl.GL33; -import com.simibubi.create.foundation.render.RenderMath; import com.simibubi.create.foundation.render.backend.BufferedModel; import com.simibubi.create.foundation.render.backend.gl.GlBuffer; import com.simibubi.create.foundation.render.backend.gl.GlVertexArray; @@ -35,6 +34,8 @@ public abstract class InstancedModel extends BufferedMod protected int minIndexChanged = -1; protected int maxIndexChanged = -1; + protected boolean anyToRemove; + public InstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { super(buf); this.renderer = renderer; @@ -70,39 +71,24 @@ public abstract class InstancedModel extends BufferedMod vao.delete(); } - protected abstract D newInstance(); - public synchronized void deleteInstance(InstanceKey key) { verifyKey(key); - int index = key.index; - - keys.remove(index); - data.remove(index); - - for (int i = index; i < keys.size(); i++) { - keys.get(i).index--; - } - - maxIndexChanged = keys.size() - 1; - markIndexChanged(Math.min(maxIndexChanged, index)); - key.invalidate(); + + anyToRemove = true; } - public synchronized void modifyInstance(InstanceKey key, Consumer edit) { + public D getInstance(InstanceKey key) { verifyKey(key); - D data = this.data.get(key.index); - - edit.accept(data); - markIndexChanged(key.index); + + return this.data.get(key.index); } - public synchronized InstanceKey setupInstance(Consumer setup) { + public synchronized InstanceKey createInstance() { D instanceData = newInstance(); - setup.accept(instanceData); InstanceKey key = new InstanceKey<>(this, data.size()); data.add(instanceData); @@ -113,21 +99,25 @@ public abstract class InstancedModel extends BufferedMod return key; } + protected abstract D newInstance(); + protected void doRender() { vao.with(vao -> { renderSetup(); - GL31.glDrawArraysInstanced(GL11.GL_QUADS, 0, vertexCount, glInstanceCount); + Backend.compat.drawArraysInstanced(GL11.GL_QUADS, 0, vertexCount, glInstanceCount); }); } protected void renderSetup() { - if (minIndexChanged < 0 || data.isEmpty()) return; + boolean anyRemoved = doRemoval(); + + if (!anyRemoved && (minIndexChanged < 0 || data.isEmpty())) return; VertexFormat instanceFormat = getInstanceFormat(); int stride = instanceFormat.getStride(); int newInstanceCount = instanceCount(); - int instanceSize = RenderMath.nextPowerOf2((newInstanceCount + 1) * stride); + int instanceSize = RenderUtil.nextPowerOf2((newInstanceCount + 1) * stride); instanceVBO.with(vbo -> { // this probably changes enough that it's not worth reallocating the entire buffer every time. @@ -141,11 +131,13 @@ public abstract class InstancedModel extends BufferedMod int offset = minIndexChanged * stride; int length = (1 + maxIndexChanged - minIndexChanged) * stride; - vbo.map(offset, length, buffer -> { - for (int i = minIndexChanged; i <= maxIndexChanged; i++) { - data.get(i).write(buffer); - } - }); + if (length > 0) { + vbo.map(offset, length, buffer -> { + for (int i = minIndexChanged; i <= maxIndexChanged; i++) { + data.get(i).write(buffer); + } + }); + } if (newInstanceCount < glInstanceCount) { int clearFrom = (maxIndexChanged + 1) * stride; @@ -163,7 +155,7 @@ public abstract class InstancedModel extends BufferedMod instanceFormat.vertexAttribPointers(staticAttributes); for (int i = 0; i < instanceFormat.getShaderAttributeCount(); i++) { - GL33.glVertexAttribDivisor(i + staticAttributes, 1); + Backend.compat.vertexAttribDivisor(i + staticAttributes, 1); } }); @@ -171,6 +163,52 @@ public abstract class InstancedModel extends BufferedMod maxIndexChanged = -1; } + // copied from ArrayList#removeIf + protected boolean doRemoval() { + if (!anyToRemove) return false; + + // figure out which elements are to be removed + // any exception thrown from the filter predicate at this stage + // will leave the collection unmodified + int removeCount = 0; + final int size = this.keys.size(); + final BitSet removeSet = new BitSet(size); + for (int i=0; i < size; i++) { + final InstanceKey element = this.keys.get(i); + if (!element.isValid()) { + removeSet.set(i); + removeCount++; + } + } + + // shift surviving elements left over the spaces left by removed elements + final boolean anyToRemove = removeCount > 0; + if (anyToRemove) { + final int newSize = size - removeCount; + for (int i = 0, j = 0; (i < size) && (j < newSize); i++, j++) { + i = removeSet.nextClearBit(i); + keys.set(j, keys.get(i)); + data.set(j, data.get(i)); + } + + keys.subList(newSize, size).clear(); + data.subList(newSize, size).clear(); + + int firstChanged = removeSet.nextSetBit(0); + + for (int i = firstChanged; i < newSize; i++) { + keys.get(i).index = i; + } + + minIndexChanged = 0; + maxIndexChanged = newSize - 1; + } + + this.anyToRemove = false; + + return anyToRemove; + } + protected void markIndexChanged(int index) { if (minIndexChanged < 0) { minIndexChanged = index; diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java index 25dd60880..6928d8feb 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java @@ -1,29 +1,32 @@ package com.simibubi.create.foundation.render.backend.instancing; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.*; import javax.annotation.Nullable; +import com.simibubi.create.foundation.ponder.PonderWorld; import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.RenderMaterials; import com.simibubi.create.foundation.render.backend.gl.BasicProgram; import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.WorldAttached; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.world.ClientWorld; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; public abstract class InstancedTileRenderer

{ - public static WorldAttached> addedLastTick = new WorldAttached<>(ConcurrentHashMap::new); + protected ArrayList queuedAdditions = new ArrayList<>(64); protected Map> instances = new HashMap<>(); + protected Map tickableInstances = new HashMap<>(); + protected Map, RenderMaterial> materials = new HashMap<>(); protected InstancedTileRenderer() { @@ -35,23 +38,8 @@ public abstract class InstancedTileRenderer

{ public abstract void registerMaterials(); public void tick() { - ClientWorld world = Minecraft.getInstance().world; - int ticks = AnimationTickHolder.getTicks(); - ConcurrentHashMap map = addedLastTick.get(world); - map - .entrySet() - .stream() - .filter(it -> ticks - it.getValue() > 10) - .map(Map.Entry::getKey) - .forEach(te -> { - map.remove(te); - - onLightUpdate(te); - }); - - // Clean up twice a second. This doesn't have to happen every tick, // but this does need to be run to ensure we don't miss anything. if (ticks % 10 == 0) { @@ -59,11 +47,32 @@ public abstract class InstancedTileRenderer

{ } } + public void beginFrame(double cameraX, double cameraY, double cameraZ) { + queuedAdditions.forEach(this::add); + queuedAdditions.clear(); + tickableInstances.values().forEach(ITickableInstance::tick); + } + + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { + render(layer, viewProjection, camX, camY, camZ, null); + } + + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, ShaderCallback

callback) { + for (RenderMaterial material : materials.values()) { + if (material.canRenderInLayer(layer)) + material.render(layer, viewProjection, camX, camY, camZ, callback); + } + } + @SuppressWarnings("unchecked") public > RenderMaterial getMaterial(MaterialType materialType) { return (RenderMaterial) materials.get(materialType); } + public RenderMaterial> basicMaterial() { + return getMaterial(RenderMaterials.MODELS); + } + @Nullable public TileEntityInstance getInstance(T tile) { return getInstance(tile, true); @@ -72,7 +81,7 @@ public abstract class InstancedTileRenderer

{ @SuppressWarnings("unchecked") @Nullable public TileEntityInstance getInstance(T tile, boolean create) { - if (!Backend.canUseInstancing()) return null; + if (!Backend.canUseInstancing() || !canCreateInstance(tile)) return null; TileEntityInstance instance = instances.get(tile); @@ -82,8 +91,10 @@ public abstract class InstancedTileRenderer

{ TileEntityInstance renderer = InstancedTileRenderRegistry.instance.create(this, tile); if (renderer != null) { - addedLastTick.get(tile.getWorld()).put(tile, AnimationTickHolder.getTicks()); instances.put(tile, renderer); + + if (renderer instanceof ITickableInstance) + tickableInstances.put(tile, (ITickableInstance) renderer); } return renderer; @@ -111,6 +122,12 @@ public abstract class InstancedTileRenderer

{ } } + public void queueAdd(T tile) { + if (!Backend.canUseInstancing()) return; + + queuedAdditions.add(tile); + } + public void update(T tile) { if (!Backend.canUseInstancing()) return; @@ -131,6 +148,7 @@ public abstract class InstancedTileRenderer

{ if (instance != null) { instance.remove(); instances.remove(tile); + tickableInstances.remove(tile); } } } @@ -144,16 +162,24 @@ public abstract class InstancedTileRenderer

{ material.delete(); } instances.clear(); + tickableInstances.clear(); } - public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { - render(layer, viewProjection, camX, camY, camZ, null); - } + public boolean canCreateInstance(TileEntity tile) { + if (tile.isRemoved()) return false; - public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, ShaderCallback

callback) { - for (RenderMaterial material : materials.values()) { - if (material.canRenderInLayer(layer)) - material.render(layer, viewProjection, camX, camY, camZ, callback); + World world = tile.getWorld(); + + if (world == null) return false; + + if (world == Minecraft.getInstance().world) { + BlockPos pos = tile.getPos(); + + IBlockReader existingChunk = world.getExistingChunk(pos.getX() >> 4, pos.getZ() >> 4); + + return existingChunk != null; } + + return world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel(); } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java index ed4b1f162..b5241999c 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java @@ -1,10 +1,16 @@ package com.simibubi.create.foundation.render.backend.instancing; +import com.simibubi.create.foundation.render.backend.instancing.impl.IFlatLight; +import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.LightType; import net.minecraft.world.World; +import java.util.Arrays; +import java.util.stream.Stream; + public abstract class TileEntityInstance { protected final InstancedTileRenderer modelManager; @@ -42,7 +48,7 @@ public abstract class TileEntityInstance { * Update changed instance data using the {@link InstanceKey}s you got in {@link #init()}. * You don't have to update light data. That should be done in {@link #updateLight()} */ - protected abstract void onUpdate(); + protected void onUpdate() { } /** * Called when a light update occurs in the world. If your model needs it, update light here. @@ -53,4 +59,24 @@ public abstract class TileEntityInstance { * Call {@link InstanceKey#delete()} on all acquired keys. */ public abstract void remove(); + + public BlockPos getFloatingPos() { + return pos.subtract(modelManager.getOriginCoordinate()); + } + + protected > void relight(BlockPos pos, IFlatLight... models) { + relight(world.getLightLevel(LightType.BLOCK, pos), world.getLightLevel(LightType.SKY, pos), models); + } + + protected > void relight(BlockPos pos, Stream> models) { + relight(world.getLightLevel(LightType.BLOCK, pos), world.getLightLevel(LightType.SKY, pos), models); + } + + protected > void relight(int block, int sky, IFlatLight... models) { + relight(block, sky, Arrays.stream(models)); + } + + protected > void relight(int block, int sky, Stream> models) { + models.forEach(model -> model.setBlockLight(block).setSkyLight(sky)); + } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/impl/BasicInstancedModel.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/impl/BasicInstancedModel.java new file mode 100644 index 000000000..cd67de720 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/impl/BasicInstancedModel.java @@ -0,0 +1,25 @@ +package com.simibubi.create.foundation.render.backend.instancing.impl; + +import com.simibubi.create.foundation.render.backend.gl.attrib.InstanceVertexAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import net.minecraft.client.renderer.BufferBuilder; + +public class BasicInstancedModel extends InstancedModel { + public static final VertexFormat INSTANCE_FORMAT = VertexFormat.builder().addAttributes(InstanceVertexAttributes.class).build(); + + public BasicInstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(renderer, buf); + } + + @Override + protected ModelData newInstance() { + return new ModelData(this); + } + + @Override + protected VertexFormat getInstanceFormat() { + return INSTANCE_FORMAT; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/impl/IFlatLight.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/impl/IFlatLight.java new file mode 100644 index 000000000..7dea998b1 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/impl/IFlatLight.java @@ -0,0 +1,26 @@ +package com.simibubi.create.foundation.render.backend.instancing.impl; + +import com.simibubi.create.foundation.render.backend.instancing.InstanceData; + +/** + * An interface that implementors of {@link InstanceData} should also implement + * if they wish to make use of Flywheel's provided light update methods. + * + * This only covers flat lighting, smooth lighting is still TODO. + * @param The name of the class that implements this interface. + */ +public interface IFlatLight> { + /** + * @param blockLight An integer in the range [0, 15] representing the + * amount of block light this instance should receive. + * @return this + */ + D setBlockLight(int blockLight); + + /** + * @param skyLight An integer in the range [0, 15] representing the + * amount of sky light this instance should receive. + * @return this + */ + D setSkyLight(int skyLight); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/impl/ModelData.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/impl/ModelData.java new file mode 100644 index 000000000..827dad117 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/impl/ModelData.java @@ -0,0 +1,102 @@ +package com.simibubi.create.foundation.render.backend.instancing.impl; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.render.backend.RenderUtil; +import com.simibubi.create.foundation.render.backend.instancing.InstanceData; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import net.minecraft.util.math.vector.Matrix3f; +import net.minecraft.util.math.vector.Matrix4f; + +import java.nio.ByteBuffer; + +public class ModelData extends InstanceData implements IFlatLight { + private static final Matrix4f IDENT4 = new Matrix4f(); + private static final Matrix3f IDENT3 = new Matrix3f(); + static { + IDENT4.loadIdentity(); + IDENT3.loadIdentity(); + } + + private Matrix4f modelMat = IDENT4; + private Matrix3f normalMat = IDENT3; + + private byte blockLight; + private byte skyLight; + + private byte r = (byte) 0xFF; + private byte g = (byte) 0xFF; + private byte b = (byte) 0xFF; + private byte a = (byte) 0xFF; + + public ModelData(InstancedModel owner) { + super(owner); + } + + public ModelData setModelMat(Matrix4f modelMat) { + this.modelMat = modelMat; + return this; + } + + public ModelData setNormalMat(Matrix3f normalMat) { + this.normalMat = normalMat; + return this; + } + + public ModelData setTransform(MatrixStack stack) { + this.modelMat = stack.peek().getModel().copy(); + this.normalMat = stack.peek().getNormal().copy(); + return this; + } + + public ModelData setTransformNoCopy(MatrixStack stack) { + this.modelMat = stack.peek().getModel(); + this.normalMat = stack.peek().getNormal(); + return this; + } + + @Override + public ModelData setBlockLight(int blockLight) { + this.blockLight = (byte) (blockLight << 4); + return this; + } + + @Override + public ModelData setSkyLight(int skyLight) { + this.skyLight = (byte) (skyLight << 4); + return this; + } + + public ModelData setColor(int color) { + byte a = (byte) ((color >> 24) & 0xFF); + byte r = (byte) ((color >> 16) & 0xFF); + byte g = (byte) ((color >> 8) & 0xFF); + byte b = (byte) (color & 0xFF); + return setColor(r, g, b); + } + + public ModelData setColor(int r, int g, int b) { + return setColor((byte) r, (byte) g, (byte) b); + } + + public ModelData setColor(byte r, byte g, byte b) { + this.r = r; + this.g = g; + this.b = b; + return this; + } + + public ModelData setColor(byte r, byte g, byte b, byte a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + return this; + } + + @Override + public void write(ByteBuffer buf) { + RenderUtil.writeMat4(buf, modelMat); + RenderUtil.writeMat3(buf, normalMat); + buf.put(new byte[] { blockLight, skyLight, r, g, b, a }); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/GridAlignedBB.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/GridAlignedBB.java index 78732ee81..82ecd770d 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/light/GridAlignedBB.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/GridAlignedBB.java @@ -1,8 +1,8 @@ package com.simibubi.create.foundation.render.backend.light; -import static com.simibubi.create.foundation.render.RenderMath.isPowerOf2; +import static com.simibubi.create.foundation.render.backend.RenderUtil.isPowerOf2; -import com.simibubi.create.foundation.render.RenderMath; +import com.simibubi.create.foundation.render.backend.RenderUtil; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; @@ -53,6 +53,17 @@ public class GridAlignedBB { pos.getWorldEndZ() + 1); } + public static GridAlignedBB fromChunk(int sectionX, int sectionZ) { + int startX = sectionX << 4; + int startZ = sectionZ << 4; + return new GridAlignedBB(startX, + 0, + startZ, + startX + 16, + 256, + startZ + 16); + } + public static AxisAlignedBB toAABB(GridAlignedBB bb) { return new AxisAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); } @@ -131,9 +142,9 @@ public class GridAlignedBB { int sizeY = sizeY(); int sizeZ = sizeZ(); - int newSizeX = RenderMath.nextPowerOf2(sizeX); - int newSizeY = RenderMath.nextPowerOf2(sizeY); - int newSizeZ = RenderMath.nextPowerOf2(sizeZ); + int newSizeX = RenderUtil.nextPowerOf2(sizeX); + int newSizeY = RenderUtil.nextPowerOf2(sizeY); + int newSizeZ = RenderUtil.nextPowerOf2(sizeZ); int diffX = newSizeX - sizeX; int diffY = newSizeY - sizeY; @@ -151,9 +162,9 @@ public class GridAlignedBB { * Grow this bounding box to have power of 2 side lengths, scaling from the minimum coords. */ public void nextPowerOf2() { - int sizeX = RenderMath.nextPowerOf2(sizeX()); - int sizeY = RenderMath.nextPowerOf2(sizeY()); - int sizeZ = RenderMath.nextPowerOf2(sizeZ()); + int sizeX = RenderUtil.nextPowerOf2(sizeX()); + int sizeY = RenderUtil.nextPowerOf2(sizeY()); + int sizeZ = RenderUtil.nextPowerOf2(sizeZ()); this.maxX = this.minX + sizeX; this.maxY = this.minY + sizeY; @@ -258,6 +269,10 @@ public class GridAlignedBB { } } + public AxisAlignedBB toAABB() { + return toAABB(this); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java index 84bef0cf7..933f99e35 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java @@ -2,11 +2,12 @@ package com.simibubi.create.foundation.render.backend.light; import java.nio.ByteBuffer; +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.gl.versioned.RGPixelFormat; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; -import org.lwjgl.opengl.GL40; import org.lwjgl.system.MemoryUtil; import com.simibubi.create.foundation.render.backend.RenderWork; @@ -15,7 +16,6 @@ import com.simibubi.create.foundation.render.backend.gl.GlTexture; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.SectionPos; import net.minecraft.world.IBlockDisplayReader; -import net.minecraft.world.IWorldReader; import net.minecraft.world.LightType; public class LightVolume { @@ -29,11 +29,15 @@ public class LightVolume { private final GlTexture glTexture; + private final RGPixelFormat pixelFormat; + public LightVolume(GridAlignedBB sampleVolume) { setSampleVolume(sampleVolume); + pixelFormat = Backend.compat.pixelFormat; + this.glTexture = new GlTexture(GL20.GL_TEXTURE_3D); - this.lightData = MemoryUtil.memAlloc(this.textureVolume.volume() * 2); // TODO: reduce this to span only sampleVolume + this.lightData = MemoryUtil.memAlloc(this.textureVolume.volume() * pixelFormat.byteCount()); // allocate space for the texture GL20.glActiveTexture(GL20.GL_TEXTURE4); @@ -42,7 +46,7 @@ public class LightVolume { int sizeX = textureVolume.sizeX(); int sizeY = textureVolume.sizeY(); int sizeZ = textureVolume.sizeZ(); - GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, 0); + GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, pixelFormat.internalFormat(), sizeX, sizeY, sizeZ, 0, pixelFormat.format(), GL20.GL_UNSIGNED_BYTE, 0); glTexture.unbind(); GL20.glActiveTexture(GL20.GL_TEXTURE0); @@ -129,6 +133,15 @@ public class LightVolume { else if (type == LightType.SKY) copySky(world, changedVolume); } + public void notifyLightPacket(IBlockDisplayReader world, int chunkX, int chunkZ) { + GridAlignedBB changedVolume = GridAlignedBB.fromChunk(chunkX, chunkZ); + if (!changedVolume.intersects(sampleVolume)) + return; + changedVolume.intersectAssign(sampleVolume); // compute the region contained by us that has dirty lighting data. + + copyLight(world, changedVolume); + } + /** * Completely (re)populate this volume with block and sky lighting data. * This is expensive and should be avoided. @@ -223,7 +236,7 @@ public class LightVolume { // just in case something goes wrong or we accidentally call this before this volume is properly disposed of. if (lightData == null || removed) return; - GL13.glActiveTexture(GL40.GL_TEXTURE4); + GL13.glActiveTexture(GL20.GL_TEXTURE4); glTexture.bind(); GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR); GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR); @@ -246,7 +259,7 @@ public class LightVolume { int sizeY = textureVolume.sizeY(); int sizeZ = textureVolume.sizeZ(); - GL12.glTexSubImage3D(GL12.GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightData); + GL12.glTexSubImage3D(GL12.GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, pixelFormat.format(), GL20.GL_UNSIGNED_BYTE, lightData); GL20.glPixelStorei(GL20.GL_UNPACK_ALIGNMENT, 4); // 4 is the default bufferDirty = false; @@ -270,7 +283,7 @@ public class LightVolume { byte b = (byte) ((block & 0xF) << 4); byte s = (byte) ((sky & 0xF) << 4); - int i = index(x, y, z); + int i = posToIndex(x, y, z); lightData.put(i, b); lightData.put(i + 1, s); } @@ -278,16 +291,16 @@ public class LightVolume { private void writeBlock(int x, int y, int z, int block) { byte b = (byte) ((block & 0xF) << 4); - lightData.put(index(x, y, z), b); + lightData.put(posToIndex(x, y, z), b); } private void writeSky(int x, int y, int z, int sky) { byte b = (byte) ((sky & 0xF) << 4); - lightData.put(index(x, y, z) + 1, b); + lightData.put(posToIndex(x, y, z) + 1, b); } - private int index(int x, int y, int z) { - return (x + textureVolume.sizeX() * (y + z * textureVolume.sizeY())) * 2; + private int posToIndex(int x, int y, int z) { + return (x + textureVolume.sizeX() * (y + z * textureVolume.sizeY())) * pixelFormat.byteCount(); } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolumeDebugger.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolumeDebugger.java index 811987c5d..ca96b1b79 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolumeDebugger.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolumeDebugger.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.outliner.AABBOutline; @@ -29,6 +30,6 @@ public class LightVolumeDebugger { outline.getParams().colored(pair.getSecond()); return outline; }) - .forEach(outline -> outline.render(ms, buffer)); + .forEach(outline -> outline.render(ms, buffer, AnimationTickHolder.getPartialTicks())); } } diff --git a/src/main/java/com/simibubi/create/foundation/renderState/SuperRenderTypeBuffer.java b/src/main/java/com/simibubi/create/foundation/renderState/SuperRenderTypeBuffer.java index 2377e721b..be9fa3e57 100644 --- a/src/main/java/com/simibubi/create/foundation/renderState/SuperRenderTypeBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/renderState/SuperRenderTypeBuffer.java @@ -1,5 +1,7 @@ package com.simibubi.create.foundation.renderState; +import java.util.Objects; +import java.util.Optional; import java.util.SortedMap; import com.mojang.blaze3d.systems.RenderSystem; @@ -13,9 +15,11 @@ import net.minecraft.client.renderer.RegionRenderCacheBuilder; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.model.ModelBakery; import net.minecraft.util.Util; +import net.minecraft.util.math.BlockPos; public class SuperRenderTypeBuffer implements IRenderTypeBuffer { + public static BlockPos vertexSortingOrigin = BlockPos.ZERO; static SuperRenderTypeBuffer instance; public static SuperRenderTypeBuffer getInstance() { @@ -65,6 +69,7 @@ public class SuperRenderTypeBuffer implements IRenderTypeBuffer { // Visible clones from net.minecraft.client.renderer.RenderTypeBuffers static final RegionRenderCacheBuilder blockBuilders = new RegionRenderCacheBuilder(); + static final SortedMap createEntityBuilders() { return Util.make(new Object2ObjectLinkedOpenHashMap<>(), (map) -> { map.put(Atlases.getEntitySolid(), blockBuilders.get(RenderType.getSolid())); @@ -86,7 +91,6 @@ public class SuperRenderTypeBuffer implements IRenderTypeBuffer { }); }); } - private static void assign(Object2ObjectLinkedOpenHashMap map, RenderType type) { map.put(type, new BufferBuilder(type.getExpectedBufferSize())); @@ -96,6 +100,20 @@ public class SuperRenderTypeBuffer implements IRenderTypeBuffer { super(new BufferBuilder(256), createEntityBuilders()); } + public void draw(RenderType p_228462_1_) { + BlockPos v = vertexSortingOrigin; + BufferBuilder bufferbuilder = layerBuffers.getOrDefault(p_228462_1_, this.fallbackBuffer); + boolean flag = Objects.equals(this.currentLayer, p_228462_1_.asOptional()); + if (flag || bufferbuilder != this.fallbackBuffer) { + if (this.activeConsumers.remove(bufferbuilder)) { + p_228462_1_.draw(bufferbuilder, v.getX(), v.getY(), v.getZ()); + if (flag) { + this.currentLayer = Optional.empty(); + } + } + } + } + } } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/ComparatorUtil.java b/src/main/java/com/simibubi/create/foundation/tileEntity/ComparatorUtil.java new file mode 100644 index 000000000..e35593b63 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/ComparatorUtil.java @@ -0,0 +1,26 @@ +package com.simibubi.create.foundation.tileEntity; + +import com.simibubi.create.foundation.fluid.SmartFluidTank; +import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.IBlockReader; + +public class ComparatorUtil { + + public static int fractionToRedstoneLevel(double frac) { + return MathHelper.floor(MathHelper.clamp(frac * 14 + (frac > 0 ? 1 : 0), 0, 15)); + } + + public static int levelOfSmartFluidTank(IBlockReader world, BlockPos pos) { + SmartFluidTankBehaviour fluidBehaviour = TileEntityBehaviour.get(world, pos, SmartFluidTankBehaviour.TYPE); + if (fluidBehaviour == null) + return 0; + SmartFluidTank primaryHandler = fluidBehaviour.getPrimaryHandler(); + double fillFraction = (double) primaryHandler.getFluid() + .getAmount() / primaryHandler.getCapacity(); + return fractionToRedstoneLevel(fillFraction); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java b/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java index af52a4b24..cd63d60db 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java @@ -24,6 +24,9 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka private int lazyTickRate; private int lazyTickCounter; + // Used for simulating this TE in a client-only setting + private boolean virtualMode; + public SmartTileEntity(TileEntityType tileEntityTypeIn) { super(tileEntityTypeIn); behaviours = new HashMap<>(); @@ -145,17 +148,23 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka @SuppressWarnings("unchecked") public T getBehaviour(BehaviourType type) { - if (behaviours.containsKey(type)) - return (T) behaviours.get(type); - return null; + return (T) behaviours.get(type); } - + protected boolean isItemHandlerCap(Capability cap) { return cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; } - + protected boolean isFluidHandlerCap(Capability cap) { return cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY; } + + public void markVirtual() { + virtualMode = true; + } + + public boolean isVirtual() { + return virtualMode; + } } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/SyncedTileEntity.java b/src/main/java/com/simibubi/create/foundation/tileEntity/SyncedTileEntity.java index d16146759..c31c91252 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/SyncedTileEntity.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/SyncedTileEntity.java @@ -9,6 +9,9 @@ import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SUpdateTileEntityPacket; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.math.SectionPos; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.fml.network.PacketDistributor; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault @@ -68,4 +71,12 @@ public abstract class SyncedTileEntity extends TileEntity { sendData(); } + public PacketDistributor.PacketTarget packetTarget() { + return PacketDistributor.TRACKING_CHUNK.with(this::containedChunk); + } + + public Chunk containedChunk() { + SectionPos sectionPos = SectionPos.from(pos); + return world.getChunk(sectionPos.getSectionX(), sectionPos.getSectionZ()); + } } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java index af79b9005..859346c4a 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java @@ -5,7 +5,6 @@ import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; @@ -47,7 +46,7 @@ public abstract class TileEntityBehaviour { } - public void onNeighborChanged(Direction direction) { + public void onNeighborChanged(BlockPos neighborPos) { } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/ValueBox.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/ValueBox.java index 883bccb19..a81df38bb 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/ValueBox.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/ValueBox.java @@ -75,7 +75,7 @@ public class ValueBox extends ChasingAABBOutline { } @Override - public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { + public void render(MatrixStack ms, SuperRenderTypeBuffer buffer, float pt) { boolean hasTransform = transform != null; if (transform instanceof Sided && params.getHighlightedFace() != null) ((Sided) transform).fromSide(params.getHighlightedFace()); @@ -90,7 +90,7 @@ public class ValueBox extends ChasingAABBOutline { .getNormal() .copy(); params.colored(isPassive ? passiveColor : highlightColor); - super.render(ms, buffer); + super.render(ms, buffer, pt); float fontScale = hasTransform ? -transform.getFontScale() : -1 / 64f; ms.scale(fontScale, fontScale, fontScale); diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringHandler.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringHandler.java index ee573a53a..df129fe5a 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringHandler.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringHandler.java @@ -127,6 +127,8 @@ public class FilteringHandler { return false; if (!filtering.isCountVisible()) return false; + if (!filtering.isActive()) + return false; if (filtering.slotPositioning instanceof ValueBoxTransform.Sided) ((Sided) filtering.slotPositioning).fromSide(result.getFace()); if (!filtering.testHit(objectMouseOver.getHitVec())) diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java index c69c1aeb2..8775f16d3 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java @@ -9,8 +9,8 @@ import com.simibubi.create.foundation.fluid.SmartFluidTank; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; -import com.simibubi.create.foundation.utility.LerpedFloat; -import com.simibubi.create.foundation.utility.LerpedFloat.Chaser; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; import com.simibubi.create.foundation.utility.NBTHelper; import net.minecraft.nbt.CompoundNBT; @@ -132,6 +132,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { protected void updateFluids() { fluidUpdateCallback.run(); tileEntity.sendData(); + tileEntity.markDirty(); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/InvManipulationBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/InvManipulationBehaviour.java index 55ee7dc0a..a7c6b6319 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/InvManipulationBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/InvManipulationBehaviour.java @@ -139,6 +139,13 @@ public class InvManipulationBehaviour extends TileEntityBehaviour { findNewNextTick = true; } + @Override + public void onNeighborChanged(BlockPos neighborPos) { + BlockFace targetBlockFace = target.getTarget(getWorld(), tileEntity.getPos(), tileEntity.getBlockState()); + if (targetBlockFace.getConnectedPos().equals(neighborPos)) + onHandlerInvalidated(targetCapability); + } + protected void onHandlerInvalidated(LazyOptional handler) { findNewNextTick = true; targetCapability = LazyOptional.empty(); @@ -168,7 +175,7 @@ public class InvManipulationBehaviour extends TileEntityBehaviour { return amount; } - protected void findNewCapability() { + public void findNewCapability() { BlockFace targetBlockFace = target.getTarget(getWorld(), tileEntity.getPos(), tileEntity.getBlockState()) .getOpposite(); BlockPos pos = targetBlockFace.getPos(); diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueHandler.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueHandler.java index c614f07c6..52b6ddf8e 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueHandler.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueHandler.java @@ -7,6 +7,7 @@ import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform.Sided; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour.StepContext; +import com.simibubi.create.foundation.utility.animation.PhysicalFloat; import net.minecraft.client.Minecraft; import net.minecraft.client.world.ClientWorld; import net.minecraft.util.math.BlockPos; @@ -20,6 +21,11 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber; @EventBusSubscriber public class ScrollValueHandler { + private static float lastPassiveScroll = 0.0f; + private static float passiveScroll = 0.0f; + private static float passiveScrollDirection = 1f; + private static final PhysicalFloat wrenchCog = PhysicalFloat.create().withDrag(0.3); + @OnlyIn(Dist.CLIENT) public static boolean onScroll(double delta) { RayTraceResult objectMouseOver = Minecraft.getInstance().objectMouseOver; @@ -36,6 +42,10 @@ public class ScrollValueHandler { return false; if (!mc.player.isAllowEdit()) return false; + + passiveScrollDirection = (float) -delta; + wrenchCog.bump(3, -delta * 10); + if (scrolling.needsWrench && !AllItems.WRENCH.isIn(mc.player.getHeldItemMainhand())) return false; if (scrolling.slotPositioning instanceof Sided) @@ -57,6 +67,17 @@ public class ScrollValueHandler { return true; } + public static float getScroll(float partialTicks) { + return wrenchCog.getValue(partialTicks) + MathHelper.lerp(partialTicks, lastPassiveScroll, passiveScroll); + } + + @OnlyIn(Dist.CLIENT) + public static void tick() { + lastPassiveScroll = passiveScroll; + wrenchCog.tick(); + passiveScroll += passiveScrollDirection * 0.5; + } + protected static void applyTo(double delta, ScrollValueBehaviour scrolling) { scrolling.ticksUntilScrollPacket = 10; int valueBefore = scrolling.scrollableValue; diff --git a/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java b/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java index 4b8f410c5..1da015fd6 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java +++ b/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java @@ -1,6 +1,10 @@ package com.simibubi.create.foundation.utility; +import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.ponder.PonderWorld; + import net.minecraft.client.Minecraft; +import net.minecraft.world.IWorld; public class AnimationTickHolder { @@ -15,8 +19,12 @@ public class AnimationTickHolder { ticks = (ticks + 1) % 1_728_000; // wrap around every 24 hours so we maintain enough floating point precision } } + + public static int getTicks() { + return ticks; + } - public static float getRenderTick() { + public static float getRenderTime() { return getTicks() + getPartialTicks(); } @@ -24,8 +32,16 @@ public class AnimationTickHolder { Minecraft mc = Minecraft.getInstance(); return (mc.isGamePaused() ? mc.renderPartialTicksPaused : mc.getRenderPartialTicks()); } - - public static int getTicks() { - return ticks; + + public static int getTicks(IWorld world) { + return world instanceof PonderWorld ? PonderUI.ponderTicks : getTicks(); + } + + public static float getRenderTime(IWorld world) { + return getTicks(world) + getPartialTicks(world); + } + + public static float getPartialTicks(IWorld world) { + return world instanceof PonderWorld ? PonderUI.getPartialTicks() : getPartialTicks(); } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/BlockHelper.java b/src/main/java/com/simibubi/create/foundation/utility/BlockHelper.java index 40a92fab2..87a103e85 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/BlockHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/BlockHelper.java @@ -173,20 +173,21 @@ public class BlockHelper { public static void destroyBlock(World world, BlockPos pos, float effectChance, Consumer droppedItemCallback) { - FluidState FluidState = world.getFluidState(pos); + + FluidState fluidState = world.getFluidState(pos); BlockState state = world.getBlockState(pos); if (world.rand.nextFloat() < effectChance) world.playEvent(2001, pos, Block.getStateId(state)); TileEntity tileentity = state.hasTileEntity() ? world.getTileEntity(pos) : null; - if (world.getGameRules() - .getBoolean(GameRules.DO_TILE_DROPS) && !world.restoringBlockSnapshots && world instanceof ServerWorld) { + if (world instanceof ServerWorld && world.getGameRules() + .getBoolean(GameRules.DO_TILE_DROPS) && !world.restoringBlockSnapshots) { for (ItemStack itemStack : Block.getDrops(state, (ServerWorld) world, pos, tileentity)) droppedItemCallback.accept(itemStack); state.spawnAdditionalDrops((ServerWorld) world, pos, ItemStack.EMPTY); } - world.setBlockState(pos, FluidState.getBlockState()); + world.setBlockState(pos, fluidState.getBlockState()); } public static boolean isSolidWall(IBlockReader reader, BlockPos fromPos, Direction toDirection) { diff --git a/src/main/java/com/simibubi/create/foundation/utility/ColorHelper.java b/src/main/java/com/simibubi/create/foundation/utility/ColorHelper.java index 432f87431..51996fb3a 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/ColorHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/ColorHelper.java @@ -4,6 +4,7 @@ import java.util.UUID; import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3d; public class ColorHelper { @@ -30,6 +31,14 @@ public class ColorHelper { return 255 - progress; } + public static int applyAlpha(int color, float alpha) { + int prevAlphaChannel = (color >> 24) & 0xFF; + if (prevAlphaChannel > 0) + alpha *= prevAlphaChannel / 256f; + int alphaChannel = (int) (0xFF * MathHelper.clamp(alpha, 0, 1)); + return (color & 0xFFFFFF) | alphaChannel << 24; + } + public static int mixColors(int color1, int color2, float w) { int r1 = (color1 >> 16); int g1 = (color1 >> 8) & 0xFF; @@ -43,9 +52,25 @@ public class ColorHelper { return color; } + public static int mixAlphaColors(int color1, int color2, float w) { + int a1 = (color1 >> 24); + int r1 = (color1 >> 16) & 0xFF; + int g1 = (color1 >> 8) & 0xFF; + int b1 = color1 & 0xFF; + int a2 = (color2 >> 24); + int r2 = (color2 >> 16) & 0xFF; + int g2 = (color2 >> 8) & 0xFF; + int b2 = color2 & 0xFF; + + int color = ((int) (a1 + (a2 - a1) * w) << 24) + ((int) (r1 + (r2 - r1) * w) << 16) + + ((int) (g1 + (g2 - g1) * w) << 8) + (int) (b1 + (b2 - b1) * w); + + return color; + } + public static void glColor(int color) { color = mixColors(color, 0xFFFFFF, .5f); - int r = (color >> 16); + int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = color & 0xFF; @@ -57,7 +82,7 @@ public class ColorHelper { } public static Vector3d getRGB(int color) { - int r = (color >> 16); + int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = color & 0xFF; return new Vector3d(r, g, b).scale(1 / 256d); diff --git a/src/main/java/com/simibubi/create/foundation/utility/Coordinate.java b/src/main/java/com/simibubi/create/foundation/utility/Coordinate.java new file mode 100644 index 000000000..adb419c3e --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/Coordinate.java @@ -0,0 +1,8 @@ +package com.simibubi.create.foundation.utility; + +import net.minecraft.util.math.BlockPos; + +@FunctionalInterface +public interface Coordinate { + float get(BlockPos from); +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/Couple.java b/src/main/java/com/simibubi/create/foundation/utility/Couple.java index 9c36c903f..1c0cf6153 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Couple.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Couple.java @@ -6,6 +6,7 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.Stream; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; @@ -104,6 +105,10 @@ public class Couple extends Pair implements Iterable { return new Couplerator<>(this); } + public Stream stream() { + return Stream.of(first, second); + } + private static class Couplerator implements Iterator { int state; diff --git a/src/main/java/com/simibubi/create/foundation/utility/FontHelper.java b/src/main/java/com/simibubi/create/foundation/utility/FontHelper.java new file mode 100644 index 000000000..22bccb551 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/FontHelper.java @@ -0,0 +1,85 @@ +package com.simibubi.create.foundation.utility; + +import java.text.BreakIterator; +import java.util.LinkedList; +import java.util.List; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.TransformationMatrix; +import net.minecraftforge.client.MinecraftForgeClient; + +public final class FontHelper { + + private FontHelper() { + } + + public static List cutString(FontRenderer font, String text, int maxWidthPerLine) { + // Split words + List words = new LinkedList<>(); + BreakIterator iterator = BreakIterator.getLineInstance(MinecraftForgeClient.getLocale()); + iterator.setText(text); + int start = iterator.first(); + for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next()) { + String word = text.substring(start, end); + words.add(word); + } + // Apply hard wrap + List lines = new LinkedList<>(); + StringBuilder currentLine = new StringBuilder(); + int width = 0; + for (String word : words) { + int newWidth = font.getStringWidth(word); + if (width + newWidth > maxWidthPerLine) { + if (width > 0) { + String line = currentLine.toString(); + lines.add(line); + currentLine = new StringBuilder(); + width = 0; + } else { + lines.add(word); + continue; + } + } + currentLine.append(word); + width += newWidth; + } + if (width > 0) { + lines.add(currentLine.toString()); + } + return lines; + } + + public static void drawSplitString(FontRenderer font, String text, int x, int y, int width, int color) { + List list = cutString(font, text, width); + Matrix4f matrix4f = TransformationMatrix.identity().getMatrix(); + + for (String s : list) { + float f = (float) x; + if (font.getBidiFlag()) { + int i = font.getStringWidth(font.bidiReorder(s)); + f += (float) (width - i); + } + + draw(font, s, f, (float) y, color, matrix4f, false); + y += 9; + } + } + + private static int draw(FontRenderer font, String p_228078_1_, float p_228078_2_, float p_228078_3_, + int p_228078_4_, Matrix4f p_228078_5_, boolean p_228078_6_) { + if (p_228078_1_ == null) { + return 0; + } else { + IRenderTypeBuffer.Impl irendertypebuffer$impl = IRenderTypeBuffer + .immediate(Tessellator.getInstance().getBuffer()); + int i = font.draw(p_228078_1_, p_228078_2_, p_228078_3_, p_228078_4_, p_228078_6_, p_228078_5_, + irendertypebuffer$impl, false, 0, 15728880); + irendertypebuffer$impl.draw(); + return i; + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/Lang.java b/src/main/java/com/simibubi/create/foundation/utility/Lang.java index 11e5aeb6a..62384d800 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Lang.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Lang.java @@ -26,14 +26,14 @@ public class Lang { public static List translatedOptions(String prefix, String... keys) { List result = new ArrayList<>(keys.length); - for (String key : keys) { + for (String key : keys) result.add(translate(prefix + "." + key)); - } + return result; } public static String asId(String name) { - return name.toLowerCase(Locale.ENGLISH); + return name.toLowerCase(Locale.ROOT); } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java b/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java index dc838dba5..70cd06f1c 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java +++ b/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java @@ -2,15 +2,17 @@ package com.simibubi.create.foundation.utility; import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Quaternion; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3f; import net.minecraft.util.math.vector.Vector3i; public class MatrixStacker { - static Vector3d center = VecHelper.getCenterOf(BlockPos.ZERO); + public static final Vector3d center = VecHelper.getCenterOf(BlockPos.ZERO); static MatrixStacker instance; MatrixStack ms; @@ -22,6 +24,23 @@ public class MatrixStacker { return instance; } + public MatrixStacker restoreIdentity() { + MatrixStack.Entry entry = ms.peek(); + + entry.getModel().loadIdentity(); + entry.getNormal().loadIdentity(); + + return this; + } + + public MatrixStacker rotate(Direction axis, float radians) { + if (radians == 0) + return this; + ms.multiply(axis.getUnitVector() + .getRadialQuaternion(radians)); + return this; + } + public MatrixStacker rotate(double angle, Axis axis) { Vector3f vec = axis == Axis.X ? Vector3f.POSITIVE_X : axis == Axis.Y ? Vector3f.POSITIVE_Y : Vector3f.POSITIVE_Z; @@ -63,8 +82,18 @@ public class MatrixStacker { return this; } + public MatrixStacker translate(double x, double y, double z) { + ms.translate(x, y, z); + return this; + } + + public MatrixStacker multiply(Quaternion quaternion) { + ms.multiply(quaternion); + return this; + } + public MatrixStacker nudge(int id) { - long randomBits = (long) id * 493286711L; + long randomBits = (long) id * 31L * 493286711L; randomBits = randomBits * randomBits * 4392167121L + randomBits * 98761L; float xNudge = (((float) (randomBits >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; float yNudge = (((float) (randomBits >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; @@ -73,11 +102,25 @@ public class MatrixStacker { return this; } - private MatrixStacker multiply(Vector3f axis, double angle) { + public MatrixStacker multiply(Vector3f axis, double angle) { if (angle == 0) return this; ms.multiply(axis.getDegreesQuaternion((float) angle)); return this; } + public MatrixStacker push() { + ms.push(); + return this; + } + + public MatrixStacker pop() { + ms.pop(); + return this; + } + + public MatrixStack unwrap() { + return ms; + } + } diff --git a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java index 4c195b8b6..de27b649a 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java +++ b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java @@ -219,7 +219,7 @@ public class TreeCutter { } private static boolean isLeaf(BlockState state) { - return BlockHelper.hasBlockStateProperty(state, LeavesBlock.DISTANCE); + return state.contains(LeavesBlock.DISTANCE) || state.isIn(BlockTags.LEAVES); } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/UniqueLinkedList.java b/src/main/java/com/simibubi/create/foundation/utility/UniqueLinkedList.java new file mode 100644 index 000000000..d30c3badb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/UniqueLinkedList.java @@ -0,0 +1,89 @@ +package com.simibubi.create.foundation.utility; + +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +public class UniqueLinkedList extends LinkedList { + private final HashSet contained = new HashSet<>(); + + @Override + public boolean contains(Object o) { + return contained.contains(o); + } + + @Override + public E poll() { + E e = super.poll(); + contained.remove(e); + return e; + } + + @Override + public boolean add(E e) { + if (contained.add(e)) return super.add(e); + else return false; + } + + @Override + public void add(int index, E element) { + if (contained.add(element)) super.add(index, element); + } + + @Override + public void addFirst(E e) { + if (contained.add(e)) super.addFirst(e); + } + + @Override + public void addLast(E e) { + if (contained.add(e)) super.addLast(e); + } + + @Override + public boolean addAll(Collection c) { + List filtered = c.stream().filter(it -> !contained.contains(it)).collect(Collectors.toList()); + return super.addAll(filtered); + } + + @Override + public boolean addAll(int index, Collection c) { + List filtered = c.stream().filter(it -> !contained.contains(it)).collect(Collectors.toList()); + return super.addAll(index, filtered); + } + + @Override + public boolean remove(Object o) { + contained.remove(o); + return super.remove(o); + } + + @Override + public E remove(int index) { + E e = super.remove(index); + contained.remove(e); + return e; + } + + @Override + public E removeFirst() { + E e = super.removeFirst(); + contained.remove(e); + return e; + } + + @Override + public E removeLast() { + E e = super.removeLast(); + contained.remove(e); + return e; + } + + @Override + public void clear() { + super.clear(); + contained.clear(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java index bfaef8b36..1f39b14ae 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java @@ -60,7 +60,8 @@ public class VecHelper { } public static boolean isVecPointingTowards(Vector3d vec, Direction direction) { - return Vector3d.of(direction.getDirectionVec()).distanceTo(vec.normalize()) < .75; + return Vector3d.of(direction.getDirectionVec()).dotProduct(vec.normalize()) > 0; + //return new Vec3d(direction.getDirectionVec()).distanceTo(vec.normalize()) < .75; } public static Vector3d getCenterOf(Vector3i pos) { @@ -124,6 +125,11 @@ public class VecHelper { .scale(maxLength) : vec; } + public static Vector3d lerp(float p, Vector3d from, Vector3d to) { + return from.add(to.subtract(from) + .scale(p)); + } + public static Vector3d clampComponentWise(Vector3d vec, float maxLength) { return new Vector3d(MathHelper.clamp(vec.x, -maxLength, maxLength), MathHelper.clamp(vec.y, -maxLength, maxLength), MathHelper.clamp(vec.z, -maxLength, maxLength)); diff --git a/src/main/java/com/simibubi/create/foundation/utility/WorldAttached.java b/src/main/java/com/simibubi/create/foundation/utility/WorldAttached.java index 99a84db53..c457bea5e 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/WorldAttached.java +++ b/src/main/java/com/simibubi/create/foundation/utility/WorldAttached.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -39,5 +40,9 @@ public class WorldAttached { public void put(IWorld world, T entry) { attached.put(world, entry); } + + public void forEach(Consumer consumer) { + attached.values().forEach(consumer); + } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/animation/Force.java b/src/main/java/com/simibubi/create/foundation/utility/animation/Force.java new file mode 100644 index 000000000..23e7d0080 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/animation/Force.java @@ -0,0 +1,84 @@ +package com.simibubi.create.foundation.utility.animation; + +public interface Force { + + float get(float mass, float value, float speed); + + boolean finished(); + + class Drag implements Force { + final float dragFactor; + + public Drag(float dragFactor) { + this.dragFactor = dragFactor; + } + + @Override + public float get(float mass, float value, float speed) { + return -speed * dragFactor; + } + + @Override + public boolean finished() { + return false; + } + } + + class Zeroing implements Force { + final float g; + + public Zeroing(float g) { + this.g = g / 20; + } + + @Override + public float get(float mass, float value, float speed) { + return -Math.signum(value) * g * mass; + } + + @Override + public boolean finished() { + return false; + } + } + + class Impulse implements Force { + + float force; + + public Impulse(float force) { + this.force = force; + } + + @Override + public float get(float mass, float value, float speed) { + return force; + } + + @Override + public boolean finished() { + return true; + } + } + + class OverTime implements Force { + int timeRemaining; + float f; + + public OverTime(int time, float totalAcceleration) { + this.timeRemaining = time; + this.f = totalAcceleration / (float) time; + } + + @Override + public float get(float mass, float value, float speed) { + timeRemaining--; + return f; + } + + @Override + public boolean finished() { + return timeRemaining <= 0; + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/LerpedFloat.java b/src/main/java/com/simibubi/create/foundation/utility/animation/LerpedFloat.java similarity index 91% rename from src/main/java/com/simibubi/create/foundation/utility/LerpedFloat.java rename to src/main/java/com/simibubi/create/foundation/utility/animation/LerpedFloat.java index 073f2fc07..7e99e39cb 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/LerpedFloat.java +++ b/src/main/java/com/simibubi/create/foundation/utility/animation/LerpedFloat.java @@ -1,5 +1,6 @@ -package com.simibubi.create.foundation.utility; +package com.simibubi.create.foundation.utility.animation; +import com.simibubi.create.foundation.utility.AngleHelper; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.math.MathHelper; @@ -46,6 +47,10 @@ public class LerpedFloat { return this; } + public void updateChaseTarget(float target) { + this.chaseTarget = target; + } + public boolean updateChaseSpeed(double speed) { float prevSpeed = this.chaseSpeed; this.chaseSpeed = (float) speed; @@ -76,6 +81,10 @@ public class LerpedFloat { return MathHelper.lerp(partialTicks, previousValue, value); } + public boolean settled() { + return MathHelper.epsilonEquals(previousValue, value); + } + public float getChaseTarget() { return chaseTarget; } diff --git a/src/main/java/com/simibubi/create/foundation/utility/animation/PhysicalFloat.java b/src/main/java/com/simibubi/create/foundation/utility/animation/PhysicalFloat.java new file mode 100644 index 000000000..a710d8525 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/animation/PhysicalFloat.java @@ -0,0 +1,80 @@ +package com.simibubi.create.foundation.utility.animation; + +import net.minecraft.util.math.MathHelper; + +import java.util.ArrayList; + +public class PhysicalFloat { + + float previousValue; + float value; + + float previousSpeed; + float speed; + + float mass; + + private final ArrayList forces = new ArrayList<>(); + + public static PhysicalFloat create() { + return new PhysicalFloat(1); + } + + public static PhysicalFloat create(float mass) { + return new PhysicalFloat(mass); + } + + public PhysicalFloat(float mass) { + this.mass = mass; + } + + public PhysicalFloat startAt(double value) { + previousValue = this.value = (float) value; + return this; + } + + public PhysicalFloat withDrag(double drag) { + return addForce(new Force.Drag((float) drag)); + } + + public PhysicalFloat zeroing(double g) { + return addForce(new Force.Zeroing((float) g)); + } + + public void tick() { + previousSpeed = speed; + previousValue = value; + + float totalImpulse = 0; + for (Force force : forces) + totalImpulse += force.get(mass, value, speed) / mass; + + speed += totalImpulse; + + forces.removeIf(Force::finished); + + value += speed; + } + + public PhysicalFloat addForce(Force f) { + forces.add(f); + return this; + } + + public PhysicalFloat bump(double force) { + return addForce(new Force.Impulse((float) force)); + } + + public PhysicalFloat bump(int time, double force) { + return addForce(new Force.OverTime(time, (float) force)); + } + + public float getValue() { + return getValue(1); + } + + public float getValue(float partialTicks) { + return MathHelper.lerp(partialTicks, previousValue, value); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/ghost/GhostBlockRenderer.java b/src/main/java/com/simibubi/create/foundation/utility/ghost/GhostBlockRenderer.java index 4bd7af59a..0a30866a8 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/ghost/GhostBlockRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/utility/ghost/GhostBlockRenderer.java @@ -142,7 +142,8 @@ public abstract class GhostBlockRenderer { Vector3f vector3f = new Vector3f((float) vec3i.getX(), (float) vec3i.getY(), (float) vec3i.getZ()); Matrix4f matrix4f = p_227890_1_.getModel(); vector3f.transform(p_227890_1_.getNormal()); - int j = aint.length / 8; + int vertexSize = DefaultVertexFormats.BLOCK.getIntegerSize(); + int j = aint.length / vertexSize; try (MemoryStack memorystack = MemoryStack.stackPush()) { ByteBuffer bytebuffer = memorystack.malloc(DefaultVertexFormats.BLOCK.getSize()); @@ -150,7 +151,7 @@ public abstract class GhostBlockRenderer { for (int k = 0; k < j; ++k) { ((Buffer) intbuffer).clear(); - intbuffer.put(aint, k * 8, 8); + intbuffer.put(aint, k * vertexSize, vertexSize); float f = bytebuffer.getFloat(0); float f1 = bytebuffer.getFloat(4); float f2 = bytebuffer.getFloat(8); diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java index daee1416b..9839b890d 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java @@ -22,7 +22,7 @@ public class AABBOutline extends Outline { } @Override - public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { + public void render(MatrixStack ms, SuperRenderTypeBuffer buffer, float pt) { renderBB(ms, buffer, bb); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java index 751a01554..1f91f886f 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java @@ -30,7 +30,7 @@ public class BlockClusterOutline extends Outline { } @Override - public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { + public void render(MatrixStack ms, SuperRenderTypeBuffer buffer, float pt) { for (MergeEntry edge : cluster.visibleEdges) { Vector3d start = Vector3d.of(edge.pos); Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, edge.axis); diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java index 6621b1a0e..d70ef3189 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java @@ -2,7 +2,6 @@ package com.simibubi.create.foundation.utility.outliner; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; -import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.MathHelper; @@ -29,8 +28,8 @@ public class ChasingAABBOutline extends AABBOutline { } @Override - public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { - renderBB(ms, buffer, interpolateBBs(prevBB, bb, AnimationTickHolder.getPartialTicks())); + public void render(MatrixStack ms, SuperRenderTypeBuffer buffer, float pt) { + renderBB(ms, buffer, interpolateBBs(prevBB, bb, pt)); } private static AxisAlignedBB interpolateBBs(AxisAlignedBB current, AxisAlignedBB target, float pt) { diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/LineOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/LineOutline.java index 1fcc82046..6085a76a6 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/LineOutline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/LineOutline.java @@ -2,7 +2,6 @@ package com.simibubi.create.foundation.utility.outliner; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; -import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3d; @@ -19,7 +18,7 @@ public class LineOutline extends Outline { } @Override - public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { + public void render(MatrixStack ms, SuperRenderTypeBuffer buffer, float pt) { renderCuboidLine(ms, buffer, start, end); } @@ -46,8 +45,7 @@ public class LineOutline extends Outline { } @Override - public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { - float pt = AnimationTickHolder.getPartialTicks(); + public void render(MatrixStack ms, SuperRenderTypeBuffer buffer, float pt) { float distanceToTarget = 1 - MathHelper.lerp(pt, prevProgress, progress); Vector3d start = end.add(this.start.subtract(end) .scale(distanceToTarget)); diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java index 94321a234..605d47dfa 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java @@ -31,7 +31,7 @@ public abstract class Outline { params = new OutlineParams(); } - public abstract void render(MatrixStack ms, SuperRenderTypeBuffer buffer); + public abstract void render(MatrixStack ms, SuperRenderTypeBuffer buffer, float pt); public void renderCuboidLine(MatrixStack ms, SuperRenderTypeBuffer buffer, Vector3d start, Vector3d end) { Vector3d diff = end.subtract(start); 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 7a2be9234..64ae8334f 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 @@ -10,7 +10,6 @@ import java.util.Set; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBox; -import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.outliner.LineOutline.EndChasingLineOutline; import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams; @@ -60,14 +59,14 @@ public class Outliner { public OutlineParams showAABB(Object slot, AxisAlignedBB bb, int ttl) { createAABBOutlineIfMissing(slot, bb); ChasingAABBOutline outline = getAndRefreshAABB(slot, ttl); - outline.prevBB = outline.targetBB = bb; + outline.prevBB = outline.targetBB = outline.bb = bb; return outline.getParams(); } public OutlineParams showAABB(Object slot, AxisAlignedBB bb) { createAABBOutlineIfMissing(slot, bb); ChasingAABBOutline outline = getAndRefreshAABB(slot); - outline.prevBB = outline.targetBB = bb; + outline.prevBB = outline.targetBB = outline.bb = bb; return outline.getParams(); } @@ -107,7 +106,7 @@ public class Outliner { // Utility private void createAABBOutlineIfMissing(Object slot, AxisAlignedBB bb) { - if (!outlines.containsKey(slot)) { + if (!outlines.containsKey(slot) || !(outlines.get(slot).outline instanceof AABBOutline)) { ChasingAABBOutline outline = new ChasingAABBOutline(bb); outlines.put(slot, new OutlineEntry(outline)); } @@ -146,7 +145,7 @@ public class Outliner { toClear.forEach(outlines::remove); } - public void renderOutlines(MatrixStack ms, SuperRenderTypeBuffer buffer) { + public void renderOutlines(MatrixStack ms, SuperRenderTypeBuffer buffer, float pt) { outlines.forEach((key, entry) -> { Outline outline = entry.getOutline(); outline.params.alpha = 1; @@ -156,13 +155,13 @@ public class Outliner { float fadeticks = OutlineEntry.fadeTicks; float lastAlpha = prevTicks >= 0 ? 1 : 1 + (prevTicks / fadeticks); float currentAlpha = 1 + (entry.ticksTillRemoval / fadeticks); - float alpha = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), lastAlpha, currentAlpha); + float alpha = MathHelper.lerp(pt, lastAlpha, currentAlpha); outline.params.alpha = alpha * alpha * alpha; if (outline.params.alpha < 1 / 8f) return; } - outline.render(ms, buffer); + outline.render(ms, buffer, pt); }); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java b/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java index 89d777546..cdc56e488 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java @@ -1,19 +1,13 @@ package com.simibubi.create.foundation.utility.placement; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.VecHelper; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; @@ -22,6 +16,12 @@ import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + @MethodsReturnNonnullByDefault public interface IPlacementHelper { @@ -46,11 +46,11 @@ public interface IPlacementHelper { * @return PlacementOffset.fail() if no valid offset could be found. * PlacementOffset.success(newPos) with newPos being the new position the block should be placed at */ - PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray); + PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray); - //overrides the default ghost state of the helper with the actual state of the held block item, this is used in PlacementHelpers and can be ignored in most cases - default PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray, ItemStack heldItem) { - PlacementOffset offset = getOffset(world, state, pos, ray); + //sets the offset's ghost state with the default state of the held block item, this is used in PlacementHelpers and can be ignored in most cases + default PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray, ItemStack heldItem) { + PlacementOffset offset = getOffset(player, world, state, pos, ray); if (heldItem.getItem() instanceof BlockItem) { BlockItem blockItem = (BlockItem) heldItem.getItem(); offset = offset.withGhostState(blockItem.getBlock().getDefaultState()); @@ -60,11 +60,10 @@ public interface IPlacementHelper { //only gets called when placementOffset is successful default void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) { - //IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), ray.getFace()); - displayGhost(offset); } + //RIP static void renderArrow(Vector3d center, Vector3d target, Direction arrowPlane) { renderArrow(center, target, arrowPlane, 1D); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementHelpers.java b/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementHelpers.java index 054379b70..3a5237ab8 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementHelpers.java +++ b/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementHelpers.java @@ -1,11 +1,5 @@ package com.simibubi.create.foundation.utility.placement; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.lwjgl.opengl.GL11; - import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.gui.AllGuiTextures; @@ -13,7 +7,6 @@ import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingAngle; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.client.MainWindow; import net.minecraft.client.Minecraft; @@ -32,6 +25,11 @@ import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; @Mod.EventBusSubscriber public class PlacementHelpers { @@ -106,7 +104,7 @@ public class PlacementHelpers { boolean atLeastOneMatch = false; for (IPlacementHelper h : filteredForState) { - PlacementOffset offset = h.getOffset(world, state, pos, ray, heldItem); + PlacementOffset offset = h.getOffset(mc.player, world, state, pos, ray, heldItem); if (offset.isSuccessful()) { h.renderAt(pos, state, ray, offset); diff --git a/src/main/java/com/simibubi/create/foundation/utility/placement/util/PoleHelper.java b/src/main/java/com/simibubi/create/foundation/utility/placement/util/PoleHelper.java index 3ef639d9d..4126f8cca 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/placement/util/PoleHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/placement/util/PoleHelper.java @@ -1,22 +1,24 @@ package com.simibubi.create.foundation.utility.placement.util; +import com.simibubi.create.content.curiosities.tools.ExtendoGripItem; +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.utility.placement.IPlacementHelper; +import com.simibubi.create.foundation.utility.placement.PlacementOffset; +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.block.BlockState; +import net.minecraft.entity.ai.attributes.ModifiableAttributeInstance; +import net.minecraft.state.Property; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeMod; + import java.util.List; import java.util.function.Function; import java.util.function.Predicate; -import com.simibubi.create.foundation.utility.VecHelper; -import com.simibubi.create.foundation.utility.placement.IPlacementHelper; -import com.simibubi.create.foundation.utility.placement.PlacementOffset; - -import mcp.MethodsReturnNonnullByDefault; -import net.minecraft.block.BlockState; -import net.minecraft.state.Property; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.vector.Vector3d; -import net.minecraft.world.World; - @MethodsReturnNonnullByDefault public abstract class PoleHelper> implements IPlacementHelper { @@ -55,10 +57,19 @@ public abstract class PoleHelper> implements IPlacementH } @Override - public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + public PlacementOffset getOffset(PlayerEntity player, World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { List directions = IPlacementHelper.orderedByDistance(pos, ray.getHitVec(), dir -> dir.getAxis() == axisFunction.apply(state)); for (Direction dir : directions) { + int range = AllConfigs.SERVER.curiosities.placementAssistRange.get(); + if (player != null) { + ModifiableAttributeInstance reach = player.getAttribute(ForgeMod.REACH_DISTANCE.get()); + if (reach != null && reach.hasModifier(ExtendoGripItem.singleRangeAttributeModifier)) + range += 4; + } int poles = attachedPoles(world, pos, dir); + if (poles >= range) + continue; + BlockPos newPos = pos.offset(dir, poles + 1); BlockState newState = world.getBlockState(newPos); @@ -69,12 +80,4 @@ public abstract class PoleHelper> implements IPlacementH return PlacementOffset.fail(); } - - @Override - public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) { - //Vector3d centerOffset = new Vector3d(ray.getFace().getDirectionVec()).scale(.3); - //IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos).add(centerOffset), VecHelper.getCenterOf(offset.getPos()).add(centerOffset), ray.getFace(), 0.75D); - - displayGhost(offset); - } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java index 8e8d71b3c..9e548cf46 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.function.Predicate; +import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.tileentity.TileEntity; @@ -13,7 +14,7 @@ import net.minecraft.util.math.SectionPos; import net.minecraft.world.World; import net.minecraft.world.lighting.WorldLightManager; -public class PlacementSimulationWorld extends WrappedWorld { +public class PlacementSimulationWorld extends WrappedWorld implements IFlywheelWorld { public HashMap blocksAdded; public HashMap tesAdded; diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java index 13755e9e8..83f8c3439 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java @@ -10,6 +10,8 @@ import javax.annotation.ParametersAreNonnullByDefault; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.client.multiplayer.ClientChunkProvider; +import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.fluid.Fluid; @@ -35,17 +37,17 @@ import net.minecraft.world.storage.MapData; public class WrappedWorld extends World { protected World world; - private WrappedChunkProvider provider; + private AbstractChunkProvider provider; - public WrappedWorld(World world, WrappedChunkProvider provider) { - this(world); + public WrappedWorld(World world, AbstractChunkProvider provider) { + super((ISpawnWorldInfo) world.getWorldInfo(), world.getRegistryKey(), world.getDimension(), world::getProfiler, + world.isRemote, world.isDebugWorld(), 0); + this.world = world; this.provider = provider; } public WrappedWorld(World world) { - super((ISpawnWorldInfo) world.getWorldInfo(), world.getRegistryKey(), world.getDimension(), world::getProfiler, - world.isRemote, world.isDebugWorld(), 0); - this.world = world; + this(world, null); } public World getWorld() { diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 07d93cb91..670ca6d94 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -51,4 +51,36 @@ public com.mojang.blaze3d.platform.GlStateManager$BooleanState field_179201_b #f public net.minecraft.client.renderer.GameRenderer func_215311_a(Lnet/minecraft/client/renderer/ActiveRenderInfo;FZ)D #getFOVModifier # IResizeCallback -public net.minecraft.util.palette.IResizeCallback \ No newline at end of file +public net.minecraft.util.palette.IResizeCallback + +# Entity +public net.minecraft.entity.Entity func_205011_p()V # updateAquatics +public net.minecraft.entity.Entity field_70122_E #onGround + +# For uploading matrices as vertex attributes. +public net.minecraft.util.math.vector.Matrix3f field_226097_a_ #a00 +public net.minecraft.util.math.vector.Matrix3f field_226098_b_ #a01 +public net.minecraft.util.math.vector.Matrix3f field_226099_c_ #a02 +public net.minecraft.util.math.vector.Matrix3f field_226100_d_ #a10 +public net.minecraft.util.math.vector.Matrix3f field_226101_e_ #a11 +public net.minecraft.util.math.vector.Matrix3f field_226102_f_ #a12 +public net.minecraft.util.math.vector.Matrix3f field_226103_g_ #a20 +public net.minecraft.util.math.vector.Matrix3f field_226104_h_ #a21 +public net.minecraft.util.math.vector.Matrix3f field_226105_i_ #a22 + +public net.minecraft.util.math.vector.Matrix4f field_226575_a_ #a00 +public net.minecraft.util.math.vector.Matrix4f field_226576_b_ #a01 +public net.minecraft.util.math.vector.Matrix4f field_226577_c_ #a02 +public net.minecraft.util.math.vector.Matrix4f field_226578_d_ #a03 +public net.minecraft.util.math.vector.Matrix4f field_226579_e_ #a10 +public net.minecraft.util.math.vector.Matrix4f field_226580_f_ #a11 +public net.minecraft.util.math.vector.Matrix4f field_226581_g_ #a12 +public net.minecraft.util.math.vector.Matrix4f field_226582_h_ #a13 +public net.minecraft.util.math.vector.Matrix4f field_226583_i_ #a20 +public net.minecraft.util.math.vector.Matrix4f field_226584_j_ #a21 +public net.minecraft.util.math.vector.Matrix4f field_226585_k_ #a22 +public net.minecraft.util.math.vector.Matrix4f field_226586_l_ #a23 +public net.minecraft.util.math.vector.Matrix4f field_226587_m_ #a30 +public net.minecraft.util.math.vector.Matrix4f field_226588_n_ #a31 +public net.minecraft.util.math.vector.Matrix4f field_226589_o_ #a32 +public net.minecraft.util.math.vector.Matrix4f field_226590_p_ #a33 diff --git a/src/main/resources/assets/create/flywheel/shaders/belt.vert b/src/main/resources/assets/create/flywheel/shaders/belt.vert new file mode 100644 index 000000000..08e776ef6 --- /dev/null +++ b/src/main/resources/assets/create/flywheel/shaders/belt.vert @@ -0,0 +1,87 @@ +#version 110 +#define PI 3.1415926538 + +#flwinclude <"create:core/quaternion.glsl"> +#flwinclude <"create:core/matutils.glsl"> +#flwinclude <"create:core/diffuse.glsl"> + +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +attribute vec3 aInstancePos; +attribute vec2 aLight; +attribute vec3 aNetworkTint; +attribute float aSpeed; +attribute float aOffset; +attribute vec4 aInstanceRot; +attribute vec2 aSourceTexture; +attribute vec4 aScrollTexture; +attribute float aScrollMult; + +varying vec2 TexCoords; +varying vec4 Color; +varying float Diffuse; +varying vec2 Light; + +#if defined(CONTRAPTION) +varying vec3 BoxCoord; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; +#endif + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; + +#if defined(USE_FOG) +varying float FragDistance; +#endif + +void main() { + vec3 rotated = rotateVertexByQuat(aPos - .5, aInstanceRot) + aInstancePos + .5; + + vec4 worldPos = vec4(rotated, 1.); + + vec3 norm = rotateVertexByQuat(aNormal, aInstanceRot); + +#ifdef CONTRAPTION + worldPos = uModel * worldPos; + norm = normalize(modelToNormal(uModel) * norm); + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + #if defined(USE_FOG) + FragDistance = length(worldPos.xyz); + #endif +#elif defined(USE_FOG) + FragDistance = length(worldPos.xyz - uCameraPos); +#endif + + float scrollSize = aScrollTexture.w - aScrollTexture.y; + float scroll = fract(aSpeed * uTime / (31.5 * 16.) + aOffset) * scrollSize * aScrollMult; + + Diffuse = diffuse(norm); + TexCoords = aTexCoords - aSourceTexture + aScrollTexture.xy + vec2(0, scroll); + Light = aLight; + gl_Position = uViewProjection * worldPos; + + #ifdef CONTRAPTION + if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } + #else + if (uDebug == 1) { + Color = vec4(aNetworkTint, 1.); + } else if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } + #endif +} diff --git a/src/main/resources/assets/create/shader/contraption.frag b/src/main/resources/assets/create/flywheel/shaders/contraption.frag similarity index 60% rename from src/main/resources/assets/create/shader/contraption.frag rename to src/main/resources/assets/create/flywheel/shaders/contraption.frag index 5d90b40ff..9049221f1 100644 --- a/src/main/resources/assets/create/shader/contraption.frag +++ b/src/main/resources/assets/create/flywheel/shaders/contraption.frag @@ -4,17 +4,35 @@ varying vec2 TexCoords; varying vec4 Color; varying float Diffuse; varying vec2 Light; -varying float FragDistance; varying vec3 BoxCoord; -uniform vec2 uFogRange; -uniform vec4 uFogColor; - uniform sampler2D uBlockAtlas; uniform sampler2D uLightMap; uniform sampler3D uLightVolume; +#if defined(USE_FOG) +varying float FragDistance; +uniform vec4 uFogColor; +#endif + +#if defined(USE_FOG_LINEAR) +uniform vec2 uFogRange; + +float fogFactor() { + return (uFogRange.y - FragDistance) / (uFogRange.y - uFogRange.x); +} +#endif + +#ifdef USE_FOG_EXP2 +uniform float uFogDensity; + +float fogFactor() { + float dist = FragDistance * uFogDensity; + return 1. / exp2(dist * dist); +} +#endif + vec4 light() { vec2 lm = texture3D(uLightVolume, BoxCoord).rg * 0.9375 + 0.03125; return texture2D(uLightMap, max(lm, Light)); @@ -25,9 +43,12 @@ void main() { vec4 color = vec4(tex.rgb * light().rgb * Diffuse * Color.rgb, tex.a); - float fog = (uFogRange.y - FragDistance) / (uFogRange.y - uFogRange.x); - fog = clamp(fog, 0., 1.); +#if defined(USE_FOG) + float fog = clamp(fogFactor(), 0., 1.); gl_FragColor = mix(uFogColor, color, fog); gl_FragColor.a = color.a; +#else + gl_FragColor = color; +#endif } \ No newline at end of file diff --git a/src/main/resources/assets/create/flywheel/shaders/contraption_actor.vert b/src/main/resources/assets/create/flywheel/shaders/contraption_actor.vert new file mode 100644 index 000000000..b58a4df0e --- /dev/null +++ b/src/main/resources/assets/create/flywheel/shaders/contraption_actor.vert @@ -0,0 +1,71 @@ +#version 110 +#define PI 3.1415926538 + +#flwinclude <"create:core/matutils.glsl"> +#flwinclude <"create:core/quaternion.glsl"> +#flwinclude <"create:core/diffuse.glsl"> + +// model data +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +// instance data +attribute vec3 aInstancePos; +attribute vec2 aModelLight; +attribute float aOffset; +attribute vec3 aAxis; +attribute vec4 aInstanceRot; +attribute vec3 aRotationCenter; +attribute float aSpeed; + + +varying float Diffuse; +varying vec2 TexCoords; +varying vec4 Color; +varying vec3 BoxCoord; +varying vec2 Light; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; + +#if defined(USE_FOG) +varying float FragDistance; +#endif + +void main() { + float degrees = aOffset + uTime * aSpeed / 20.; + //float angle = fract(degrees / 360.) * PI * 2.; + + vec4 kineticRot = quat(aAxis, degrees); + vec3 rotated = rotateVertexByQuat(aPos - aRotationCenter, kineticRot) + aRotationCenter; + vec3 localPos = rotateVertexByQuat(rotated - .5, aInstanceRot) + aInstancePos + .5; + + vec4 worldPos = uModel * vec4(localPos, 1.); + + vec3 norm = rotateVertexByQuat(rotateVertexByQuat(aNormal, kineticRot), aInstanceRot); + norm = modelToNormal(uModel) * norm; + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + Diffuse = diffuse(norm); + TexCoords = aTexCoords; + Light = aModelLight; + gl_Position = uViewProjection * worldPos; + + #if defined(USE_FOG) + FragDistance = length(worldPos.xyz); + #endif + + if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/shader/contraption_structure.vert b/src/main/resources/assets/create/flywheel/shaders/contraption_structure.vert similarity index 54% rename from src/main/resources/assets/create/shader/contraption_structure.vert rename to src/main/resources/assets/create/flywheel/shaders/contraption_structure.vert index a665ea8ff..dbcf4a595 100644 --- a/src/main/resources/assets/create/shader/contraption_structure.vert +++ b/src/main/resources/assets/create/flywheel/shaders/contraption_structure.vert @@ -1,6 +1,9 @@ #version 110 #define PI 3.1415926538 +#flwinclude <"create:core/matutils.glsl"> +#flwinclude <"create:core/diffuse.glsl"> + attribute vec3 aPos; attribute vec3 aNormal; attribute vec2 aTexCoords; @@ -22,25 +25,10 @@ uniform mat4 uViewProjection; uniform int uDebug; uniform vec3 uCameraPos; + +#if defined(USE_FOG) varying float FragDistance; - -mat4 rotate(vec3 axis, float angle) { - float s = sin(angle); - float c = cos(angle); - float oc = 1. - c; - - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., - 0., 0., 0., 1.); -} - -float diffuse(vec3 normal) { - float x = normal.x; - float y = normal.y; - float z = normal.z; - return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.); -} +#endif void main() { vec4 viewPos = uModel * vec4(aPos, 1.); @@ -52,8 +40,10 @@ void main() { Color = aColor / diffuse(aNormal); TexCoords = aTexCoords; Light = aModelLight; - FragDistance = length(viewPos.xyz); gl_Position = uViewProjection * viewPos; + #if defined(USE_FOG) + FragDistance = length(viewPos.xyz); + #endif if (uDebug == 2) { Color = vec4(norm, 1.); diff --git a/src/main/resources/assets/create/flywheel/shaders/core/diffuse.glsl b/src/main/resources/assets/create/flywheel/shaders/core/diffuse.glsl new file mode 100644 index 000000000..bc5792231 --- /dev/null +++ b/src/main/resources/assets/create/flywheel/shaders/core/diffuse.glsl @@ -0,0 +1,5 @@ + +float diffuse(vec3 normal) { + vec3 n2 = normal * normal * vec3(.6, .25, .8); + return min(n2.x + n2.y * (3. + normal.y) + n2.z, 1.); +} diff --git a/src/main/resources/assets/create/flywheel/shaders/core/matutils.glsl b/src/main/resources/assets/create/flywheel/shaders/core/matutils.glsl new file mode 100644 index 000000000..f7c846e71 --- /dev/null +++ b/src/main/resources/assets/create/flywheel/shaders/core/matutils.glsl @@ -0,0 +1,42 @@ + +//mat4 rotate(vec3 axis, float angle) { +// float s = sin(angle); +// float c = cos(angle); +// float oc = 1. - c; +// +// return mat4( +// oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., +// oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., +// oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., +// 0., 0., 0., 1. +// ); +//} + +mat4 rotate(vec3 axis, float angle) { + float s = sin(angle); + float c = cos(angle); + float oc = 1. - c; + + vec3 sa = axis * s; + + mat4 mr = mat4(1.); + mr[0].xyz = oc * axis.xxz * axis.xyx + vec3(c, sa.z, -sa.y); + mr[1].xyz = oc * axis.xyy * axis.yyz + vec3(-sa.z, c, sa.x); + mr[2].xyz = oc * axis.zyz * axis.xzz + vec3(sa.y, -sa.x, c); + + return mr; +} + +mat4 rotation(vec3 rot) { + return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x); +} + +mat3 modelToNormal(mat4 mat) { + // Discard the edges. This won't be accurate for scaled or skewed matrices, + // but we don't have to work with those often. + mat3 m; + m[0] = mat[0].xyz; + m[1] = mat[1].xyz; + m[2] = mat[2].xyz; + return m; +} \ No newline at end of file diff --git a/src/main/resources/assets/create/flywheel/shaders/core/quaternion.glsl b/src/main/resources/assets/create/flywheel/shaders/core/quaternion.glsl new file mode 100644 index 000000000..cbfff38ee --- /dev/null +++ b/src/main/resources/assets/create/flywheel/shaders/core/quaternion.glsl @@ -0,0 +1,56 @@ + +#define PIOVER2 1.5707963268 + +vec4 quat(vec3 axis, float angle) { + float halfAngle = angle * PIOVER2 / 180.0; + vec2 cs = sin(vec2(PIOVER2 - halfAngle, halfAngle)); // compute sin and cos in one instruction + return vec4(axis.xyz * cs.y, cs.x); +} + +vec4 quatMult(vec4 q1, vec4 q2) { + // disgustingly vectorized quaternion multiplication + vec4 a = q1.w * q2.xyzw; + vec4 b = q1.x * q2.wzxy * vec4(1., -1., 1., -1.); + vec4 c = q1.y * q2.zwxy * vec4(1., 1., -1., -1.); + vec4 d = q1.z * q2.yxwz * vec4(-1., 1., 1., -1.); + + return a + b + c + d; +} +// +//vec4 exp(vec4 q) { +// vec3 i = q.xyz; +// float r = sqrt(dot(i, i)); +// float et = exp(q.w); +// float s = et * sin(r) / r; +// +// vec4 qr; +// qr.w = et * cos(r); +// qr.xyz = i * s; +// +// return qr; +//} +// +//vec4 ln(vec4 q) { +// vec3 i = q.xyz; +// float r = sqrt(dot(i, i)); +// float t = atan(r, q.w) / r; +// +// vec4 qr; +// qr.w = log(dot(q, q)) * 0.5; +// qr.xyz = i * t; +// +// return qr; +//} +// +//vec4 pow(vec4 q, float n) { +// return exp(ln(q) * n); +//} + +vec3 rotateVertexByQuat(vec3 v, vec4 q) { + vec3 i = q.xyz; + return v + 2.0 * cross(i, cross(i, v) + q.w * v); +} + +vec3 rotateAbout(vec3 v, vec3 axis, float angle) { + return rotateVertexByQuat(v, quat(axis, angle)); +} \ No newline at end of file diff --git a/src/main/resources/assets/create/flywheel/shaders/flap.vert b/src/main/resources/assets/create/flywheel/shaders/flap.vert new file mode 100644 index 000000000..496051288 --- /dev/null +++ b/src/main/resources/assets/create/flywheel/shaders/flap.vert @@ -0,0 +1,94 @@ +#version 110 +#define PI 3.1415926538 + +#flwinclude <"create:core/matutils.glsl"> +#flwinclude <"create:core/quaternion.glsl"> +#flwinclude <"create:core/diffuse.glsl"> + +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +attribute vec3 aInstancePos; +attribute vec2 aLight; + +attribute vec3 aSegmentOffset; +attribute vec3 aPivot; +attribute float aHorizontalAngle; +attribute float aIntensity; +attribute float aFlapScale; + +attribute float aFlapness; + +// outputs +varying vec2 TexCoords; +varying vec4 Color; +varying float Diffuse; +varying vec2 Light; + +#if defined(CONTRAPTION) +varying vec3 BoxCoord; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; +#endif + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; + +#if defined(USE_FOG) +varying float FragDistance; +#endif + +float toRad(float degrees) { + return fract(degrees / 360.) * PI * 2.; +} + +float getFlapAngle() { + float absFlap = abs(aFlapness); + + float angle = sin((1. - absFlap) * PI * aIntensity) * 30. * aFlapness * aFlapScale; + + float halfAngle = angle * 0.5; + + float which = step(0., aFlapness); + float degrees = which * halfAngle + (1. - which) * angle; // branchless conditional multiply + + return degrees; +} + +void main() { + float flapAngle = getFlapAngle(); + + vec4 orientation = quat(vec3(0., 1., 0.), -aHorizontalAngle); + vec4 flapRotation = quat(vec3(1., 0., 0.), flapAngle); + + vec3 rotated = rotateVertexByQuat(aPos - aPivot, flapRotation) + aPivot + aSegmentOffset; + rotated = rotateVertexByQuat(rotated - .5, orientation) + aInstancePos + .5; + + vec4 worldPos = vec4(rotated, 1.); + vec3 norm = rotateVertexByQuat(rotateVertexByQuat(aNormal, flapRotation), orientation); + + #ifdef CONTRAPTION + worldPos = uModel * worldPos; + norm = modelToNormal(uModel) * norm; + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + #if defined(USE_FOG) + FragDistance = length(worldPos.xyz); + #endif + #elif defined(USE_FOG) + FragDistance = length(worldPos.xyz - uCameraPos); + #endif + + Diffuse = diffuse(norm); + TexCoords = aTexCoords; + Light = aLight; + gl_Position = uViewProjection * worldPos; + + Color = vec4(1.); +} diff --git a/src/main/resources/assets/create/shader/instanced.frag b/src/main/resources/assets/create/flywheel/shaders/model.frag similarity index 56% rename from src/main/resources/assets/create/shader/instanced.frag rename to src/main/resources/assets/create/flywheel/shaders/model.frag index cb85241f5..e8ffaa00c 100644 --- a/src/main/resources/assets/create/shader/instanced.frag +++ b/src/main/resources/assets/create/flywheel/shaders/model.frag @@ -4,14 +4,32 @@ varying vec2 TexCoords; varying vec2 Light; varying float Diffuse; varying vec4 Color; -varying float FragDistance; - -uniform vec2 uFogRange; -uniform vec4 uFogColor; uniform sampler2D uBlockAtlas; uniform sampler2D uLightMap; +#if defined(USE_FOG) +varying float FragDistance; +uniform vec4 uFogColor; +#endif + +#if defined(USE_FOG_LINEAR) +uniform vec2 uFogRange; + +float fogFactor() { + return (uFogRange.y - FragDistance) / (uFogRange.y - uFogRange.x); +} +#endif + +#ifdef USE_FOG_EXP2 +uniform float uFogDensity; + +float fogFactor() { + float dist = FragDistance * uFogDensity; + return 1. / exp2(dist * dist); +} +#endif + vec4 light() { vec2 lm = Light * 0.9375 + 0.03125; return texture2D(uLightMap, lm); @@ -22,9 +40,12 @@ void main() { vec4 color = vec4(tex.rgb * light().rgb * Diffuse, tex.a) * Color; - float fog = (uFogRange.y - FragDistance) / (uFogRange.y - uFogRange.x); - fog = clamp(fog, 0., 1.); +#if defined(USE_FOG) + float fog = clamp(fogFactor(), 0., 1.); gl_FragColor = mix(uFogColor, color, fog); gl_FragColor.a = color.a; +#else + gl_FragColor = color; +#endif } \ No newline at end of file diff --git a/src/main/resources/assets/create/flywheel/shaders/model.vert b/src/main/resources/assets/create/flywheel/shaders/model.vert new file mode 100644 index 000000000..9767a122c --- /dev/null +++ b/src/main/resources/assets/create/flywheel/shaders/model.vert @@ -0,0 +1,63 @@ +#version 110 + +#flwinclude <"create:core/matutils.glsl"> +#flwinclude <"create:core/diffuse.glsl"> + +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +attribute mat4 aTransform; +attribute mat3 aNormalMat; +attribute vec2 aLight; +attribute vec4 aColor; + +varying vec2 TexCoords; +varying vec4 Color; +varying float Diffuse; +varying vec2 Light; + +#if defined(CONTRAPTION) +varying vec3 BoxCoord; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; +#endif + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; + +#if defined(USE_FOG) +varying float FragDistance; +#endif + +void main() { + vec4 worldPos = aTransform * vec4(aPos, 1.); + + mat3 normalMat = aNormalMat; + +#ifdef CONTRAPTION + worldPos = uModel * worldPos; + normalMat *= modelToNormal(uModel); + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + #if defined(USE_FOG) + FragDistance = length(worldPos.xyz); + #endif +#elif defined(USE_FOG) + FragDistance = length(worldPos.xyz - uCameraPos); +#endif + + vec3 norm = normalize(normalMat * aNormal); + + Diffuse = diffuse(norm); + TexCoords = aTexCoords; + Light = aLight; + gl_Position = uViewProjection * worldPos; + + Color = aColor; +} \ No newline at end of file diff --git a/src/main/resources/assets/create/flywheel/shaders/rotating.vert b/src/main/resources/assets/create/flywheel/shaders/rotating.vert new file mode 100644 index 000000000..53d258bfd --- /dev/null +++ b/src/main/resources/assets/create/flywheel/shaders/rotating.vert @@ -0,0 +1,82 @@ +#version 110 +#define PI 3.1415926538 + +#flwinclude <"create:core/quaternion.glsl"> +#flwinclude <"create:core/matutils.glsl"> +#flwinclude <"create:core/diffuse.glsl"> + +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +attribute vec3 aInstancePos; +attribute vec2 aLight; +attribute vec3 aNetworkTint; +attribute float aSpeed; +attribute float aOffset; +attribute vec3 aAxis; + +varying vec2 TexCoords; +varying vec4 Color; +varying float Diffuse; +varying vec2 Light; + +#if defined(CONTRAPTION) +varying vec3 BoxCoord; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; +#endif + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; + +#if defined(USE_FOG) +varying float FragDistance; +#endif + +void main() { + float degrees = aOffset + uTime * aSpeed * 3./10.; + vec4 kineticRot = quat(aAxis, degrees); + + vec4 worldPos = vec4(rotateVertexByQuat(aPos - .5, kineticRot) + aInstancePos + .5, 1.); + + vec3 norm = rotateVertexByQuat(aNormal, kineticRot); + + #ifdef CONTRAPTION + worldPos = uModel * worldPos; + norm = modelToNormal(uModel) * norm; + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + #if defined(USE_FOG) + FragDistance = length(worldPos.xyz); + #endif + #elif defined(USE_FOG) + FragDistance = length(worldPos.xyz - uCameraPos); + #endif + + Diffuse = diffuse(norm); + TexCoords = aTexCoords; + Light = aLight; + gl_Position = uViewProjection * worldPos; + + #ifdef CONTRAPTION + if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } + #else + if (uDebug == 1) { + Color = vec4(aNetworkTint, 1.); + } else if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } + #endif +} \ No newline at end of file diff --git a/src/main/resources/assets/create/lang/default/messages.json b/src/main/resources/assets/create/lang/default/messages.json index deb8aed43..37ee82398 100644 --- a/src/main/resources/assets/create/lang/default/messages.json +++ b/src/main/resources/assets/create/lang/default/messages.json @@ -172,13 +172,16 @@ "create.gui.goggles.kinetic_stats": "Kinetic Stats:", "create.gui.goggles.at_current_speed": "at current speed", "create.gui.goggles.pole_length": "Pole Length:", + "create.gui.goggles.fluid_container": "Fluid Container Info:", + "create.gui.goggles.fluid_container.capacity": "Capacity: ", "create.gui.assembly.exception": "This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "Unmovable Block (%4$s) at [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.unmovableBlock": "Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.structureTooLarge": "There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "The Piston is missing some extension Poles", + "create.gui.assembly.exception.not_enough_sails": "Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.gauge.info_header": "Gauge Information:", "create.gui.speedometer.title": "Rotation Speed", diff --git a/src/main/resources/assets/create/lang/default/tooltips.json b/src/main/resources/assets/create/lang/default/tooltips.json index b4baad170..b674155b4 100644 --- a/src/main/resources/assets/create/lang/default/tooltips.json +++ b/src/main/resources/assets/create/lang/default/tooltips.json @@ -301,6 +301,8 @@ "item.create.goggles.tooltip.behaviour1": "Shows _colored indicators_ corresponding to the _Speed Level_ of a placed kinetic component as well as _Stress Impact_ and _Capacity_ of individual components.", "item.create.goggles.tooltip.condition2": "When looking at gauge", "item.create.goggles.tooltip.behaviour2": "Shows detailed information about _Speed_ or _Stress_ of the network to which the gauge is connected.", + "item.create.goggles.tooltip.condition3": "When looking at fluid containers", + "item.create.goggles.tooltip.behaviour3": "Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", "item.create.wrench.tooltip": "WRENCH", "item.create.wrench.tooltip.summary": "A useful tool for working on kinetic contraptions. Can be used to _Rotate_, _Dismantle_ and to _Configure_ components.", diff --git a/src/main/resources/assets/create/lang/es_es.json b/src/main/resources/assets/create/lang/es_es.json index 787422bb8..c8e41ac46 100644 --- a/src/main/resources/assets/create/lang/es_es.json +++ b/src/main/resources/assets/create/lang/es_es.json @@ -107,7 +107,7 @@ "block.create.dolomite_pillar": "Pilar de dolomita", "block.create.encased_chain_drive": "Cadena de transmisión revestida", "block.create.encased_fan": "Ventilador revestido", - "block.create.encased_fluid_pipe": "Tubería de fluidos de cobre revestida", + "block.create.encased_fluid_pipe": "Tubería de fluidos de cobre reforzada", "block.create.fancy_andesite_bricks": "Ladrillos de andesita elegantes", "block.create.fancy_andesite_bricks_slab": "Ladrillos de andesita elegantes", "block.create.fancy_andesite_bricks_stairs": "Escaleras de ladrillos de andesita elegantes", @@ -165,7 +165,7 @@ "block.create.gantry_shaft": "Eje de grúa", "block.create.gearbox": "Caja de transmisión", "block.create.gearshift": "Caja de cambios", - "block.create.glass_fluid_pipe": "Tubo de cristal para fluidos", + "block.create.glass_fluid_pipe": "Tubería de fluidos de cristal", "block.create.granite_bricks": "Ladrillos de granito", "block.create.granite_bricks_slab": "Losa de ladrillos de granito", "block.create.granite_bricks_stairs": "Escaleras de ladrillos de granito", @@ -349,7 +349,7 @@ "block.create.redstone_link": "Enlace de Redstone", "block.create.refined_radiance_casing": "Revestidor de radiante", "block.create.reinforced_rail": "Raíl reforzado", - "block.create.rope": "Soga", + "block.create.rope": "Cuerda", "block.create.rope_pulley": "Polea de cuerda", "block.create.rotation_speed_controller": "Controlador de velocidad de rotación", "block.create.sail_frame": "Marco de vela", @@ -506,7 +506,7 @@ "advancement.create.splitter_tunnel": "Divide y vencerás", "advancement.create.splitter_tunnel.desc": "Crear un divisor con un grupo de túneles de latón.", "advancement.create.chute": "Caída en picado", - "advancement.create.chute.desc": "Coloque un ducto, la contrapartida vertical de la correa.", + "advancement.create.chute.desc": "Coloque un ducto, la contrapartida vertical de la cinta.", "advancement.create.upward_chute": "Abducción aérea", "advancement.create.upward_chute.desc": "Observe cómo un objeto lanzado vuela hacia un paracaídas impulsado por un ventilador.", "advancement.create.belt_funnel": "Colgantes con forma de embudo", @@ -532,7 +532,7 @@ "advancement.create.aesthetics": "Boom, Estética!", "advancement.create.aesthetics.desc": "Colocar los soportes en un eje, tubo y rueda dentada.", "advancement.create.reinforced": "Boom, Reforzado!", - "advancement.create.reinforced.desc": "Utilizar bloques de revestimiento en un eje, un tubo y una correa.", + "advancement.create.reinforced.desc": "Utilizar bloques de revestimiento en un eje, un tubo y una cinta.", "advancement.create.water_wheel": "Aprovechar la hidráulica", "advancement.create.water_wheel.desc": "Coloca una Rueda hidráulica e intenta hacerla girar.", "advancement.create.chocolate_wheel": "Potencia de buen gusto", @@ -684,6 +684,7 @@ "create.recipe.mechanical_crafting": "Elaboración mecánica", "create.recipe.automatic_shaped": "Elaboración automatizada de productos con forma", "create.recipe.block_cutting": "Corte de bloques", + "create.recipe.wood_cutting": "Corte de maderas", "create.recipe.blockzapper_upgrade": "Blockzapper", "create.recipe.sandpaper_polishing": "Pulido con papel de lija", "create.recipe.mystery_conversion": "Conversión misteriosa", @@ -823,11 +824,12 @@ "create.gui.goggles.at_current_speed": "con la velocidad actual", "create.gui.goggles.pole_length": "Longitud del poste:", "create.gui.assembly.exception": "Este artilugio no se pudo montar:", - "create.gui.assembly.exception.unmovableBlock": "Bloque inamovible (%4$s) en [%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "El bloque en [%1$s %2$s %3$s] no estaba en un chunk cargado", + "create.gui.assembly.exception.unmovableBlock": "Bloque inamovible (%4$s) en [%1$s,%2$s,%3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "El bloque en [%1$s,%2$s,%3$s] no estaba en un chunk cargado", "create.gui.assembly.exception.structureTooLarge": "Hay demasiados bloques incluídos en el artilugio.\nEl máximo configurado es: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "Hay demasiadas Pértigas de extensión conectadas a este Pistón.\nEl máximo configurado es: %1$s", "create.gui.assembly.exception.noPistonPoles": "Faltan pértigas de extensión para el Pistón", + "create.gui.assembly.exception.not_enough_sails": "La estructura adjunta no incluye suficientes bloques tipo vela: %1$s\nSe requiere un mínimo de %2$s", "create.gui.gauge.info_header": "Información sobre el medidor:", "create.gui.speedometer.title": "Velocidad de rotación", "create.gui.stressometer.title": "Estrés de la red", @@ -844,13 +846,19 @@ "create.gui.stockpile_switch.move_to_upper_at": "Pasar al carril superior en %1$s%%", "create.gui.sequenced_gearshift.title": "Cambio de marchas secuenciado", "create.gui.sequenced_gearshift.instruction": "Instrucción", + "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Giro por ángulo", "create.gui.sequenced_gearshift.instruction.turn_angle": "Giro", "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Ángulo", + "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Giro para mover el pistón/polea/grúa", "create.gui.sequenced_gearshift.instruction.turn_distance": "Pistón", "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distancia", - "create.gui.sequenced_gearshift.instruction.wait": "Espera", - "create.gui.sequenced_gearshift.instruction.wait.duration": "Duración", + "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Tiempo de retraso", + "create.gui.sequenced_gearshift.instruction.delay": "Retraso", + "create.gui.sequenced_gearshift.instruction.delay.duration": "Duración", + "create.gui.sequenced_gearshift.instruction.end.descriptive": "Fin", "create.gui.sequenced_gearshift.instruction.end": "Fin", + "create.gui.sequenced_gearshift.instruction.await.descriptive": "En espera de un Pulso de Redstone", + "create.gui.sequenced_gearshift.instruction.await": "En espera", "create.gui.sequenced_gearshift.speed": "Velocidad, Dirección", "create.gui.sequenced_gearshift.speed.forward": "Velocidad de entrada, hacia adelante", "create.gui.sequenced_gearshift.speed.forward_fast": "Doble velocidad, hacia adelante", @@ -1159,19 +1167,19 @@ "block.create.metal_bracket.tooltip.summary": "Decora tus _Ejes_, _Ruedas dentadas_ y _Ductos_ con un poco de refuerzo industrial robusto.", "block.create.andesite_casing.tooltip": "REVESTIDOR DE ANDESITA", - "block.create.andesite_casing.tooltip.summary": "Máquina de revestimiento simple con una variedad de usos. Seguro para la decoración. Puede utilizarse para _encastrar ejes_ y _correas._", + "block.create.andesite_casing.tooltip.summary": "Máquina de revestimiento simple con una variedad de usos. Seguro para la decoración. Puede utilizarse para _revestir ejes_ y _cintas._", "block.create.andesite_funnel.tooltip": "EMBUDO DE ANDESITA", "block.create.andesite_funnel.tooltip.summary": "Un componente de transferencia de elementos en general, que hace la transición de éstos entre los medios de transporte. Se puede controlar con una _señal de Redstone_.", "block.create.andesite_funnel.tooltip.condition1": "Comportamiento general", "block.create.andesite_funnel.tooltip.behaviour1": "La cara _abierta_ _recogerá los objetos molidos_ en el espacio del bloque que tiene delante y los _insertará_ en cualquier contenedor del lado opuesto del embudo", - "block.create.andesite_funnel.tooltip.condition2": "Cuando se montan en correas, depósitos y similares", + "block.create.andesite_funnel.tooltip.condition2": "Cuando se montan en cintas, depósitos y similares", "block.create.andesite_funnel.tooltip.behaviour2": "_Recoge_ o _Coloca_ los elementos en el componente montado, desde o hacia el inventario _detrás_ de sí mismo. Siempre que el embudo tenga una direccionalidad específica, puede invertirse utilizando una Llave.", "block.create.andesite_funnel.tooltip.condition3": "Cuando se encuentra verticalmente entre dos inventarios", "block.create.andesite_funnel.tooltip.behaviour3": "Transferirá los artículos hacia abajo, como una tolva sin búfer.", "block.create.andesite_tunnel.tooltip": "TÚNEL DE ANDESITA", - "block.create.andesite_tunnel.tooltip.summary": "¡Una cubierta protectora para sus _correas_!. El _Túnel de Andesita_ puede separar un elemento de una pila cuando se coloca otra correa o depósito al lado de la correa principal.", + "block.create.andesite_tunnel.tooltip.summary": "¡Una cubierta protectora para sus _cintas_!. El _Túnel de Andesita_ puede separar un elemento de una pila cuando se coloca otra cinta o depósito al lado de la cinta principal.", "block.create.andesite_tunnel.tooltip.control1": "Click derecho con la Llave Inglesa en el lateral", "block.create.andesite_tunnel.tooltip.action1": "_Ajusta las persianas de las ventanas_ si el túnel tiene una ventana en esa cara.", @@ -1179,15 +1187,15 @@ "block.create.brass_funnel.tooltip.summary": "Un componente de transferencia de elementos en general, que hace la transición de éstos entre los medios de transporte. Se puede controlar con una _señal de Redstone_. Viene con un práctico _filtro_.", "block.create.brass_funnel.tooltip.condition1": "Comportamiento General", "block.create.brass_funnel.tooltip.behaviour1": "La cara _abierta_ _recogerá los objetos molidos_ en el espacio del bloque que tiene delante y los _insertará_ en cualquier contenedor del lado opuesto del embudo.", - "block.create.brass_funnel.tooltip.condition2": "Cuando se montan en correas, depósitos y similares", + "block.create.brass_funnel.tooltip.condition2": "Cuando se montan en cintas, depósitos y similares", "block.create.brass_funnel.tooltip.behaviour2": "_Recoge_ o _Coloca_ los elementos en el componente montado, desde o hacia el inventario _detrás_ de sí mismo. Siempre que el embudo tenga una direccionalidad específica, puede invertirse utilizando una Llave Inglesa.", "block.create.brass_funnel.tooltip.condition3": "Cuando se encuentra verticalmente entre dos inventarios", "block.create.brass_funnel.tooltip.behaviour3": "Transfiere los artículos hacia abajo, como una tolva sin búfer.", "block.create.brass_tunnel.tooltip": "TÚNEL DE LATÓN", - "block.create.brass_tunnel.tooltip.summary": "Una cubierta protectora elegante para sus _correas_. Los _Túneles de latón_ también vienen con una serie de opciones de _Filtración_ y _División_ para sus artículos.", + "block.create.brass_tunnel.tooltip.summary": "Una cubierta protectora elegante para sus _cintas_. Los _Túneles de latón_ también vienen con una serie de opciones de _Filtración_ y _División_ para sus artículos.", "block.create.brass_tunnel.tooltip.condition1": "Cuando se colocan uno al lado del otro", - "block.create.brass_tunnel.tooltip.behaviour1": "Los túneles de latón se conectan entre sí y permiten redirigir el contenido de una correa a otra.", + "block.create.brass_tunnel.tooltip.behaviour1": "Los túneles de latón se conectan entre sí y permiten redirigir el contenido de una cinta a otra.", "block.create.brass_tunnel.tooltip.condition2": "Filtrado", "block.create.brass_tunnel.tooltip.behaviour2": "Los _Túneles de latón_ vienen con filtros tanto para la _Entrada_ como para la _Salida_. Si un _Elemento_ no está permitido desde la salida filtrada de un _Túnel_ será transferido a la salida de un _Túnel_ conectado.", "block.create.brass_tunnel.tooltip.condition3": "Dividiendo", @@ -1202,8 +1210,8 @@ "block.create.copper_casing.tooltip.condition1": "Cuando se utiliza en una tubería de fluidos", "block.create.copper_casing.tooltip.behaviour1": "_Reviste_ la _Tubería de fluidos_ con _Revestimiento de cobre_. Las tuberías de fluidos revestidas _bloquean sus conexiones_ en su lugar, dejando de reaccionar a los cambios en las tuberías vecinas.", - "block.create.encased_fluid_pipe.tooltip": "TUBO DE FLUIDOS REVESTIDO", - "block.create.encased_fluid_pipe.tooltip.summary": "Un tubo de fluidos revestido con cobre.", + "block.create.encased_fluid_pipe.tooltip": "TUBO DE FLUIDOS REFORZADO", + "block.create.encased_fluid_pipe.tooltip.summary": "Un tubo de fluidos reforzado con más cobre.", "block.create.copper_valve_handle.tooltip": "ASA DE VÁLVULA DE COBRE", "block.create.copper_valve_handle.tooltip.summary": "Una precisa _fuente_ de _fuerza de rotación_ que requiere la interacción de los jugadores. ¡Ten cuidado de no agotarte!", @@ -1218,12 +1226,12 @@ "block.create.chute.tooltip": "DUCTO", "block.create.chute.tooltip.summary": "_Recoge_ y _Transporta_ elementos en vertical o en diagonal. Puede tanto coger como colocar objetos en _contenedores de objetos_. También puede interactuar con los ductos desde el lateral utilizando _tolvas_ o _embudos montados_.", "block.create.chute.tooltip.condition1": "Cuando se alimenta con un ventilador", - "block.create.chute.tooltip.behaviour1": "Los ductos accionados por ventilador pueden transportar _elementos_ hacia arriba, y aspirar _elementos_ de los _depósitos_ y de las _correas_.", + "block.create.chute.tooltip.behaviour1": "Los ductos accionados por ventilador pueden transportar _elementos_ hacia arriba, y aspirar _elementos_ de los _depósitos_ y de las _cintas_.", "block.create.depot.tooltip": "DEPÓSITO", "block.create.depot.tooltip.summary": "Un lugar práctico para colocar sus _elementos_. Proporciona un punto de interacción para varias máquinas", "block.create.depot.tooltip.condition1": "Click derecho en el depósito", - "block.create.depot.tooltip.behaviour1": "Coloca o toma un _Elemento_ del _Depósito_. Los _Bloques_ y los _Artilugios_ que interactúan con una _Correa_ también funcionan en un _Depósito_.", + "block.create.depot.tooltip.behaviour1": "Coloca o toma un _Elemento_ del _Depósito_. Los _Bloques_ y los _Artilugios_ que interactúan con una _cinta_ también funcionan en un _Depósito_.", "item.create.blaze_cake.tooltip": "PASTEL DE BLAZE", "item.create.blaze_cake.tooltip.summary": "Un delicioso regalo para sus esforzados _Quemadores de blaze_. Los pone en marcha!.", @@ -1285,7 +1293,7 @@ "block.create.spout.tooltip.condition1": "Transferencia de fluidos", "block.create.spout.tooltip.behaviour1": "Cuando se coloca un _contenedor de fluidos_ como un _cubo_ o una _botella_ debajo, el caño intentará rellenarlo con su propio _fluido_ almacenado", "block.create.spout.tooltip.condition2": "Automatización de fluidos", - "block.create.spout.tooltip.behaviour2": "El caño colocado encima de una _correa_ o _depósito_ reaccionará automáticamente con un contenedor de fluidos_ que pase por debajo", + "block.create.spout.tooltip.behaviour2": "El caño colocado encima de una _cinta_ o _depósito_ reaccionará automáticamente con un contenedor de fluidos_ que pase por debajo", "block.create.item_drain.tooltip": "DRENADOR DE ELEMENTOS", "block.create.item_drain.tooltip.summary": "Un depósito rallado para vaciar tus _artículos fluidos._", @@ -1295,7 +1303,7 @@ "block.create.mechanical_arm.tooltip": "BRAZO MECÁNICO", "block.create.mechanical_arm.tooltip.summary": "Artilugio avanzado para reubicar _elementos_", "block.create.mechanical_arm.tooltip.condition1": "Transferencia de elementos", - "block.create.mechanical_arm.tooltip.behaviour1": "Puede tomar o colocar objetos en cualquier _inventario_ accesible_, como _Correas_, _Depósitos_, _Embudos_ y _Autoensambladores_", + "block.create.mechanical_arm.tooltip.behaviour1": "Puede tomar o colocar objetos en cualquier _inventario_ accesible_, como _Cintas_, _Depósitos_, _Embudos_ y _Autoensambladores_", "block.create.mechanical_arm.tooltip.control1": "Mientras está en la mano", "block.create.mechanical_arm.tooltip.action1": "Haz clic con el botón derecho en un _objeto accesible del inventario_ para establecerlo como _fuente_ para el _brazo mecánico_. Haz clic con el botón derecho del ratón dos veces para establecerlo como _destino_", "block.create.mechanical_arm.tooltip.control2": "Usa la rueda del ratón con la Llave Inglesa", @@ -1410,7 +1418,7 @@ "block.create.gearshift.tooltip.condition1": "Cuando se alimenta", "block.create.gearshift.tooltip.behaviour1": "_Invierte_ la rotación de salida", - "bloque.crear.embrague.información.sobre.herramientas": "EMBRAGUE", + "block.create.clutch.tooltip": "Embrague", "block.create.clutch.tooltip.summary": "Un control para conectar/desconectar la rotación de los ejes conectados", "block.create.clutch.tooltip.condition1": "Cuando se acciona", "block.create.clutch.tooltip.behaviour1": "_Detiene_ el transporte de la rotación al otro lado", @@ -1493,8 +1501,8 @@ "block.create.mechanical_press.tooltip.summary": "Un pistón de fuerza para comprimir los objetos que tiene debajo. Requiere una _fuerza de rotación_ constante", "block.create.mechanical_press.tooltip.condition1": "Cuando es impulsado por Redstone", "block.create.mechanical_press.tooltip.behaviour1": "Comienza a _comprimir_ los objetos que caen debajo", - "block.create.mechanical_press.tooltip.condition2": "Cuando está por encima de una correa", - "block.create.mechanical_press.tooltip.behaviour2": "Comprime _automáticamente_ los elementos de derivación en la correa", + "block.create.mechanical_press.tooltip.condition2": "Cuando está por encima de una cinta", + "block.create.mechanical_press.tooltip.behaviour2": "Comprime _automáticamente_ los elementos de derivación en la cinta", "block.create.mechanical_press.tooltip.condition3": "Cuando está por encima de la Cuenca", "block.create.mechanical_press.tooltip.behaviour3": "Comienza a _compactar artículos_ en la cuenca siempre que estén presentes todos los ingredientes necesarios", @@ -1519,13 +1527,13 @@ "block.create.mechanical_mixer.tooltip.behaviour1": "Comienza a mezclar los elementos en la cuenca siempre que estén presentes todos los ingredientes necesarios. Para evitar recetas no deseadas, utilice la ranura del filtro de la cuenca o reduzca la fuerza de rotación hasta que se hayan añadido todos los ingredientes deseados", "block.create.mechanical_crafter.tooltip": "AUTOENSAMBLADOR MECÁNICO", - "block.create.mechanical_crafter.tooltip.summary": "Un ensamblador cinético para _automatizar_ cualquier receta de _crafteo_ con forma. Coloca _múltiples en una cuadrícula_ correspondiente a tu receta, y _organiza sus correas_ para crear un _flujo_ que salga de la cuadrícula en uno de los Autoensambladores", + "block.create.mechanical_crafter.tooltip.summary": "Un ensamblador cinético para _automatizar_ cualquier receta de _crafteo_ con forma. Coloca _múltiples en una cuadrícula_ correspondiente a tu receta, y _organiza sus cintas_ para crear un _flujo_ que salga de la cuadrícula en uno de los Autoensambladores", "block.create.mechanical_crafter.tooltip.condition1": "Cuando es impulsado por la cinética", "block.create.mechanical_crafter.tooltip.behaviour1": "_Empieza el proceso de creación_ en cuanto _todos los crafters_ de la parrilla hayan recibido un objeto_", "block.create.mechanical_crafter.tooltip.condition2": "Con pulso de Redstone", "block.create.mechanical_crafter.tooltip.behaviour2": "_Fuerza_ el inicio del proceso de _creación_ con todos los _artículos_ dados actualmente en la parrilla", "block.create.mechanical_crafter.tooltip.control1": "Cuando se arranca por delante", - "block.create.mechanical_crafter.tooltip.action1": "_Circula la dirección_ hacia la que un autoensamblador individual _mueve sus objetos_. Para formar una cuadrícula de trabajo, _organiza las correas en un flujo_ que mueva todos los objetos hacia un autoensamblador final. El autoensamblador final debe _apuntar hacia fuera_ de la rejilla", + "block.create.mechanical_crafter.tooltip.action1": "_Circula la dirección_ hacia la que un autoensamblador individual _mueve sus objetos_. Para formar una cuadrícula de trabajo, _organiza las cintas en un flujo_ que mueva todos los objetos hacia un autoensamblador final. El autoensamblador final debe _apuntar hacia fuera_ de la rejilla", "block.create.mechanical_crafter.tooltip.control2": "Cuando se arranca hacia atrás", "block.create.mechanical_crafter.tooltip.action2": "Conecta_ el _inventario de entrada_ de los autoensambladores adyacentes. Usa esto para _combinar ranuras_ en la cuadrícula de trabajo y _guardar el la entrada de trabajo_", @@ -1630,7 +1638,7 @@ "block.create.secondary_linear_chassis.tooltip": "CHASIS LINEAL SECUNDARIO", "block.create.secondary_linear_chassis.tooltip.summary": "Un segundo tipo de _Chasis lineal_ que no se conecta al otro", - "bloque.crear.chasis_radial.tooltip": "CHASIS DE ROTACIÓN", + "block.create.radial_chassis.tooltip": "CHASIS RADIAL", "block.create.radial_chassis.tooltip.summary": "Bloque base configurable que conecta estructuras para el movimiento", "block.create.radial_chassis.tooltip.condition1": "Cuando se mueve", "block.create.radial_chassis.tooltip.behaviour1": "_Mueve_ todos los _Chasis_ adjuntos en una columna, y un cilindro de bloques a su alrededor. Los bloques que lo rodean sólo se mueven cuando están dentro del rango y están adheridos a un lado pegajoso (Ver [Ctrl]).", @@ -1716,7 +1724,7 @@ "block.create.deployer.tooltip.behaviour3": "El desplegador no se activará a menos que el elemento retenido _coincida_ con el _filtro._ Los elementos que no coincidan no podrán ser insertados; los elementos retenidos que coincidan con el filtro no podrán ser extraídos.", "block.create.brass_casing.tooltip": "REVESTIDOR DE LATÓN", - "block.create.brass_casing.tooltip.summary": "Resistente máquina revestidora con una gran variedad de usos. Segura para la decoración. Se puede utilizar para _revestir ejes_ y _correas._", + "block.create.brass_casing.tooltip.summary": "Resistente máquina revestidora con una gran variedad de usos. Segura para la decoración. Se puede utilizar para _revestir ejes_ y _cintas._", "block.create.pulse_repeater.tooltip": "REPETIDOR DE PULSOS DE REDSTONE", "block.create.pulse_repeater.tooltip.summary": "Un circuito sencillo para cortar las señales de Redstone que pasan a una longitud de _1 tick_", @@ -1792,6 +1800,6 @@ "create.tooltip.randomWipDescription7": "Este quizás no es para ti. ¿Qué tal ese?", "create.tooltip.randomWipDescription8": "Úsalo y arrepiéntete de tu decisión inmediatamente", - "_": "Gracias por traducir Create!" + "_": "Thank you for translating Create!" } diff --git a/src/main/resources/assets/create/lang/ru_ru.json b/src/main/resources/assets/create/lang/ru_ru.json index 87369b59b..d7197e071 100644 --- a/src/main/resources/assets/create/lang/ru_ru.json +++ b/src/main/resources/assets/create/lang/ru_ru.json @@ -773,7 +773,7 @@ "create.gui.terrainzapper.tool.overlay": "Наложение", "create.gui.terrainzapper.tool.flatten": "Выравнивание", - "create.terrainzapper.shiftRightClickToSet": "ПКМ крадясь, чтобы выбрать форму", + "create.terrainzapper.shiftRightClickToSet": "ПКМ крадучись, чтобы выбрать форму", "create.blockzapper.usingBlock": "С помощью: %1$s", "create.blockzapper.componentUpgrades": "Обновления компонентов:", @@ -1304,7 +1304,7 @@ "item.create.wand_of_symmetry.tooltip.action1": "_Создаёт_ или _Перемещает_ зеркало", "item.create.wand_of_symmetry.tooltip.control2": "ПКМ в воздух", "item.create.wand_of_symmetry.tooltip.action2": "_Убирает_ зеркало", - "item.create.wand_of_symmetry.tooltip.control3": "ПКМ крадясь", + "item.create.wand_of_symmetry.tooltip.control3": "ПКМ крадучись", "item.create.wand_of_symmetry.tooltip.action3": "Открывает _интерфейс_ _конфигурации_", "item.create.handheld_blockzapper.tooltip": "BLOCKZAPPER", @@ -1313,7 +1313,7 @@ "item.create.handheld_blockzapper.tooltip.action1": "Устанавливает выбранный блок как материал.", "item.create.handheld_blockzapper.tooltip.control2": "ПКМ на блок", "item.create.handheld_blockzapper.tooltip.action2": "_Размещает_ или _Замещает_ блок.", - "item.create.handheld_blockzapper.tooltip.control3": "ПКМ крадясь", + "item.create.handheld_blockzapper.tooltip.control3": "ПКМ крадучись", "item.create.handheld_blockzapper.tooltip.action3": "Открывает _интерфейс_ _конфигурации_", "item.create.handheld_worldshaper.tooltip": "HANDHELD WORLDSHAPER", @@ -1322,7 +1322,7 @@ "item.create.handheld_worldshaper.tooltip.action1": "Устанавливает блоки, помещенные инструментом, в целевой блок.", "item.create.handheld_worldshaper.tooltip.control2": "ПКМ на блок", "item.create.handheld_worldshaper.tooltip.action2": "Применяет выбранную _кисть_ и _инструмент_ в выбранном месте.", - "item.create.handheld_worldshaper.tooltip.control3": "ПКМ крадясь", + "item.create.handheld_worldshaper.tooltip.control3": "ПКМ крадучись", "item.create.handheld_worldshaper.tooltip.action3": "Открывает _интерфейс_ _конфигурации_", "item.create.tree_fertilizer.tooltip": "TREE FERTILIZER", @@ -1359,7 +1359,7 @@ "item.create.schematic.tooltip.summary": "Содержит структуру, которая будет позиционироваться и помещаться в мир. Расположите голограмму по своему усмотрению и используйте _схематичную пушку_ для ее построения.", "item.create.schematic.tooltip.condition1": "При удерживании", "item.create.schematic.tooltip.behaviour1": "Может быть позиционирован с помощью инструментов на экране.", - "item.create.schematic.tooltip.control1": "ПКМ крадясь", + "item.create.schematic.tooltip.control1": "ПКМ крадучись", "item.create.schematic.tooltip.action1": "Открывает _интерфейс_ для ввода _точных_ _координат_.", "item.create.schematic_and_quill.tooltip": "SCHEMATIC AND QUILL", @@ -1372,7 +1372,7 @@ "item.create.schematic_and_quill.tooltip.action1": "Выберите угловые точки / подтвердите сохранение.", "item.create.schematic_and_quill.tooltip.control2": "Удержание Ctrl", "item.create.schematic_and_quill.tooltip.action2": "Выберите точки в воздухе. Прокрутка для настройки расстояния.", - "item.create.schematic_and_quill.tooltip.control3": "ПКМ крадясь", + "item.create.schematic_and_quill.tooltip.control3": "ПКМ крадучись", "item.create.schematic_and_quill.tooltip.action3": "_Сбрасывает_ и _удаляет_ выделение.", "block.create.schematicannon.tooltip": "SCHEMATICANNON", @@ -1424,7 +1424,7 @@ "item.create.belt_connector.tooltip.summary": "Соединяет _2_ _Вала_ с помощью _механического_ _ремня_._ Соединённые валы будут иметь одинаковые _скорость_ и _направление_ _вращения._ Лента может служить как _конвейер_ для _транспортировки._", "item.create.belt_connector.tooltip.control1": "ПКМ по валу", "item.create.belt_connector.tooltip.action1": "Выбирает вал в качестве одного шкива конвейера. Оба выбранных вала должны быть _на_ _одной_ _линии_ _вертикально,_ _горизонтально_ либо _диагонально_ по направлению конвейера.", - "item.create.belt_connector.tooltip.control2": "ПКМ крадясь", + "item.create.belt_connector.tooltip.control2": "ПКМ крадучись", "item.create.belt_connector.tooltip.action2": "_Сбрасывает_ первый выбранный шкив для конвейера.", "item.create.goggles.tooltip": "GOGGLES", @@ -1438,7 +1438,7 @@ "item.create.wrench.tooltip.summary": "Полезный _инструмент_ для работы с _кинетическими_ штуковинами. Может использоваться для _поворота_, _демонтажа_ и _настройки_ компонентов.", "item.create.wrench.tooltip.control1": "ПКМ по кинетическому блоку", "item.create.wrench.tooltip.action1": "_Поворачивает_ _компонент_ с которым вы взаимодействуете _к_ _лицу_ или _от_ _лица_.", - "item.create.wrench.tooltip.control2": "ПКМ крадясь", + "item.create.wrench.tooltip.control2": "ПКМ крадучись", "item.create.wrench.tooltip.action2": "Разбирает кинетические компоненты и помещает их обратно в ваш инвентарь.", "block.create.creative_motor.tooltip": "CREATIVE MOTOR", @@ -1671,10 +1671,10 @@ "block.create.redstone_link.tooltip": "REDSTONE LINK", "block.create.redstone_link.tooltip.summary": "_Беспроводной_ _передатчик_ сигнала красного камня. Можно выбрать _частоты_ с помощью любого предмета. Диапазон сигнала ограничен, но достаточно далёк.", "block.create.redstone_link.tooltip.condition1": "Когда приведен в действие", - "block.create.redstone_link.tooltip.behaviour1": "Приняв сигнал той-же _частоты_ выдаёт сигнал красного камня или наоборот.", + "block.create.redstone_link.tooltip.behaviour1": "Приняв сигнал той же _частоты_ выдаёт сигнал красного камня или наоборот.", "block.create.redstone_link.tooltip.control1": "При ПКМ предметом", "block.create.redstone_link.tooltip.action1": "Устанавливает частоту для этого предмета. Всего _два_ разных предмета могут быть использованы в комбинации для определения частоты.", - "block.create.redstone_link.tooltip.control2": "ПКМ крадясь", + "block.create.redstone_link.tooltip.control2": "ПКМ крадучись", "block.create.redstone_link.tooltip.action2": "Переключение между режимом _приемника_ и _передатчика_.", "block.create.nixie_tube.tooltip": "NIXIE TUBE", diff --git a/src/main/resources/assets/create/models/block/analog_lever/item.json b/src/main/resources/assets/create/models/block/analog_lever/item.json index 01b9ee73e..855add131 100644 --- a/src/main/resources/assets/create/models/block/analog_lever/item.json +++ b/src/main/resources/assets/create/models/block/analog_lever/item.json @@ -67,7 +67,7 @@ }, "fixed": { "rotation": [-90, 0, 0], - "translation": [0, 0, -6], + "translation": [0, 0, -5.25], "scale": [0.75, 0.75, 0.75] } }, diff --git a/src/main/resources/assets/create/models/block/belt/diagonal_end.json b/src/main/resources/assets/create/models/block/belt/diagonal_end.json index 5a73025f5..02bd2d2d7 100644 --- a/src/main/resources/assets/create/models/block/belt/diagonal_end.json +++ b/src/main/resources/assets/create/models/block/belt/diagonal_end.json @@ -10,6 +10,7 @@ "name": "Bottom", "from": [0.9, 3, 1], "to": [15.1, 5, 6.8], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "north": {"uv": [1, 6, 15, 7], "rotation": 180, "texture": "#0"}, "east": {"uv": [14, 0, 16, 6], "rotation": 270, "texture": "#0"}, @@ -22,6 +23,7 @@ "name": "Bottom", "from": [2.9, 5, 2], "to": [13.1, 6, 6.8], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "east": {"uv": [3, 0, 4, 5], "rotation": 270, "texture": "#0"}, "west": {"uv": [12, 0, 13, 5], "rotation": 90, "texture": "#0"}, @@ -32,8 +34,9 @@ "name": "Top", "from": [0.9, 11, 1], "to": [15.1, 13, 10.1], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { - "north": {"uv": [1, 6, 15, 5], "rotation": 180, "texture": "#0"}, + "north": {"uv": [1, 5, 15, 6], "rotation": 180, "texture": "#0"}, "east": {"uv": [14, 6, 16, 15], "rotation": 90, "texture": "#0"}, "west": {"uv": [0, 6, 2, 15], "rotation": 270, "texture": "#0"}, "up": {"uv": [1, 6, 15, 15], "texture": "#0"}, @@ -44,6 +47,7 @@ "name": "Top", "from": [2.9, 10, 2], "to": [13.1, 11, 10.1], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "east": {"uv": [3, 7, 4, 15], "rotation": 90, "texture": "#0"}, "west": {"uv": [12, 7, 13, 15], "rotation": 270, "texture": "#0"}, @@ -54,19 +58,21 @@ "name": "Side", "from": [1, 4, 0], "to": [15, 12, 2], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "north": {"uv": [1, 8, 15, 16], "rotation": 180, "texture": "#0"}, "east": {"uv": [14, 8, 16, 16], "rotation": 180, "texture": "#0"}, "south": {"uv": [1, 8, 15, 16], "rotation": 180, "texture": "#0"}, "west": {"uv": [0, 8, 2, 16], "rotation": 180, "texture": "#0"}, - "up": {"uv": [1, 4, 15, 5], "rotation": 180, "texture": "#0"}, - "down": {"uv": [1, 7, 15, 8], "rotation": 180, "texture": "#0"} + "up": {"uv": [1, 4, 15, 5], "texture": "#0"}, + "down": {"uv": [1, 7, 15, 8], "texture": "#0"} } }, { "name": "Side", "from": [2.9, 6, 2], "to": [13.1, 10, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "east": {"uv": [3, 10, 4, 14], "rotation": 180, "texture": "#0"}, "south": {"uv": [3, 10, 13, 14], "rotation": 180, "texture": "#0"}, diff --git a/src/main/resources/assets/create/models/block/belt/end.json b/src/main/resources/assets/create/models/block/belt/end.json index 142f58c71..d8f167443 100644 --- a/src/main/resources/assets/create/models/block/belt/end.json +++ b/src/main/resources/assets/create/models/block/belt/end.json @@ -9,9 +9,10 @@ "name": "Top", "from": [1, 11, 0], "to": [15, 13, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "east": {"uv": [0, 1, 2, 16], "rotation": 270, "texture": "#0"}, - "south": {"uv": [1, 1, 15, 0], "texture": "#0"}, + "south": {"uv": [1, 0, 15, 1], "rotation": 180, "texture": "#0"}, "west": {"uv": [14, 1, 16, 16], "rotation": 90, "texture": "#0"}, "up": {"uv": [1, 1, 15, 16], "rotation": 180, "texture": "#0"}, "down": {"uv": [1, 1, 15, 16], "texture": "#0"} @@ -21,6 +22,7 @@ "name": "Top", "from": [3, 10, 0], "to": [13, 11, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "east": {"uv": [3, 2, 4, 16], "rotation": 270, "texture": "#0"}, "west": {"uv": [12, 2, 13, 16], "rotation": 90, "texture": "#0"}, @@ -31,19 +33,21 @@ "name": "Side", "from": [1.1, 4, 14], "to": [14.9, 12, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "north": {"uv": [1, 8, 15, 16], "rotation": 180, "texture": "#0"}, "east": {"uv": [0, 8, 2, 16], "rotation": 180, "texture": "#0"}, "south": {"uv": [1, 8, 15, 16], "rotation": 180, "texture": "#0"}, "west": {"uv": [14, 8, 16, 16], "rotation": 180, "texture": "#0"}, - "up": {"uv": [1, 15, 15, 16], "rotation": 180, "texture": "#0"}, - "down": {"uv": [1, 8, 15, 9], "rotation": 180, "texture": "#0"} + "up": {"uv": [1, 0, 15, 1], "rotation": 180, "texture": "#0"}, + "down": {"uv": [1, 7, 15, 8], "rotation": 180, "texture": "#0"} } }, { "name": "Side", "from": [3, 6, 13], "to": [13, 10, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "north": {"uv": [3, 10, 13, 14], "rotation": 180, "texture": "#0"}, "east": {"uv": [12, 10, 13, 14], "rotation": 180, "texture": "#0"}, diff --git a/src/main/resources/assets/create/models/block/belt/start.json b/src/main/resources/assets/create/models/block/belt/start.json index ff4a6eed9..c262e4bb5 100644 --- a/src/main/resources/assets/create/models/block/belt/start.json +++ b/src/main/resources/assets/create/models/block/belt/start.json @@ -9,6 +9,7 @@ "name": "Top", "from": [3, 10, 2], "to": [13, 11, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "east": {"uv": [3, 0, 4, 14], "rotation": 270, "texture": "#0"}, "west": {"uv": [12, 0, 13, 14], "rotation": 90, "texture": "#0"}, @@ -19,6 +20,7 @@ "name": "Top", "from": [1, 11, 1], "to": [15, 13, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "north": {"uv": [1, 15, 15, 16], "texture": "#0"}, "east": {"uv": [0, 0, 2, 15], "rotation": 270, "texture": "#0"}, @@ -31,23 +33,25 @@ "name": "Side", "from": [1.1, 4, 0], "to": [14.9, 12, 2], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "north": {"uv": [1, 0, 15, 8], "texture": "#0"}, "east": {"uv": [0, 0, 2, 8], "texture": "#0"}, "south": {"uv": [1, 0, 15, 8], "texture": "#0"}, "west": {"uv": [14, 0, 16, 8], "texture": "#0"}, - "up": {"uv": [1, 0, 15, 1], "rotation": 180, "texture": "#0"}, - "down": {"uv": [1, 7, 15, 8], "rotation": 180, "texture": "#0"} + "up": {"uv": [1, 15, 15, 16], "rotation": 180, "texture": "#0"}, + "down": {"uv": [1, 8, 15, 9], "rotation": 180, "texture": "#0"} } }, { "name": "Side", "from": [3, 6, 2], "to": [13, 10, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { - "east": {"uv": [3, 6, 4, 10], "rotation": 180, "texture": "#0"}, + "east": {"uv": [3, 6, 4, 10], "texture": "#0"}, "south": {"uv": [3, 2, 13, 6], "texture": "#0"}, - "west": {"uv": [12, 6, 13, 10], "rotation": 180, "texture": "#0"} + "west": {"uv": [12, 6, 13, 10], "texture": "#0"} } } ] diff --git a/src/main/resources/assets/create/models/block/belt/start_bottom.json b/src/main/resources/assets/create/models/block/belt/start_bottom.json index cecb17d1d..bacf34a55 100644 --- a/src/main/resources/assets/create/models/block/belt/start_bottom.json +++ b/src/main/resources/assets/create/models/block/belt/start_bottom.json @@ -9,8 +9,9 @@ "name": "Bottom", "from": [1, 3, 1], "to": [15, 5, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { - "north": {"uv": [1, 0, 15, 1], "rotation": 180, "texture": "#1"}, + "north": {"uv": [1, 0, 15, 1], "texture": "#1"}, "east": {"uv": [0, 1, 2, 16], "rotation": 90, "texture": "#1"}, "west": {"uv": [14, 1, 16, 16], "rotation": 270, "texture": "#1"}, "up": {"uv": [1, 1, 15, 16], "texture": "#1"}, @@ -21,6 +22,7 @@ "name": "Bottom", "from": [3, 5, 2], "to": [13, 6, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "east": {"uv": [12, 2, 13, 16], "rotation": 90, "texture": "#1"}, "west": {"uv": [3, 2, 4, 16], "rotation": 270, "texture": "#1"}, diff --git a/src/main/resources/assets/create/models/block/deployer/hand_holding.json b/src/main/resources/assets/create/models/block/deployer/hand_holding.json index 9a585fb63..0548e608e 100644 --- a/src/main/resources/assets/create/models/block/deployer/hand_holding.json +++ b/src/main/resources/assets/create/models/block/deployer/hand_holding.json @@ -4,7 +4,6 @@ "ambientocclusion": false, "textures": { "18": "create:block/deployer", - "particle": "create:block/gearbox_top", "mechanical_press_head": "create:block/mechanical_press_head", "mechanical_press_pole": "create:block/mechanical_press_pole" }, @@ -25,15 +24,15 @@ }, { "from": [6, 6, 14], - "to": [10, 9, 16], + "to": [10, 10, 16], "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 5]}, "faces": { "north": {"uv": [0, 0, 4, 3], "texture": "#mechanical_press_head"}, - "east": {"uv": [0, 0, 2, 3], "texture": "#mechanical_press_head"}, + "east": {"uv": [3, 0, 5, 4], "rotation": 180, "texture": "#mechanical_press_head"}, "south": {"uv": [0, 0, 4, 3], "texture": "#mechanical_press_head"}, - "west": {"uv": [0, 0, 2, 3], "texture": "#mechanical_press_head"}, - "up": {"uv": [0, 0, 2, 4], "rotation": 270, "texture": "#mechanical_press_head"}, - "down": {"uv": [0, 0, 2, 4], "rotation": 90, "texture": "#mechanical_press_head"} + "west": {"uv": [3, 0, 5, 4], "texture": "#mechanical_press_head"}, + "up": {"uv": [3, 0, 5, 4], "rotation": 270, "texture": "#mechanical_press_head"}, + "down": {"uv": [3, 0, 5, 4], "rotation": 90, "texture": "#mechanical_press_head"} } }, { diff --git a/src/main/resources/assets/create/models/block/deployer/hand_pointing.json b/src/main/resources/assets/create/models/block/deployer/hand_pointing.json index 09d55a11b..b0b91369a 100644 --- a/src/main/resources/assets/create/models/block/deployer/hand_pointing.json +++ b/src/main/resources/assets/create/models/block/deployer/hand_pointing.json @@ -4,7 +4,6 @@ "ambientocclusion": false, "textures": { "18": "create:block/deployer", - "particle": "create:block/gearbox_top", "mechanical_press_head": "create:block/mechanical_press_head", "mechanical_press_pole": "create:block/mechanical_press_pole" }, @@ -51,15 +50,15 @@ }, { "from": [6, 6, 14], - "to": [10, 9, 18], + "to": [10, 9.95, 18], "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 5]}, "faces": { "north": {"uv": [0, 0, 4, 3], "texture": "#mechanical_press_head"}, - "east": {"uv": [0, 0, 4, 3], "texture": "#mechanical_press_head"}, + "east": {"uv": [3, 0, 7, 4], "texture": "#mechanical_press_head"}, "south": {"uv": [0, 0, 4, 3], "texture": "#mechanical_press_head"}, - "west": {"uv": [0, 0, 4, 3], "texture": "#mechanical_press_head"}, + "west": {"uv": [3, 0, 7, 4], "texture": "#mechanical_press_head"}, "up": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#mechanical_press_head"}, - "down": {"uv": [0, 0, 4, 4], "rotation": 90, "texture": "#mechanical_press_head"} + "down": {"uv": [4, 8, 8, 12], "rotation": 90, "texture": "#mechanical_press_head"} } }, { diff --git a/src/main/resources/assets/create/models/block/deployer/hand_punching.json b/src/main/resources/assets/create/models/block/deployer/hand_punching.json index e60304921..2cde3a6ae 100644 --- a/src/main/resources/assets/create/models/block/deployer/hand_punching.json +++ b/src/main/resources/assets/create/models/block/deployer/hand_punching.json @@ -4,7 +4,6 @@ "ambientocclusion": false, "textures": { "18": "create:block/deployer", - "particle": "create:block/gearbox_top", "mechanical_press_head": "create:block/mechanical_press_head", "mechanical_press_pole": "create:block/mechanical_press_pole" }, @@ -25,14 +24,15 @@ }, { "from": [6, 6, 14], - "to": [10, 9, 17], + "to": [10.05, 9.95, 17], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]}, "faces": { "north": {"uv": [0, 0, 4, 3], "texture": "#mechanical_press_head"}, - "east": {"uv": [0, 0, 3, 3], "texture": "#mechanical_press_head"}, + "east": {"uv": [4, 0, 7, 4], "texture": "#mechanical_press_head"}, "south": {"uv": [0, 0, 4, 3], "texture": "#mechanical_press_head"}, - "west": {"uv": [0, 0, 3, 3], "texture": "#mechanical_press_head"}, - "up": {"uv": [0, 0, 3, 4], "rotation": 270, "texture": "#mechanical_press_head"}, - "down": {"uv": [0, 0, 3, 4], "rotation": 90, "texture": "#mechanical_press_head"} + "west": {"uv": [3, 0, 6, 4], "texture": "#mechanical_press_head"}, + "up": {"uv": [3, 0, 6, 4], "rotation": 270, "texture": "#mechanical_press_head"}, + "down": {"uv": [4, 8, 7, 12], "rotation": 270, "texture": "#mechanical_press_head"} } }, { @@ -88,28 +88,28 @@ } }, { - "from": [9, 8, 16], + "from": [9, 8, 15], "to": [11, 10, 17], "rotation": {"angle": 0, "axis": "x", "origin": [7, 8, 8]}, "faces": { "north": {"uv": [0, 2, 2, 4], "rotation": 90, "texture": "#18"}, - "east": {"uv": [0, 3, 2, 4], "rotation": 90, "texture": "#18"}, + "east": {"uv": [0, 2, 2, 4], "rotation": 90, "texture": "#18"}, "south": {"uv": [0, 8, 2, 10], "rotation": 180, "texture": "#18"}, "west": {"uv": [0, 0, 1, 2], "rotation": 180, "texture": "#18"}, - "up": {"uv": [0, 0, 1, 2], "rotation": 90, "texture": "#18"}, + "up": {"uv": [0, 0, 2, 2], "rotation": 90, "texture": "#18"}, "down": {"uv": [0, 0, 1, 2], "rotation": 270, "texture": "#18"} } }, { "from": [5, 7, 15], - "to": [9, 10, 17], + "to": [10, 11, 17], "rotation": {"angle": 0, "axis": "x", "origin": [7, 8, 8]}, "faces": { - "north": {"uv": [0, 3, 4, 6], "texture": "#18"}, - "east": {"uv": [1, 2, 3, 5], "texture": "#18"}, + "north": {"uv": [6, 1, 10, 6], "rotation": 90, "texture": "#18"}, + "east": {"uv": [0, 6, 3, 8], "rotation": 90, "texture": "#18"}, "south": {"uv": [0, 0, 3, 4], "rotation": 270, "texture": "#18"}, - "west": {"uv": [0, 2, 2, 5], "texture": "#18"}, - "up": {"uv": [0, 0, 2, 4], "rotation": 90, "texture": "#18"}, + "west": {"uv": [0, 2, 2, 6], "texture": "#18"}, + "up": {"uv": [0, 0, 2, 5], "rotation": 90, "texture": "#18"}, "down": {"uv": [1, 4, 3, 8], "rotation": 270, "texture": "#18"} } } diff --git a/src/main/resources/assets/create/models/block/diodes/adjustable_pulse_repeater.json b/src/main/resources/assets/create/models/block/diodes/adjustable_pulse_repeater.json index 685e4b7b6..6481341d8 100644 --- a/src/main/resources/assets/create/models/block/diodes/adjustable_pulse_repeater.json +++ b/src/main/resources/assets/create/models/block/diodes/adjustable_pulse_repeater.json @@ -60,6 +60,11 @@ } ], "display": { + "gui": { + "rotation": [30, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.625, 0.625, 0.625] + }, "fixed": { "rotation": [ 270, 0, 0 ], "translation": [ 0, 0, -3], diff --git a/src/main/resources/assets/create/models/block/diodes/adjustable_repeater.json b/src/main/resources/assets/create/models/block/diodes/adjustable_repeater.json index 7cd8a0331..cf137e612 100644 --- a/src/main/resources/assets/create/models/block/diodes/adjustable_repeater.json +++ b/src/main/resources/assets/create/models/block/diodes/adjustable_repeater.json @@ -34,6 +34,11 @@ } ], "display": { + "gui": { + "rotation": [30, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.625, 0.625, 0.625] + }, "fixed": { "rotation": [ 270, 0, 0 ], "translation": [ 0, 0, -3], diff --git a/src/main/resources/assets/create/models/block/diodes/latch_off.json b/src/main/resources/assets/create/models/block/diodes/latch_off.json index b1fdfac10..4e8ce60be 100644 --- a/src/main/resources/assets/create/models/block/diodes/latch_off.json +++ b/src/main/resources/assets/create/models/block/diodes/latch_off.json @@ -90,11 +90,16 @@ } } ], - "groups": [0, 1, 2, 3, 4, - { - "name": "lever", - "origin": [8, 8, 8], - "children": [5, 6] - } - ] + "display": { + "gui": { + "rotation": [30, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "rotation": [ 270, 0, 0 ], + "translation": [ 0, 0, -3], + "scale":[ 0.5, 0.5, 0.5 ] + } + } } \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/diodes/latch_on.json b/src/main/resources/assets/create/models/block/diodes/latch_on.json index 8354678e8..6d4c4797f 100644 --- a/src/main/resources/assets/create/models/block/diodes/latch_on.json +++ b/src/main/resources/assets/create/models/block/diodes/latch_on.json @@ -92,11 +92,16 @@ } } ], - "groups": [0, 1, 2, 3, 4, - { - "name": "lever", - "origin": [8, 8, 8], - "children": [5, 6] - } - ] + "display": { + "gui": { + "rotation": [30, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "rotation": [ 270, 0, 0 ], + "translation": [ 0, 0, -3], + "scale":[ 0.5, 0.5, 0.5 ] + } + } } \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/diodes/pulse_repeater.json b/src/main/resources/assets/create/models/block/diodes/pulse_repeater.json index 8504219bf..315d2fed2 100644 --- a/src/main/resources/assets/create/models/block/diodes/pulse_repeater.json +++ b/src/main/resources/assets/create/models/block/diodes/pulse_repeater.json @@ -46,5 +46,17 @@ "up": { "texture": "#torch", "uv": [ 7, 6, 9, 8 ] } } } - ] + ], + "display": { + "gui": { + "rotation": [30, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "rotation": [ 270, 0, 0 ], + "translation": [ 0, 0, -3], + "scale":[ 0.5, 0.5, 0.5 ] + } + } } \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/funnel/block_ceiling.json b/src/main/resources/assets/create/models/block/funnel/block_ceiling.json deleted file mode 100644 index 5a70211b5..000000000 --- a/src/main/resources/assets/create/models/block/funnel/block_ceiling.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "credit": "Made with Blockbench", - "parent": "block/block", - "textures": { - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall", - "6": "create:block/brass_funnel", - "7": "create:block/brass_funnel_plating", - "2_2": "create:block/brass_funnel_pull" - }, - "elements": [ - { - "name": "LeftWall", - "from": [14, 6, 0], - "to": [16.05, 12, 16], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 2]}, - "faces": { - "north": {"uv": [14, 0, 16, 6], "rotation": 180, "texture": "#2_2"}, - "east": {"uv": [0, 0, 16, 6], "rotation": 180, "texture": "#2_2"}, - "south": {"uv": [0, 0, 2, 6], "rotation": 180, "texture": "#2_2"}, - "west": {"uv": [0, 12, 16, 6], "texture": "#2_2"}, - "up": {"uv": [15, 0, 16, 8], "texture": "#7"}, - "down": {"uv": [0, 0, 1, 8], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "LeftWall", - "from": [-0.05, 6, 0], - "to": [2, 12, 16], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 2]}, - "faces": { - "north": {"uv": [2, 0, 0, 6], "texture": "#2_2"}, - "east": {"uv": [0, 6, 16, 12], "rotation": 180, "texture": "#2_2"}, - "south": {"uv": [14, 0, 16, 6], "rotation": 180, "texture": "#2_2"}, - "west": {"uv": [0, 6, 16, 0], "texture": "#2_2"}, - "up": {"uv": [8, 0, 9, 8], "texture": "#7"}, - "down": {"uv": [7, 0, 8, 8], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "Top", - "from": [2, 6, 0], - "to": [14, 12, 6], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 2]}, - "faces": { - "north": {"uv": [2, 0, 14, 6], "rotation": 180, "texture": "#2_2"}, - "south": {"uv": [9, 13, 15, 16], "rotation": 180, "texture": "#7"}, - "up": {"uv": [9, 0, 15, 3], "texture": "#7"}, - "down": {"uv": [1, 0, 7, 3], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "Top", - "from": [2, 6, 14], - "to": [14, 12, 16], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 18]}, - "faces": { - "north": {"uv": [15, 13, 9, 16], "rotation": 180, "texture": "#7"}, - "south": {"uv": [14, 0, 2, 6], "rotation": 180, "texture": "#2_2"}, - "up": {"uv": [9, 3, 15, 0], "texture": "#7"}, - "down": {"uv": [0.5, 12.5, 7.5, 11.5], "texture": "#7"} - } - }, - { - "name": "Top", - "from": [2, 7, 6], - "to": [14, 8, 15], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 2]}, - "faces": { - "down": {"uv": [0, 9, 6, 13.5], "rotation": 180, "texture": "#3"} - } - }, - { - "from": [1, 11, 1], - "to": [15, 14, 15], - "rotation": {"angle": 0, "axis": "y", "origin": [9, 21, 10]}, - "faces": { - "north": {"uv": [9, 6.5, 16, 8], "rotation": 180, "texture": "#3"}, - "east": {"uv": [9, 6.5, 16, 8], "rotation": 180, "texture": "#3"}, - "south": {"uv": [9, 6.5, 16, 8], "rotation": 180, "texture": "#3"}, - "west": {"uv": [9, 6.5, 16, 8], "rotation": 180, "texture": "#3"}, - "up": {"uv": [0, 0, 6, 6], "rotation": 90, "texture": "#3"} - } - }, - { - "name": "Back", - "from": [2.1, 14, 2.05], - "to": [13.9, 18.1, 14.1], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 6, 24.1]}, - "faces": { - "north": {"uv": [0, 0, 12, 4], "rotation": 180, "texture": "#6"}, - "east": {"uv": [0, 0, 12, 4], "rotation": 180, "texture": "#6"}, - "south": {"uv": [0, 0, 12, 4], "rotation": 180, "texture": "#6"}, - "west": {"uv": [0, 0, 12, 4], "rotation": 180, "texture": "#6"}, - "up": {"uv": [6, 8, 12, 14], "texture": "#3"} - } - }, - { - "name": "Back", - "from": [2.1, 11.9, 2.05], - "to": [13.9, 14, 13.1], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 22, 24.1]}, - "faces": { - "north": {"uv": [0, 1.5, 6, 0.5], "rotation": 180, "texture": "#6"}, - "east": {"uv": [2.5, 0.5, 8, 1.5], "texture": "#5"}, - "west": {"uv": [2.5, 1.5, 8, 0.5], "rotation": 180, "texture": "#5"} - } - } - ], - "groups": [ - { - "name": "block_retracted", - "origin": [8, 8, 8], - "children": [ - { - "name": "BeltFunnel", - "origin": [9, -4, 8], - "children": [ - { - "name": "FrontSection", - "origin": [9, -4, 8], - "children": [0, 1, 2, 3, 4, 5] - }, - { - "name": "Base", - "origin": [9, -4, 8], - "children": [6, 7] - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/funnel/block_ceiling_old.json b/src/main/resources/assets/create/models/block/funnel/block_ceiling_old.json deleted file mode 100644 index d5fd6b599..000000000 --- a/src/main/resources/assets/create/models/block/funnel/block_ceiling_old.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "credit": "Made with Blockbench", - "parent": "block/block", - "textures": { - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall", - "6": "create:block/brass_funnel", - "7": "create:block/brass_funnel_plating", - "2_2": "create:block/brass_funnel_pull" - }, - "elements": [ - { - "name": "LeftWall", - "from": [14, 6, -2], - "to": [16.05, 12, 14], - "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 12, 0]}, - "faces": { - "north": {"uv": [0, 0, 2, 6], "texture": "#2_2"}, - "east": {"uv": [0, 0, 16, 6], "rotation": 180, "texture": "#2_2"}, - "south": {"uv": [14, 0, 16, 6], "texture": "#2_2"}, - "west": {"uv": [0, 12, 16, 6], "texture": "#2_2"}, - "up": {"uv": [15, 0, 16, 8], "texture": "#7"}, - "down": {"uv": [0, 0, 1, 8], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "LeftWall", - "from": [-0.05, 6, -2], - "to": [2, 12, 14], - "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 12, 0]}, - "faces": { - "north": {"uv": [16, 0, 14, 6], "rotation": 180, "texture": "#2_2"}, - "east": {"uv": [0, 6, 16, 12], "rotation": 180, "texture": "#2_2"}, - "south": {"uv": [0, 0, 2, 6], "texture": "#2_2"}, - "west": {"uv": [0, 6, 16, 0], "texture": "#2_2"}, - "up": {"uv": [8, 0, 9, 8], "texture": "#7"}, - "down": {"uv": [7, 0, 8, 8], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "Top", - "from": [2, 6, -2], - "to": [14, 12, 4], - "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 12, 0]}, - "faces": { - "north": {"uv": [2, 0, 14, 6], "rotation": 180, "texture": "#2_2"}, - "south": {"uv": [9, 13, 15, 16], "rotation": 180, "texture": "#7"}, - "up": {"uv": [9, 0, 15, 3], "texture": "#7"}, - "down": {"uv": [1, 0, 7, 3], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "Top", - "from": [2, 7, 4], - "to": [14, 8, 13], - "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 12, 0]}, - "faces": { - "down": {"uv": [0, 9, 6, 13.5], "rotation": 180, "texture": "#3"} - } - }, - { - "name": "Top", - "from": [0.05, 12, 14], - "to": [15.95, 15.95, 16], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 17, 2]}, - "faces": { - "north": {"uv": [8, 11, 16, 13], "rotation": 180, "texture": "#7"}, - "east": {"uv": [16, 11, 15, 13], "texture": "#7"}, - "south": {"uv": [8, 11, 16, 13], "rotation": 180, "texture": "#7"}, - "west": {"uv": [9, 11, 8, 13], "texture": "#7"}, - "up": {"uv": [0, 13.5, 8, 14.5], "texture": "#7"}, - "down": {"uv": [0, 11.5, 8, 12.5], "texture": "#7"} - } - }, - { - "name": "Top", - "from": [0, 14, 13.1], - "to": [16, 16, 14], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 17, 1.1]}, - "faces": { - "east": {"uv": [6, 13, 5, 13.5], "rotation": 270, "texture": "#7"}, - "south": {"uv": [0, 13.5, 8, 14.5], "rotation": 180, "texture": "#7"}, - "west": {"uv": [7, 13, 6, 13.5], "rotation": 270, "texture": "#7"}, - "up": {"uv": [0, 13, 8, 13.5], "texture": "#7"} - } - }, - { - "from": [1, 11, 0], - "to": [15, 14, 7], - "rotation": {"angle": 0, "axis": "y", "origin": [9, 21, 9]}, - "faces": { - "north": {"uv": [6.5, 0, 8, 6], "rotation": 270, "texture": "#3"}, - "east": {"uv": [1, 6.5, 4.5, 8], "rotation": 180, "texture": "#3"}, - "west": {"uv": [1, 6, 4.5, 7.5], "texture": "#3"}, - "up": {"uv": [8, 0, 11.5, 6], "rotation": 90, "texture": "#3"} - } - }, - { - "name": "Back", - "from": [2.1, 14, 1.05], - "to": [13.9, 18.1, 13.1], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 6, 23.1]}, - "faces": { - "north": {"uv": [0, 0, 12, 4], "rotation": 180, "texture": "#6"}, - "east": {"uv": [0, 0, 12, 4], "rotation": 180, "texture": "#6"}, - "south": {"uv": [0, 0, 12, 4], "rotation": 180, "texture": "#6"}, - "west": {"uv": [0, 0, 12, 4], "rotation": 180, "texture": "#6"}, - "up": {"uv": [6, 8, 12, 14], "texture": "#3"} - } - }, - { - "name": "Back", - "from": [2.1, 11.9, 1.05], - "to": [13.9, 14, 12.1], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 22, 23.1]}, - "faces": { - "north": {"uv": [0, 1.5, 6, 0.5], "rotation": 180, "texture": "#6"}, - "east": {"uv": [2.5, 0.5, 8, 1.5], "texture": "#5"}, - "west": {"uv": [2.5, 1.5, 8, 0.5], "rotation": 180, "texture": "#5"} - } - } - ], - "groups": [ - { - "name": "block_retracted", - "origin": [8, 8, 8], - "children": [ - { - "name": "BeltFunnel", - "origin": [9, -4, 8], - "children": [ - { - "name": "FrontSection", - "origin": [9, -4, 8], - "children": [0, 1, 2, 3, 4, 5, 6] - }, - { - "name": "Base", - "origin": [9, -4, 8], - "children": [7, 8] - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/funnel/block_floor.json b/src/main/resources/assets/create/models/block/funnel/block_floor.json deleted file mode 100644 index ecd156783..000000000 --- a/src/main/resources/assets/create/models/block/funnel/block_floor.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "credit": "Made with Blockbench", - "parent": "block/block", - "textures": { - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall", - "6": "create:block/brass_funnel", - "7": "create:block/brass_funnel_plating", - "2_2": "create:block/brass_funnel_pull" - }, - "elements": [ - { - "name": "LeftWall", - "from": [-0.05, 4, 0], - "to": [2, 10, 16], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 4, 2]}, - "faces": { - "north": {"uv": [14, 0, 16, 6], "texture": "#2_2"}, - "east": {"uv": [0, 12, 16, 6], "rotation": 180, "texture": "#2_2"}, - "south": {"uv": [0, 0, 2, 6], "texture": "#2_2"}, - "west": {"uv": [0, 0, 16, 6], "texture": "#2_2"}, - "up": {"uv": [0, 0, 1, 8], "texture": "#7"}, - "down": {"uv": [15, 0, 16, 8], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "LeftWall", - "from": [14, 4, 0], - "to": [16.05, 10, 16], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 4, 2]}, - "faces": { - "north": {"uv": [2, 0, 0, 6], "rotation": 180, "texture": "#2_2"}, - "east": {"uv": [0, 6, 16, 0], "rotation": 180, "texture": "#2_2"}, - "south": {"uv": [14, 0, 16, 6], "texture": "#2_2"}, - "west": {"uv": [0, 6, 16, 12], "texture": "#2_2"}, - "up": {"uv": [7, 0, 8, 8], "texture": "#7"}, - "down": {"uv": [8, 0, 9, 8], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "Top", - "from": [2, 4, 0], - "to": [14, 10, 6], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 4, 2]}, - "faces": { - "north": {"uv": [2, 0, 14, 6], "texture": "#2_2"}, - "south": {"uv": [9, 13, 15, 16], "texture": "#7"}, - "up": {"uv": [1, 0, 7, 3], "texture": "#7"}, - "down": {"uv": [9, 0, 15, 3], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "Top", - "from": [2, 4, 14], - "to": [14, 10, 16], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 4, 18]}, - "faces": { - "north": {"uv": [15, 13, 9, 16], "texture": "#7"}, - "south": {"uv": [14, 0, 2, 6], "texture": "#2_2"}, - "up": {"uv": [0.5, 12.5, 7.5, 11.5], "rotation": 180, "texture": "#7"}, - "down": {"uv": [9, 3, 15, 0], "rotation": 180, "texture": "#7"} - } - }, - { - "name": "Top", - "from": [2, 8, 6], - "to": [14, 9, 15], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 4, 2]}, - "faces": { - "up": {"uv": [0, 9, 6, 13.5], "texture": "#3"} - } - }, - { - "from": [1, 2, 1], - "to": [15, 5, 15], - "rotation": {"angle": 0, "axis": "y", "origin": [7, -5, 10]}, - "faces": { - "north": {"uv": [9, 6.5, 16, 8], "texture": "#3"}, - "east": {"uv": [9, 6.5, 16, 8], "texture": "#3"}, - "south": {"uv": [9, 6.5, 16, 8], "texture": "#3"}, - "west": {"uv": [9, 6.5, 16, 8], "texture": "#3"}, - "down": {"uv": [0, 0, 6, 6], "rotation": 270, "texture": "#3"} - } - }, - { - "name": "Back", - "from": [2.1, -2.1, 2.05], - "to": [13.9, 2, 14.1], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 10, 24.1]}, - "faces": { - "north": {"uv": [0, 0, 12, 4], "texture": "#6"}, - "east": {"uv": [0, 0, 12, 4], "texture": "#6"}, - "south": {"uv": [0, 0, 12, 4], "texture": "#6"}, - "west": {"uv": [0, 0, 12, 4], "texture": "#6"}, - "down": {"uv": [6, 8, 12, 14], "rotation": 180, "texture": "#3"} - } - }, - { - "name": "Back", - "from": [2.1, 2, 2.05], - "to": [13.9, 4.1, 13.1], - "rotation": {"angle": 0, "axis": "y", "origin": [8, -6, 24.1]}, - "faces": { - "north": {"uv": [0, 1.5, 6, 0.5], "texture": "#6"}, - "east": {"uv": [2.5, 1.5, 8, 0.5], "texture": "#5"}, - "west": {"uv": [2.5, 0.5, 8, 1.5], "rotation": 180, "texture": "#5"} - } - } - ], - "groups": [ - { - "name": "block_retracted", - "origin": [8, 8, 8], - "children": [ - { - "name": "BeltFunnel", - "origin": [9, -4, 8], - "children": [ - { - "name": "FrontSection", - "origin": [9, -4, 8], - "children": [0, 1, 2, 3, 4, 5] - }, - { - "name": "Base", - "origin": [9, -4, 8], - "children": [6, 7] - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/funnel/block_wall.json b/src/main/resources/assets/create/models/block/funnel/block_horizontal.json similarity index 100% rename from src/main/resources/assets/create/models/block/funnel/block_wall.json rename to src/main/resources/assets/create/models/block/funnel/block_horizontal.json diff --git a/src/main/resources/assets/create/models/block/funnel/block_vertical.json b/src/main/resources/assets/create/models/block/funnel/block_vertical.json new file mode 100644 index 000000000..9af30934a --- /dev/null +++ b/src/main/resources/assets/create/models/block/funnel/block_vertical.json @@ -0,0 +1,212 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "3": "create:block/brass_funnel_back", + "5": "create:block/brass_funnel_tall", + "7": "create:block/brass_funnel_plating", + "8": "create:block/brass_storage_block", + "9": "create:block/brass_funnel_slope", + "10": "create:block/funnel_closed", + "2_2": "create:block/brass_funnel_pull" + }, + "elements": [ + { + "name": "LeftWall", + "from": [0, 4, 0], + "to": [2, 10, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 2]}, + "faces": { + "north": {"uv": [14, 0, 16, 6], "texture": "#2_2"}, + "south": {"uv": [0, 0, 2, 6], "texture": "#2_2"}, + "west": {"uv": [0, 0, 16, 6], "texture": "#2_2"}, + "up": {"uv": [0, 0, 2, 16], "texture": "#8"}, + "down": {"uv": [0, 0, 16, 2], "rotation": 270, "texture": "#8"} + } + }, + { + "name": "LeftWall", + "from": [14, 4, 0], + "to": [16, 10, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 2]}, + "faces": { + "north": {"uv": [2, 0, 0, 6], "rotation": 180, "texture": "#2_2"}, + "east": {"uv": [0, 6, 16, 0], "rotation": 180, "texture": "#2_2"}, + "south": {"uv": [14, 0, 16, 6], "texture": "#2_2"}, + "up": {"uv": [14, 0, 16, 16], "texture": "#8"}, + "down": {"uv": [0, 14, 16, 16], "rotation": 270, "texture": "#8"} + } + }, + { + "name": "Top", + "from": [2, 4, 0], + "to": [14, 10, 2], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 2]}, + "faces": { + "north": {"uv": [2, 0, 14, 6], "texture": "#2_2"}, + "up": {"uv": [2, 0, 14, 2], "texture": "#8"}, + "down": {"uv": [0, 2, 2, 14], "rotation": 270, "texture": "#8"} + } + }, + { + "name": "Top", + "from": [2, 4, 14], + "to": [14, 10, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 18]}, + "faces": { + "south": {"uv": [14, 0, 2, 6], "texture": "#2_2"}, + "up": {"uv": [2, 16, 14, 14], "rotation": 180, "texture": "#8"}, + "down": {"uv": [14, 14, 16, 2], "rotation": 270, "texture": "#8"} + } + }, + { + "from": [1, 1, 1], + "to": [15, 4, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [7, -6, 10]}, + "faces": { + "north": {"uv": [1, 0, 15, 3], "texture": "#5"}, + "east": {"uv": [1, 0, 15, 3], "texture": "#5"}, + "south": {"uv": [1, 0, 15, 3], "texture": "#5"}, + "west": {"uv": [1, 0, 15, 3], "texture": "#5"}, + "down": {"uv": [2, 2, 14, 14], "rotation": 270, "texture": "#8"} + } + }, + { + "from": [1, 5, 2], + "to": [2, 10, 14], + "rotation": {"angle": 22.5, "axis": "z", "origin": [2, 10, 8]}, + "faces": { + "east": {"uv": [2, 2, 14, 7], "texture": "#9"} + } + }, + { + "from": [14, 5, 2], + "to": [15, 10, 14], + "rotation": {"angle": -22.5, "axis": "z", "origin": [14, 10, 8]}, + "faces": { + "west": {"uv": [2, 2, 14, 7], "texture": "#9"} + } + }, + { + "from": [2, 5, 14], + "to": [14, 10, 15], + "rotation": {"angle": 22.5, "axis": "x", "origin": [8, 10, 14]}, + "faces": { + "north": {"uv": [2, 2, 14, 7], "texture": "#9"} + } + }, + { + "from": [2, 5, 1], + "to": [14, 10, 2], + "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 10, 2]}, + "faces": { + "south": {"uv": [2, 2, 14, 7], "texture": "#9"} + } + }, + { + "from": [3, 5, 3], + "to": [13, 6, 13], + "rotation": {"angle": 0, "axis": "y", "origin": [11, 13, 11]}, + "faces": { + "up": {"uv": [3, 3, 13, 13], "texture": "#10"} + } + }, + { + "name": "Back", + "from": [1.95, -1.95, 1.95], + "to": [14.05, 2, 14.05], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0.025, 8]}, + "faces": { + "north": {"uv": [2, 12, 14, 16], "texture": "#9"}, + "east": {"uv": [2, 12, 14, 16], "texture": "#9"}, + "south": {"uv": [2, 12, 14, 16], "texture": "#9"}, + "west": {"uv": [2, 12, 14, 16], "texture": "#9"}, + "down": {"uv": [6, 8, 12, 14], "rotation": 180, "texture": "#3"} + } + }, + { + "name": "Back", + "from": [2.1, 2, 2.05], + "to": [13.9, 4.1, 13.1], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -6, 24.1]}, + "faces": { + "east": {"uv": [2.5, 1.5, 8, 0.5], "texture": "#5"}, + "west": {"uv": [2.5, 0.5, 8, 1.5], "rotation": 180, "texture": "#5"} + } + }, + { + "from": [5.05, -0.95, 0.05], + "to": [10.95, 4, 2], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]}, + "faces": { + "north": {"uv": [2.5, 0.5, 5.5, 3], "texture": "#7"}, + "east": {"uv": [4.5, 0.5, 5.5, 3], "texture": "#7"}, + "west": {"uv": [2.5, 0.5, 3.5, 3], "texture": "#7"}, + "down": {"uv": [2.5, 11.5, 5.5, 12.5], "texture": "#7"} + } + }, + { + "from": [5.05, -0.95, 14], + "to": [10.95, 4, 15.95], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]}, + "faces": { + "east": {"uv": [2.5, 0.5, 3.5, 3], "texture": "#7"}, + "south": {"uv": [2.5, 0.5, 5.5, 3], "texture": "#7"}, + "west": {"uv": [4.5, 0.5, 5.5, 3], "texture": "#7"}, + "down": {"uv": [2.5, 11.5, 5.5, 12.5], "rotation": 180, "texture": "#7"} + } + }, + { + "from": [14, -0.95, 5.05], + "to": [15.95, 4, 10.95], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]}, + "faces": { + "north": {"uv": [2.5, 0.5, 3.5, 3], "texture": "#7"}, + "east": {"uv": [2.5, 0.5, 5.5, 3], "texture": "#7"}, + "south": {"uv": [4.5, 0.5, 5.5, 3], "texture": "#7"}, + "down": {"uv": [2.5, 11.5, 5.5, 12.5], "rotation": 270, "texture": "#7"} + } + }, + { + "from": [0.05, -0.95, 5.05], + "to": [2, 4, 10.95], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]}, + "faces": { + "north": {"uv": [4.5, 0.5, 5.5, 3], "texture": "#7"}, + "south": {"uv": [2.5, 0.5, 3.5, 3], "texture": "#7"}, + "west": {"uv": [2.5, 0.5, 5.5, 3], "texture": "#7"}, + "down": {"uv": [2.5, 11.5, 5.5, 12.5], "rotation": 90, "texture": "#7"} + } + } + ], + "display": {}, + "groups": [ + { + "name": "block_retracted", + "origin": [8, 8, 8], + "children": [ + { + "name": "BeltFunnel", + "origin": [9, -4, 8], + "children": [ + { + "name": "FrontSection", + "origin": [9, -4, 8], + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + }, + { + "name": "Base", + "origin": [9, -4, 8], + "children": [10, 11] + } + ] + } + ] + }, + { + "name": "Item Filter", + "origin": [8, 0, 8], + "children": [12, 13, 14, 15] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/funnel/block_vertical_filterless.json b/src/main/resources/assets/create/models/block/funnel/block_vertical_filterless.json new file mode 100644 index 000000000..ca31358f9 --- /dev/null +++ b/src/main/resources/assets/create/models/block/funnel/block_vertical_filterless.json @@ -0,0 +1,168 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "3": "create:block/brass_funnel_back", + "5": "create:block/brass_funnel_tall", + "7": "create:block/brass_funnel_plating", + "8": "create:block/brass_storage_block", + "9": "create:block/brass_funnel_slope", + "10": "create:block/funnel_closed", + "2_2": "create:block/brass_funnel_pull" + }, + "elements": [ + { + "name": "LeftWall", + "from": [0, 4, 0], + "to": [2, 10, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 2]}, + "faces": { + "north": {"uv": [14, 0, 16, 6], "texture": "#2_2"}, + "south": {"uv": [0, 0, 2, 6], "texture": "#2_2"}, + "west": {"uv": [0, 0, 16, 6], "texture": "#2_2"}, + "up": {"uv": [0, 0, 2, 16], "texture": "#8"}, + "down": {"uv": [0, 0, 16, 2], "rotation": 270, "texture": "#8"} + } + }, + { + "name": "LeftWall", + "from": [14, 4, 0], + "to": [16, 10, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 2]}, + "faces": { + "north": {"uv": [2, 0, 0, 6], "rotation": 180, "texture": "#2_2"}, + "east": {"uv": [0, 6, 16, 0], "rotation": 180, "texture": "#2_2"}, + "south": {"uv": [14, 0, 16, 6], "texture": "#2_2"}, + "up": {"uv": [14, 0, 16, 16], "texture": "#8"}, + "down": {"uv": [0, 14, 16, 16], "rotation": 270, "texture": "#8"} + } + }, + { + "name": "Top", + "from": [2, 4, 0], + "to": [14, 10, 2], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 2]}, + "faces": { + "north": {"uv": [2, 0, 14, 6], "texture": "#2_2"}, + "up": {"uv": [2, 0, 14, 2], "texture": "#8"}, + "down": {"uv": [0, 2, 2, 14], "rotation": 270, "texture": "#8"} + } + }, + { + "name": "Top", + "from": [2, 4, 14], + "to": [14, 10, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 18]}, + "faces": { + "south": {"uv": [14, 0, 2, 6], "texture": "#2_2"}, + "up": {"uv": [2, 16, 14, 14], "rotation": 180, "texture": "#8"}, + "down": {"uv": [14, 14, 16, 2], "rotation": 270, "texture": "#8"} + } + }, + { + "from": [1, 1, 1], + "to": [15, 4, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [7, -6, 10]}, + "faces": { + "north": {"uv": [1, 0, 15, 3], "texture": "#5"}, + "east": {"uv": [1, 0, 15, 3], "texture": "#5"}, + "south": {"uv": [1, 0, 15, 3], "texture": "#5"}, + "west": {"uv": [1, 0, 15, 3], "texture": "#5"}, + "down": {"uv": [2, 2, 14, 14], "rotation": 270, "texture": "#8"} + } + }, + { + "from": [1, 5, 2], + "to": [2, 10, 14], + "rotation": {"angle": 22.5, "axis": "z", "origin": [2, 10, 8]}, + "faces": { + "east": {"uv": [2, 2, 14, 7], "texture": "#9"} + } + }, + { + "from": [14, 5, 2], + "to": [15, 10, 14], + "rotation": {"angle": -22.5, "axis": "z", "origin": [14, 10, 8]}, + "faces": { + "west": {"uv": [2, 2, 14, 7], "texture": "#9"} + } + }, + { + "from": [2, 5, 14], + "to": [14, 10, 15], + "rotation": {"angle": 22.5, "axis": "x", "origin": [8, 10, 14]}, + "faces": { + "north": {"uv": [2, 2, 14, 7], "texture": "#9"} + } + }, + { + "from": [2, 5, 1], + "to": [14, 10, 2], + "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 10, 2]}, + "faces": { + "south": {"uv": [2, 2, 14, 7], "texture": "#9"} + } + }, + { + "from": [3, 5, 3], + "to": [13, 6, 13], + "rotation": {"angle": 0, "axis": "y", "origin": [11, 13, 11]}, + "faces": { + "up": {"uv": [3, 3, 13, 13], "texture": "#10"} + } + }, + { + "name": "Back", + "from": [1.95, -1.95, 1.95], + "to": [14.05, 2, 14.05], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0.025, 8]}, + "faces": { + "north": {"uv": [2, 12, 14, 16], "texture": "#9"}, + "east": {"uv": [2, 12, 14, 16], "texture": "#9"}, + "south": {"uv": [2, 12, 14, 16], "texture": "#9"}, + "west": {"uv": [2, 12, 14, 16], "texture": "#9"}, + "down": {"uv": [6, 8, 12, 14], "rotation": 180, "texture": "#3"} + } + }, + { + "name": "Back", + "from": [2.1, 2, 2.05], + "to": [13.9, 4.1, 13.1], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -6, 24.1]}, + "faces": { + "east": {"uv": [2.5, 1.5, 8, 0.5], "texture": "#5"}, + "west": {"uv": [2.5, 0.5, 8, 1.5], "rotation": 180, "texture": "#5"} + } + } + ], + "display": {}, + "groups": [ + { + "name": "block_retracted", + "origin": [8, 8, 8], + "children": [ + { + "name": "BeltFunnel", + "origin": [9, -4, 8], + "children": [ + { + "name": "FrontSection", + "origin": [9, -4, 8], + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + }, + { + "name": "Base", + "origin": [9, -4, 8], + "children": [10, 11] + } + ] + } + ] + }, + { + "name": "Item Filter", + "origin": [8, 0, 8], + "children": [12, 13, 14, 15] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/gantry_pinion/horizontal.json b/src/main/resources/assets/create/models/block/gantry_carriage/horizontal.json similarity index 100% rename from src/main/resources/assets/create/models/block/gantry_pinion/horizontal.json rename to src/main/resources/assets/create/models/block/gantry_carriage/horizontal.json diff --git a/src/main/resources/assets/create/models/block/gantry_pinion/item.json b/src/main/resources/assets/create/models/block/gantry_carriage/item.json similarity index 100% rename from src/main/resources/assets/create/models/block/gantry_pinion/item.json rename to src/main/resources/assets/create/models/block/gantry_carriage/item.json diff --git a/src/main/resources/assets/create/models/block/gantry_pinion/vertical.json b/src/main/resources/assets/create/models/block/gantry_carriage/vertical.json similarity index 100% rename from src/main/resources/assets/create/models/block/gantry_pinion/vertical.json rename to src/main/resources/assets/create/models/block/gantry_carriage/vertical.json diff --git a/src/main/resources/assets/create/models/block/gantry_pinion/wheels.json b/src/main/resources/assets/create/models/block/gantry_carriage/wheels.json similarity index 100% rename from src/main/resources/assets/create/models/block/gantry_pinion/wheels.json rename to src/main/resources/assets/create/models/block/gantry_carriage/wheels.json diff --git a/src/main/resources/assets/create/models/item/goggles.json b/src/main/resources/assets/create/models/block/goggles.json similarity index 86% rename from src/main/resources/assets/create/models/item/goggles.json rename to src/main/resources/assets/create/models/block/goggles.json index 5dbe10332..b91727c27 100644 --- a/src/main/resources/assets/create/models/item/goggles.json +++ b/src/main/resources/assets/create/models/block/goggles.json @@ -4,7 +4,7 @@ "textures": { "0": "create:block/brass_casing", "1": "block/black_stained_glass", - "2": "create:item/goggles", + "2": "create:item/goggles_model", "particle": "create:block/brass_casing" }, "elements": [ @@ -13,7 +13,7 @@ "from": [11, 7, 3], "to": [12, 8, 4], "faces": { - "north": {"uv": [11, 0, 12, 1], "texture": "#0"}, + "north": {"uv": [8, 1, 9, 2], "texture": "#0"}, "east": {"uv": [10, 0, 11, 1], "texture": "#0"}, "south": {"uv": [11, 8, 12, 9], "texture": "#0"}, "west": {"uv": [4, 0, 5, 1], "texture": "#0"}, @@ -26,7 +26,7 @@ "from": [4, 7, 3], "to": [5, 8, 4], "faces": { - "north": {"uv": [11, 0, 12, 1], "texture": "#0"}, + "north": {"uv": [14, 1, 15, 2], "texture": "#0"}, "east": {"uv": [10, 0, 11, 1], "texture": "#0"}, "south": {"uv": [11, 8, 12, 9], "texture": "#0"}, "west": {"uv": [4, 0, 5, 1], "texture": "#0"}, @@ -39,11 +39,11 @@ "from": [9, 8, 3], "to": [11, 9, 4], "faces": { - "north": {"uv": [7, 0, 9, 1], "texture": "#0"}, + "north": {"uv": [3, 1, 5, 2], "texture": "#0"}, "east": {"uv": [6, 0, 7, 1], "texture": "#0"}, "south": {"uv": [7, 0, 9, 1], "texture": "#0"}, "west": {"uv": [7, 0, 8, 1], "texture": "#0"}, - "up": {"uv": [7, 1, 9, 2], "texture": "#0"}, + "up": {"uv": [6, 1, 8, 2], "texture": "#0"}, "down": {"uv": [7, 0, 9, 1], "texture": "#0"} } }, @@ -52,7 +52,7 @@ "from": [7, 7, 3], "to": [9, 8, 4], "faces": { - "north": {"uv": [7, 0, 9, 1], "texture": "#0"}, + "north": {"uv": [7, 1, 9, 2], "texture": "#0"}, "east": {"uv": [6, 0, 7, 1], "texture": "#0"}, "south": {"uv": [7, 0, 9, 1], "texture": "#0"}, "west": {"uv": [7, 0, 8, 1], "texture": "#0"}, @@ -66,11 +66,11 @@ "to": [7, 9, 4], "rotation": {"angle": 0, "axis": "y", "origin": [4, 8, 8]}, "faces": { - "north": {"uv": [7, 0, 9, 1], "texture": "#0"}, + "north": {"uv": [10, 1, 12, 2], "texture": "#0"}, "east": {"uv": [6, 0, 7, 1], "texture": "#0"}, "south": {"uv": [7, 0, 9, 1], "texture": "#0"}, "west": {"uv": [7, 0, 8, 1], "texture": "#0"}, - "up": {"uv": [12, 1, 14, 2], "texture": "#0"}, + "up": {"uv": [10, 1, 12, 2], "texture": "#0"}, "down": {"uv": [7, 0, 9, 1], "texture": "#0"} } }, @@ -79,7 +79,7 @@ "from": [9, 6, 3], "to": [11, 7, 4], "faces": { - "north": {"uv": [7, 0, 9, 1], "texture": "#0"}, + "north": {"uv": [13, 14, 15, 15], "texture": "#0"}, "east": {"uv": [6, 0, 7, 1], "texture": "#0"}, "south": {"uv": [7, 0, 9, 1], "texture": "#0"}, "west": {"uv": [7, 0, 8, 1], "texture": "#0"}, @@ -93,7 +93,7 @@ "to": [7, 7, 4], "rotation": {"angle": 0, "axis": "y", "origin": [4, 8, 8]}, "faces": { - "north": {"uv": [7, 0, 9, 1], "texture": "#0"}, + "north": {"uv": [13, 14, 15, 15], "texture": "#0"}, "east": {"uv": [6, 0, 7, 1], "texture": "#0"}, "south": {"uv": [7, 0, 9, 1], "texture": "#0"}, "west": {"uv": [7, 0, 8, 1], "texture": "#0"}, @@ -103,8 +103,9 @@ }, { "name": "glass", - "from": [5, 7, 3.5], - "to": [11, 8, 3.5], + "from": [5, 7, 3.3], + "to": [11, 8, 3.3], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 7.8]}, "faces": { "north": {"uv": [1, 0, 7, 1], "texture": "#1"}, "east": {"uv": [11, 0, 11.2, 1], "texture": "#1"}, diff --git a/src/main/resources/assets/create/models/block/redstone_link/transmitter.json b/src/main/resources/assets/create/models/block/redstone_link/transmitter.json index 133eae26f..235a9a0e5 100644 --- a/src/main/resources/assets/create/models/block/redstone_link/transmitter.json +++ b/src/main/resources/assets/create/models/block/redstone_link/transmitter.json @@ -51,7 +51,13 @@ "display": { "gui": { "rotation": [30, 45, 0], + "translation": [0, 2.5, 0], "scale": [0.625, 0.625, 0.625] - } - } + }, + "fixed": { + "rotation": [ 270, 0, 0 ], + "translation": [ 0, 0, -3], + "scale":[ 0.5, 0.5, 0.5 ] + } + } } \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/sail_frame.json b/src/main/resources/assets/create/models/block/sail_frame.json index da4b090fe..6240b3aee 100644 --- a/src/main/resources/assets/create/models/block/sail_frame.json +++ b/src/main/resources/assets/create/models/block/sail_frame.json @@ -131,7 +131,7 @@ "scale": [0.25, 0.25, 0.25] }, "gui": { - "rotation": [30, 225, 0], + "rotation": [30, 315, -90], "scale": [0.625, 0.625, 0.625] }, "fixed": { diff --git a/src/main/resources/assets/create/models/block/sticker/block.json b/src/main/resources/assets/create/models/block/sticker/block.json new file mode 100644 index 000000000..1ece065f4 --- /dev/null +++ b/src/main/resources/assets/create/models/block/sticker/block.json @@ -0,0 +1,71 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "block/piston_bottom", + "1": "block/piston_inner", + "3": "create:block/sticker", + "4": "create:block/sticker_side", + "particle": "block/piston_bottom" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 8, 16], + "faces": { + "north": {"uv": [0, 8, 16, 16], "texture": "#4"}, + "east": {"uv": [0, 8, 16, 16], "texture": "#4"}, + "south": {"uv": [0, 8, 16, 16], "texture": "#4"}, + "west": {"uv": [0, 8, 16, 16], "texture": "#4"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#0"} + } + }, + { + "from": [0, 8, 0], + "to": [16, 16, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 16, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "east": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "south": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "west": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "up": {"uv": [0, 0, 8, 8], "texture": "#3"} + } + }, + { + "from": [0, 8, -0.95], + "to": [16, 16, 0.05], + "faces": { + "south": {"uv": [0, 0, 16, 8], "texture": "#4"} + } + }, + { + "from": [0, 8, 15.95], + "to": [16, 16, 16.95], + "faces": { + "north": {"uv": [0, 0, 16, 8], "texture": "#4"} + } + }, + { + "from": [15.95, 8, 0], + "to": [16.95, 16, 16], + "faces": { + "west": {"uv": [0, 0, 16, 8], "texture": "#4"} + } + }, + { + "from": [-0.95, 8, 0], + "to": [0.05, 16, 16], + "faces": { + "east": {"uv": [16, 0, 0, 8], "texture": "#4"} + } + } + ], + "groups": [ + { + "name": "Piston Block", + "origin": [8, 8, 8], + "children": [0, 1, 2, 3, 4, 5] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/sticker/block_powered.json b/src/main/resources/assets/create/models/block/sticker/block_powered.json new file mode 100644 index 000000000..ee3244b46 --- /dev/null +++ b/src/main/resources/assets/create/models/block/sticker/block_powered.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/sticker/block", + "textures": { + "4": "create:block/sticker_side_powered" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/sticker/head.json b/src/main/resources/assets/create/models/block/sticker/head.json new file mode 100644 index 000000000..b2b808c18 --- /dev/null +++ b/src/main/resources/assets/create/models/block/sticker/head.json @@ -0,0 +1,41 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "2": "block/piston_side", + "3": "create:block/sticker", + "particle": "block/piston_bottom" + }, + "elements": [ + { + "from": [1, 8, 1], + "to": [15, 13, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [9, 16, 9]}, + "faces": { + "north": {"uv": [8.5, 0, 15.5, 2.5], "texture": "#3"}, + "east": {"uv": [8.5, 0, 15.5, 2.5], "texture": "#3"}, + "south": {"uv": [8.5, 0, 15.5, 2.5], "texture": "#3"}, + "west": {"uv": [8.5, 0, 15.5, 2.5], "texture": "#3"}, + "up": {"uv": [8.5, 8.5, 15.5, 15.5], "texture": "#3"}, + "down": {"uv": [0.5, 8.5, 7.5, 15.5], "texture": "#3"} + } + }, + { + "from": [6, 3, 6], + "to": [10, 8, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 11, 14]}, + "faces": { + "north": {"uv": [0, 0, 5, 4], "rotation": 90, "texture": "#2"}, + "east": {"uv": [0, 0, 5, 4], "rotation": 90, "texture": "#2"}, + "south": {"uv": [0, 0, 5, 4], "rotation": 90, "texture": "#2"}, + "west": {"uv": [0, 0, 5, 4], "rotation": 90, "texture": "#2"} + } + } + ], + "groups": [ + { + "name": "Piston Head", + "origin": [14, 28, 14], + "children": [0, 1] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/sticker/item.json b/src/main/resources/assets/create/models/block/sticker/item.json new file mode 100644 index 000000000..c8c48ec47 --- /dev/null +++ b/src/main/resources/assets/create/models/block/sticker/item.json @@ -0,0 +1,104 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "0": "block/piston_bottom", + "1": "block/piston_inner", + "2": "block/piston_side", + "3": "create:block/sticker", + "4": "create:block/sticker_side", + "particle": "block/piston_bottom" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 8, 16], + "faces": { + "north": {"uv": [0, 8, 16, 16], "texture": "#4"}, + "east": {"uv": [0, 8, 16, 16], "texture": "#4"}, + "south": {"uv": [0, 8, 16, 16], "texture": "#4"}, + "west": {"uv": [0, 8, 16, 16], "texture": "#4"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#0"} + } + }, + { + "from": [0, 8, 0], + "to": [16, 16, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 16, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "east": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "south": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "west": {"uv": [0, 0, 16, 8], "texture": "#4"}, + "up": {"uv": [0, 0, 8, 8], "texture": "#3"} + } + }, + { + "from": [0, 8, -0.95], + "to": [16, 16, 0.05], + "faces": { + "south": {"uv": [0, 0, 16, 8], "texture": "#4"} + } + }, + { + "from": [0, 8, 15.95], + "to": [16, 16, 16.95], + "faces": { + "north": {"uv": [0, 0, 16, 8], "texture": "#4"} + } + }, + { + "from": [16, 8, 0.05], + "to": [17, 16, 16.05], + "rotation": {"angle": 0, "axis": "y", "origin": [9, 8, 8]}, + "faces": { + "west": {"uv": [0, 0, 16, 8], "texture": "#4"} + } + }, + { + "from": [-1, 8, -0.05], + "to": [0, 16, 15.95], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 8, 8]}, + "faces": { + "east": {"uv": [0, 0, 16, 8], "texture": "#4"} + } + }, + { + "from": [1, 9, 1], + "to": [15, 14, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [9, 17, 9]}, + "faces": { + "north": {"uv": [8.5, 0, 15.5, 2.5], "texture": "#3"}, + "east": {"uv": [8.5, 0, 15.5, 2.5], "texture": "#3"}, + "south": {"uv": [8.5, 0, 15.5, 2.5], "texture": "#3"}, + "west": {"uv": [8.5, 0, 15.5, 2.5], "texture": "#3"}, + "up": {"uv": [8.5, 8.5, 15.5, 15.5], "texture": "#3"}, + "down": {"uv": [0.5, 8.5, 7.5, 15.5], "texture": "#3"} + } + }, + { + "from": [6, 4, 6], + "to": [10, 9, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 12, 14]}, + "faces": { + "north": {"uv": [0, 0, 5, 4], "rotation": 90, "texture": "#2"}, + "east": {"uv": [0, 0, 5, 4], "rotation": 90, "texture": "#2"}, + "south": {"uv": [0, 0, 5, 4], "rotation": 90, "texture": "#2"}, + "west": {"uv": [0, 0, 5, 4], "rotation": 90, "texture": "#2"} + } + } + ], + "groups": [ + { + "name": "Piston Block", + "origin": [8, 8, 8], + "children": [0, 1, 2, 3, 4, 5] + }, + { + "name": "Piston Head", + "origin": [14, 28, 14], + "children": [6, 7] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/sticker/sticker.bbmodel b/src/main/resources/assets/create/models/block/sticker/sticker.bbmodel new file mode 100644 index 000000000..0a341360e --- /dev/null +++ b/src/main/resources/assets/create/models/block/sticker/sticker.bbmodel @@ -0,0 +1 @@ +{"meta":{"format_version":"3.6","creation_time":1614729493,"model_format":"java_block","box_uv":false},"name":"","parent":"","ambientocclusion":true,"front_gui_light":false,"visible_box":[1,1,0],"resolution":{"width":16,"height":16},"elements":[{"name":"cube","from":[0,0,0],"to":[16,8,16],"autouv":0,"color":6,"locked":false,"origin":[8,8,8],"faces":{"north":{"uv":[0,8,16,16],"texture":4},"east":{"uv":[0,8,16,16],"texture":4},"south":{"uv":[0,8,16,16],"texture":4},"west":{"uv":[0,8,16,16],"texture":4},"up":{"uv":[0,0,16,16],"texture":1},"down":{"uv":[0,0,16,16],"texture":0}},"uuid":"9189c687-ec3f-0483-bb94-8eb1610bb0f7"},{"name":"cube","from":[0,8,0],"to":[16,16,16],"autouv":0,"color":6,"locked":false,"origin":[8,16,8],"faces":{"north":{"uv":[0,0,16,8],"texture":4},"east":{"uv":[0,0,16,8],"texture":4},"south":{"uv":[0,0,16,8],"texture":4},"west":{"uv":[0,0,16,8],"texture":4},"up":{"uv":[0,0,8,8],"texture":3},"down":{"uv":[0,0,0,0],"texture":null}},"uuid":"c915a8a9-e0c7-0d13-5267-953429b366f5"},{"name":"cube","from":[1,12,1],"to":[15,17,15],"autouv":0,"color":1,"locked":false,"origin":[9,20,9],"faces":{"north":{"uv":[8.5,0,15.5,2.5],"texture":3},"east":{"uv":[8.5,0,15.5,2.5],"texture":3},"south":{"uv":[8.5,0,15.5,2.5],"texture":3},"west":{"uv":[8.5,0,15.5,2.5],"texture":3},"up":{"uv":[8.5,8.5,15.5,15.5],"texture":3},"down":{"uv":[0.5,8.5,7.5,15.5],"texture":3}},"uuid":"838bfc74-3754-755e-97b9-dc8f49cb4cc4"},{"name":"cube","from":[6,7,6],"to":[10,12,10],"autouv":0,"color":6,"locked":false,"origin":[14,15,14],"faces":{"north":{"uv":[0,0,5,4],"rotation":90,"texture":2},"east":{"uv":[0,0,5,4],"rotation":90,"texture":2},"south":{"uv":[0,0,5,4],"rotation":90,"texture":2},"west":{"uv":[0,0,5,4],"rotation":90,"texture":2},"up":{"uv":[0,0,4,4],"texture":null},"down":{"uv":[0,0,4,4],"texture":null}},"uuid":"e380ceaa-57a4-7e47-45d8-238ff048b7cd"}],"outliner":[{"name":"Piston Block","origin":[8,8,8],"uuid":"d35280bd-4aab-971b-e553-24b5af733d45","export":true,"isOpen":false,"locked":false,"visibility":true,"autouv":0,"children":["9189c687-ec3f-0483-bb94-8eb1610bb0f7","c915a8a9-e0c7-0d13-5267-953429b366f5"]},{"name":"Piston Head","origin":[14,28,14],"uuid":"6c824c11-53c5-d20a-8857-1867915ba892","export":true,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["838bfc74-3754-755e-97b9-dc8f49cb4cc4","e380ceaa-57a4-7e47-45d8-238ff048b7cd"]}],"textures":[{"path":"F:\\Create\\Attacher\\Sticker Textures\\piston_bottom.png","name":"piston_bottom.png","folder":"Sticker Textures","namespace":"","id":"0","particle":true,"visible":true,"mode":"bitmap","saved":true,"uuid":"fd815e7a-cd5f-a1d8-9ed5-64cee6940ea0","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABZUlEQVQ4T4VTsYqDQBRcm1RGqyMgyRVBAlbCGdsjET/Y0s6QxibcBwSrMwjhKo2Vjce8u9HVC9xrdnk7Ozvz3lsjjuNe/UZd17Lruk7WxWKhbNvm8Z8VeAME9nKp3vZ7ATRNIysOv+535e52wx75l9VKSC3LUlmWKSMMwz6KIkmQoLheZa+Dy7IUQuY3m81IEASBsPJVXASAAVUg1dUAUxTFj4LX9XoAAwTw++Gg2rYVS7w8V/l5uynD9/3e3W4n0ngJr0A2Vs/zBFNV1aB0QoCX8YJpmhMQlDCgiLUAaZ7nYxdI8KwLjuOInXkhJwSsuN7CZzm9kGIBc3A8HtXH5SJe2SrOBfIMXSUKWz8eIwFAJOGg6HMxby2wAwHmAAWceySR3krd4mDBdV1RCfmQjk6cT6eJJU4gcbCTpunYBRzQ91w6lbAetJMkyTiJ+txDMsda/xMo3NPPBBC+ML4v4r8vrGO+ARsXKQWAtEm4AAAAAElFTkSuQmCC"},{"path":"F:\\Create\\Attacher\\Sticker Textures\\piston_inner.png","name":"piston_inner.png","folder":"Sticker Textures","namespace":"","id":"1","particle":false,"visible":true,"mode":"bitmap","saved":true,"uuid":"b94d7326-7db9-4e58-dfb6-169b5ecac9fd","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABs0lEQVQ4T4VTsWoCQRR81wiCelW00QhyCFZK1MImqFj4E8HfEC0sRPE3JD9gaaeksZFgLYdgFCGmOhUUG8O85D3vYkK22b13s7PzZmeNSqVyoe/hOI4sdTZN86bmxhsgMINBesjluL7b7XgG2cf7O1nJpK5Rv4tECKShUIhGoxEZ+Xz+Ui6XuSAEstkNXq1WTCgksVjsSpDNZplVNgIkioTUns89akBu2/aXgvtoVPuEZIAfi0U6HA4kJ6PuVgnM23pNRjqdvliJBPeGAWmBQIDC4TD5/X4lXi6XvN5sNqpUCQqFws3mXq/ncb9er9NisVBFOHAymRDfgmVZ7AEGpD3VatRqtfjb5/Px3Gw2aTgceoxUAlyjOA4jq9UqdTodVXA6najdbtNzv+8xkluAglKpRK/TKW+AWZlMhrrdrqeFRqNBs9mMjURWoNTZ768EQIMESlKpFMXjcSU4Ho+03W75VmQAqwTIAZh/hkUSJydCnTul2gJMxEDSECBc48t4zGokfZJAwYEMpupb+Ct97jiLT6ghL4PB4JpENxCS3bGWfzDu18eE08/ns975f08YeMF8ApBNGgW9XdHyAAAAAElFTkSuQmCC"},{"path":"F:\\Create\\Attacher\\Sticker Textures\\piston_side.png","name":"piston_side.png","folder":"Sticker Textures","namespace":"","id":"2","particle":false,"visible":true,"mode":"bitmap","saved":true,"uuid":"db3f52e8-b2d3-9368-ac4d-62cc93c62134","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB0ElEQVQ4T4VSwWoaURQ9A8WmzTg2NNFENIIdEl0UIcZFFw2R+An5gf6BX+GfuHfpJijtQkiiELqx0iyMIlHTwowGEglMOc/c8U0J5G7evHvvnHvOeddot9tet9tFbHYGxgfrvToZxv43SE3Ps/bL+4JMJgOjWq16/X4fn0MXuJ062N6K+ADuzimk5icBvDM3cP7XRiqVglGpVLzJZILc5rXeg821N/i5KIC1k0Tfr909PKnvq7tPiEajMMrlssfE4/AHPlrrAZC5daDuptvBH/c+UHub+LqUWSqVFADDcRx1LhYLdYZCIUQiK0kBhOd+I5fLeXY6rWpbsRiSySRc18XvXk/dp+OxOrPZrOoZjUZqEPM3wyF8AHtvD5ZlwTTNQNPR8bE/eD6fYzAY+KCtVmspIRIOQwA4XeRwCvPxeBz6z8I2AECaolcovpQjYEACGRSLRXQuL33NnHBweKiYMC+hs6RHzmy2lEAAaZap9IOhG0qDJQjsA+TzeWWgGCQaKYl5ASED3R/1CmRg27Yq0DRS50t8bzYDkgRU+ghWr9dXr6Dr/p+6MBE/ZF9qtRqMQqHg7SYSappOWZzW5chySV+j0VgCsInry9VlvLa+es8/A5wUOjLC82gAAAAASUVORK5CYII="},{"path":"F:\\Create\\Attacher\\Sticker Textures\\sticker.png","name":"sticker.png","folder":"Sticker Textures","namespace":"","id":"3","particle":false,"visible":true,"mode":"bitmap","saved":true,"uuid":"d37f6ff6-f6ff-f4aa-4402-5bccef23d620","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADh0lEQVRYR+1XPUxTURQ+TQu8wiu00ECJCkaJxhgwymRAY4IDYTNGBxiMJG4OEBclcTJBFwODmwmGAQYd3AiLiTEqgwECLtVUtETTgi0t5UEf8sgz3ymneW35Tetgwlneve/de853v3v+nu35wBNzYnaWhl6M2ugA0n2707zY1ER3eu/bOl+2mYpaQh7Vty8NMS1MurZOozff2GxQdFDjYkX2Tk5Omg8/PCBfg4NBKKpCuqbzMhir9fpI14kUhSgUCVM4YNCjlsfU3NxsO9CpdzreyMiIGQwG6b36lty+TV4WD9vZiN/vp5HocMb7Vu0K1dfXU1dXV2EA9Pf3m4uLi3TO+428ioMBOFUPLbjaCMAaiz/xPKnFKKIbNBM5SdXV1dTX11cYAD09PSaMqompNEnRxCodu3CdACz7fcnRS7xucHCwMAD25Xk7LCqIDxwCOGTgkIH/m4FCFKO8GChEOc4LQD6bC7GXU7FUs/aGGOtMbqyRs6iUphKneX7GOZ2qcEWl/BwPeNLVDPO8GhIoQDUrT0ywcl9lyojTrXLZhKDMiiTjGg+/Gue4mmHcPdZhSiMi61R7BQ+1zWXCGE8RNCtoVIY6xlLVcPzZLfPjlJ+utpzlNWvJVFORNrrFiMznfszTieN11H53mPffe9dtoguKL0XJ2NgkR5Gd1NIyMowMNemJdExPLw+lALweuGGGfkVYKejfTXANofgSucsUutb7Kg2AT7uaoJWVGNX66tMqcFKwEwoH+R2+5QAAA1Ba665kAAADwTVAhPbaI172AzCAsRWAKIVBiDSo6APJodD3wBeSxnVHBqAUMv15ns431mUQAVDyXdiyXoG3ooZ+/p4jpbgsYx8DIOKmVARrI8sLlL4CaxQIAzAWX03tAt0Y4wkGsqNAfECcCy239RqsiPQ/q+SurOKueV8AQD/ACAN7AbDeNQyLD1hBbHsFOKHVB4Ru2SgMYC5gsp0ww4iSSTuAwQecxa5cBrKjQJwwvLTGeUGcUa5guyiQMMz2AWFBwME5c3wAAKwM7BWG20bB1omzo0B0ye+Yy+Uhb1U5O2XaB6xhyGGXlXhESanTzklqtzCEkyEZqWXlnBfwxDuIJKkcJ0QqRrqFw4Fua7rFxlOOmRxSdkzFhp76D1QVIkMntaSGtPUFzgWY45mTirPDENasxai1JkDRxAqD2C4K8i5Gu935v/72F6SUUT/55o1qAAAAAElFTkSuQmCC"},{"path":"F:\\Create\\Attacher\\Sticker Textures\\sticker_side.png","name":"sticker_side.png","folder":"Sticker Textures","namespace":"","id":"4","particle":false,"visible":true,"mode":"bitmap","saved":true,"uuid":"b6008321-379a-f043-b8b9-8285c50d2ce8","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACGElEQVQ4T5WSS2gTYRSFz2wCgUxSayeToqMRxyqEPDQmqEVtJAgKAdfuFFxLcdOFIqKLbkRcC3YhuHXXneKDGghJGwYC2o5IOjHNODU2j1VARu4t/zStQfSufube8537GOn+3G3Xsh08X3gp4T/i5o3rrqYqkF69WHA3N220fji49+jxP0Ee3r3jRvYrmJhQIRHpZ28L++QxEPHB/NO/Qp49mXeLhgGh4Q6qtSrelpZx9LCGs4kEbs3OjYSIcb/ULcxkTyEVS0Ei4uLSe56+3e4xZFQnwpnE4+My11+dvgBp7xIvXjrvEuTIgUlvJzTz128bIPG7Nx+4O2+Jo64wDKHiveI/AIa5xu0L+vHYCTeiKjwOBTm3bAefa5/YnQxojIR+bOeMDXsDi68/smAwGODalRleEp2YckvlmveXTJ+O4aA6ufuMva0BdF2HpmnodruoVCo4pIVZtG59R6FQ4Hez2eScPObj00vJZNJVFAXpdBrBYBCBQICLOp0OTNNkkRD3+31YlgXHttHp9eA4DqR8Pu+GZBn61BQDyH37pG12oiB4NBr1xPRNUVUUi8UdAH0IhUIsIPdSqYTLxgqMXxJaJ1PIZrPsTEaUp/d6o7ENyOVyWC6XmUoJPl29jshKFWuQED53BpFweFeX5uoqj+EBSCQg1Inowu/3Ix6PM5QWLIJqGZDJZFxxOp/Px3kxilc99CDwcM1vBi4whPcwgQ8AAAAASUVORK5CYII="},{"path":"F:\\Create\\Attacher\\Sticker Textures\\sticker_side_powered.png","name":"sticker_side_powered.png","folder":"Sticker Textures","namespace":"","id":"5","particle":false,"visible":true,"mode":"bitmap","saved":true,"uuid":"1c9b6770-8e6d-ef0b-3c7b-a3e4be8da6a6","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACNElEQVQ4T5WSTWgTYRCG3zU0EM2P/Vk2NQaRNo00mLQmESVoG81FTzl7U+hZxEsPFhE99CIiHgv2IHj11ptilTQQQlujQZO2iEmadtk0Nj8ohMavzJTd1hpEv9O338z7zDszK92fvC2Kqobnsy8l/Me5dfOGcCsypFcvZkWlomJzS8PUo8f/BHl4765w9sro61MgEel7YxvdtuMg4oPpp3+FzDyZFslMBrqGHSxnl/E2tYiBU25c9PsxcWeyI0Rvd+1bEePnz2HENwKJiHOJd9x9tdpgSCcnemUS9/TYOP965DKkw0Mcu3JJEOS0q9+YCfX8dX0DJJ5/857dGUPstIWDEEo+LP4DkFldYfs63es7I5yKzO3QocqbqoZc9gtXpwLUhn/Qs7/GkrqBudcLLGi1WohfG+ch0Yoplkhnjb8kEvLhpNL/+xrbWz9xwuuF2+1GvV7H51QKAy55z8G6hqvxON/L5TLHTL0WXr0UCASELMsIBoOw2+2wWq2cVKvVUM7lWKSLm80misUiNFVFrdGApmmQYrGYcNhsGBwaYgBVp9NWVSSWlvgeGR1Ft8djiOlNVhQkk8l9AD04HA4WSJUK5tNpLHz4hKwkMOE/i7FQCCvVKhcid+SiUCrtAaLRKBbTaaZSwLqzg3yhgJnMR6wd+YVn4QtwyTKcw8OGy9V8ntswAFRZh5AT3cUxiwUhnw/bXV08YP1QLgPC4bDQV2c2mzmut3K03ebvHyaTIST7B3N2AQhkNoSNVX+GAAAAAElFTkSuQmCC"}]} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/white_sail.json b/src/main/resources/assets/create/models/block/white_sail.json index 413810a92..dbeda7194 100644 --- a/src/main/resources/assets/create/models/block/white_sail.json +++ b/src/main/resources/assets/create/models/block/white_sail.json @@ -129,7 +129,7 @@ "scale": [0.25, 0.25, 0.25] }, "gui": { - "rotation": [30, 225, 0], + "rotation": [30, 315, -90], "scale": [0.625, 0.625, 0.625] }, "fixed": { diff --git a/src/main/resources/assets/create/shader/belt.vert b/src/main/resources/assets/create/shader/belt.vert deleted file mode 100644 index c150f012b..000000000 --- a/src/main/resources/assets/create/shader/belt.vert +++ /dev/null @@ -1,106 +0,0 @@ -#version 110 -#define PI 3.1415926538 - -attribute vec3 aPos; -attribute vec3 aNormal; -attribute vec2 aTexCoords; - -attribute vec3 aInstancePos; -attribute vec2 aLight; -attribute vec3 aNetworkTint; -attribute float aSpeed; -attribute float aOffset; -attribute vec3 aInstanceRot; -attribute vec2 aSourceTexture; -attribute vec4 aScrollTexture; -attribute float aScrollMult; - -varying vec2 TexCoords; -varying vec4 Color; -varying float Diffuse; -varying vec2 Light; - -#if defined(CONTRAPTION) -varying vec3 BoxCoord; - -uniform vec3 uLightBoxSize; -uniform vec3 uLightBoxMin; -uniform mat4 uModel; -#endif - -uniform float uTime; -uniform mat4 uViewProjection; -uniform int uDebug; - -uniform vec3 uCameraPos; -varying float FragDistance; - -mat4 rotate(vec3 axis, float angle) { - float s = sin(angle); - float c = cos(angle); - float oc = 1. - c; - - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., - 0., 0., 0., 1.); -} - -float diffuse(vec3 normal) { - float x = normal.x; - float y = normal.y; - float z = normal.z; - return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.); -} - -mat4 rotation(vec3 rot) { - return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x); -} - -mat4 localRotation() { - vec3 rot = fract(aInstanceRot / 360.) * PI * 2.; - return rotation(rot); -} - -void main() { - mat4 localRotation = localRotation(); - vec4 worldPos = localRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.); - - #ifdef CONTRAPTION - worldPos = uModel * worldPos; - mat4 normalMat = uModel * localRotation; - - BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; - FragDistance = length(worldPos.xyz); - #else - mat4 normalMat = localRotation; - - FragDistance = length(worldPos.xyz - uCameraPos); - #endif - - vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz; - - float scrollSize = aScrollTexture.w - aScrollTexture.y; - float scroll = fract(aSpeed * uTime / (36. * 16.) + aOffset) * scrollSize * aScrollMult; - - Diffuse = diffuse(norm); - TexCoords = aTexCoords - aSourceTexture + aScrollTexture.xy + vec2(0, scroll); - Light = aLight; - gl_Position = uViewProjection * worldPos; - - #ifdef CONTRAPTION - if (uDebug == 2) { - Color = vec4(norm, 1.); - } else { - Color = vec4(1.); - } - #else - if (uDebug == 1) { - Color = vec4(aNetworkTint, 1.); - } else if (uDebug == 2) { - Color = vec4(norm, 1.); - } else { - Color = vec4(1.); - } - #endif -} diff --git a/src/main/resources/assets/create/shader/contraption_actor.vert b/src/main/resources/assets/create/shader/contraption_actor.vert deleted file mode 100644 index 7dbae771c..000000000 --- a/src/main/resources/assets/create/shader/contraption_actor.vert +++ /dev/null @@ -1,88 +0,0 @@ -#version 110 -#define PI 3.1415926538 -// model data -attribute vec3 aPos; -attribute vec3 aNormal; -attribute vec2 aTexCoords; - -// instance data -attribute vec3 aInstancePos; -attribute vec2 aModelLight; -attribute float aOffset; -attribute vec3 aAxis; -attribute vec3 aInstanceRot; -attribute vec3 aRotationCenter; - - -varying float Diffuse; -varying vec2 TexCoords; -varying vec4 Color; -varying vec3 BoxCoord; -varying vec2 Light; - -uniform vec3 uLightBoxSize; -uniform vec3 uLightBoxMin; -uniform mat4 uModel; - -uniform float uTime; -uniform mat4 uViewProjection; -uniform int uDebug; - -uniform vec3 uCameraPos; -varying float FragDistance; - -mat4 rotate(vec3 axis, float angle) { - float s = sin(angle); - float c = cos(angle); - float oc = 1. - c; - - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., - 0., 0., 0., 1.); -} - -float diffuse(vec3 normal) { - float x = normal.x; - float y = normal.y; - float z = normal.z; - return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.); -} - -mat4 rotation(vec3 rot) { - return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x); -} - -mat4 kineticRotation() { - const float speed = -20.; - float degrees = aOffset + uTime * speed * -3./10.; - float angle = fract(degrees / 360.) * PI * 2.; - - return rotate(normalize(aAxis), angle); -} - -void main() { - mat4 kineticRotation = kineticRotation(); - vec4 localPos = kineticRotation * vec4(aPos - aRotationCenter, 1.) + vec4(aRotationCenter, 0.); - - vec3 rot = fract(aInstanceRot / 360.) * PI * 2.; - mat4 localRot = rotation(rot); - localPos = localRot * vec4(localPos.xyz - .5, 1.) + vec4(aInstancePos + .5, 0.); - - vec4 worldPos = uModel * localPos; - - vec3 norm = normalize(uModel * localRot * kineticRotation * vec4(aNormal, 0.)).xyz; - - BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; - Diffuse = diffuse(norm); - TexCoords = aTexCoords; - Light = aModelLight; - FragDistance = length(worldPos.xyz); - gl_Position = uViewProjection * worldPos; - - if (uDebug == 2) { - Color = vec4(norm, 1.); - } else { - Color = vec4(1.); - } -} \ No newline at end of file diff --git a/src/main/resources/assets/create/shader/rotating.vert b/src/main/resources/assets/create/shader/rotating.vert deleted file mode 100644 index a1f803139..000000000 --- a/src/main/resources/assets/create/shader/rotating.vert +++ /dev/null @@ -1,101 +0,0 @@ -#version 110 -#define PI 3.1415926538 -attribute vec3 aPos; -attribute vec3 aNormal; -attribute vec2 aTexCoords; - -attribute vec3 aInstancePos; -attribute vec2 aLight; -attribute vec3 aNetworkTint; -attribute float aSpeed; -attribute float aOffset; -attribute vec3 aAxis; - -varying vec2 TexCoords; -varying vec4 Color; -varying float Diffuse; -varying vec2 Light; - -#if defined(CONTRAPTION) -varying vec3 BoxCoord; - -uniform vec3 uLightBoxSize; -uniform vec3 uLightBoxMin; -uniform mat4 uModel; -#endif - -uniform float uTime; -uniform mat4 uViewProjection; -uniform int uDebug; - -uniform vec3 uCameraPos; -varying float FragDistance; - -mat4 rotate(vec3 axis, float angle) { - float s = sin(angle); - float c = cos(angle); - float oc = 1. - c; - - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., - 0., 0., 0., 1.); -} - -float diffuse(vec3 normal) { - float x = normal.x; - float y = normal.y; - float z = normal.z; - return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.); -} - -mat4 rotation(vec3 rot) { - return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x); -} - -mat4 kineticRotation() { - float degrees = aOffset + uTime * aSpeed * -3./10.; - float angle = fract(degrees / 360.) * PI * 2.; - - return rotate(aAxis, angle); -} - -void main() { - mat4 kineticRotation = kineticRotation(); - vec4 worldPos = kineticRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.); - - #ifdef CONTRAPTION - worldPos = uModel * worldPos; - mat4 normalMat = uModel * kineticRotation; - - BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; - FragDistance = length(worldPos.xyz); - #else - mat4 normalMat = kineticRotation; - - FragDistance = length(worldPos.xyz - uCameraPos); - #endif - - vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz; - - Diffuse = diffuse(norm); - TexCoords = aTexCoords; - Light = aLight; - gl_Position = uViewProjection * worldPos; - - #ifdef CONTRAPTION - if (uDebug == 2) { - Color = vec4(norm, 1.); - } else { - Color = vec4(1.); - } - #else - if (uDebug == 1) { - Color = vec4(aNetworkTint, 1.); - } else if (uDebug == 2) { - Color = vec4(norm, 1.); - } else { - Color = vec4(1.); - } - #endif -} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/linear_chassis_side_connected.png b/src/main/resources/assets/create/textures/block/linear_chassis_side_connected.png new file mode 100644 index 000000000..b1398a957 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/linear_chassis_side_connected.png differ diff --git a/src/main/resources/assets/create/textures/block/secondary_linear_chassis_side_connected.png b/src/main/resources/assets/create/textures/block/secondary_linear_chassis_side_connected.png new file mode 100644 index 000000000..2b9ab5f1d Binary files /dev/null and b/src/main/resources/assets/create/textures/block/secondary_linear_chassis_side_connected.png differ diff --git a/src/main/resources/assets/create/textures/block/sticker.png b/src/main/resources/assets/create/textures/block/sticker.png new file mode 100644 index 000000000..75429c8af Binary files /dev/null and b/src/main/resources/assets/create/textures/block/sticker.png differ diff --git a/src/main/resources/assets/create/textures/block/sticker_side.png b/src/main/resources/assets/create/textures/block/sticker_side.png new file mode 100644 index 000000000..4e82caf62 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/sticker_side.png differ diff --git a/src/main/resources/assets/create/textures/block/sticker_side_powered.png b/src/main/resources/assets/create/textures/block/sticker_side_powered.png new file mode 100644 index 000000000..04a2c1e23 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/sticker_side_powered.png differ diff --git a/src/main/resources/assets/create/textures/gui/icons.png b/src/main/resources/assets/create/textures/gui/icons.png index 499eccc38..c9d661aee 100644 Binary files a/src/main/resources/assets/create/textures/gui/icons.png and b/src/main/resources/assets/create/textures/gui/icons.png differ diff --git a/src/main/resources/assets/create/textures/gui/widgets.png b/src/main/resources/assets/create/textures/gui/widgets.png index 76be05990..22ec3d894 100644 Binary files a/src/main/resources/assets/create/textures/gui/widgets.png and b/src/main/resources/assets/create/textures/gui/widgets.png differ diff --git a/src/main/resources/assets/create/textures/item/builders_tea.png b/src/main/resources/assets/create/textures/item/builders_tea.png index 574284067..55870a490 100644 Binary files a/src/main/resources/assets/create/textures/item/builders_tea.png and b/src/main/resources/assets/create/textures/item/builders_tea.png differ diff --git a/src/main/resources/assets/create/textures/item/chocolate_glazed_berries.png b/src/main/resources/assets/create/textures/item/chocolate_glazed_berries.png new file mode 100644 index 000000000..29e0f3c16 Binary files /dev/null and b/src/main/resources/assets/create/textures/item/chocolate_glazed_berries.png differ diff --git a/src/main/resources/assets/create/textures/item/cinder_flour.png b/src/main/resources/assets/create/textures/item/cinder_flour.png index ed2e5d297..d5b757e94 100644 Binary files a/src/main/resources/assets/create/textures/item/cinder_flour.png and b/src/main/resources/assets/create/textures/item/cinder_flour.png differ diff --git a/src/main/resources/assets/create/textures/item/goggles.png b/src/main/resources/assets/create/textures/item/goggles.png index bf6467f88..278ad9090 100644 Binary files a/src/main/resources/assets/create/textures/item/goggles.png and b/src/main/resources/assets/create/textures/item/goggles.png differ diff --git a/src/main/resources/assets/create/textures/item/goggles_model.png b/src/main/resources/assets/create/textures/item/goggles_model.png new file mode 100644 index 000000000..bf6467f88 Binary files /dev/null and b/src/main/resources/assets/create/textures/item/goggles_model.png differ diff --git a/src/main/resources/assets/create/textures/item/honeyed_apple.png b/src/main/resources/assets/create/textures/item/honeyed_apple.png new file mode 100644 index 000000000..39311123e Binary files /dev/null and b/src/main/resources/assets/create/textures/item/honeyed_apple.png differ diff --git a/src/main/resources/assets/create/textures/item/sweet_roll.png b/src/main/resources/assets/create/textures/item/sweet_roll.png new file mode 100644 index 000000000..7fdf41754 Binary files /dev/null and b/src/main/resources/assets/create/textures/item/sweet_roll.png differ diff --git a/src/main/resources/assets/create/textures/ponder/chapter/basic_kinetics.png b/src/main/resources/assets/create/textures/ponder/chapter/basic_kinetics.png new file mode 100644 index 000000000..da70cc75a Binary files /dev/null and b/src/main/resources/assets/create/textures/ponder/chapter/basic_kinetics.png differ diff --git a/src/main/resources/assets/create/textures/ponder/tag/item_transfer.png b/src/main/resources/assets/create/textures/ponder/tag/item_transfer.png new file mode 100644 index 000000000..da70cc75a Binary files /dev/null and b/src/main/resources/assets/create/textures/ponder/tag/item_transfer.png differ diff --git a/src/main/resources/create.mixins.json b/src/main/resources/create.mixins.json index e9d682678..37137f8a6 100644 --- a/src/main/resources/create.mixins.json +++ b/src/main/resources/create.mixins.json @@ -4,12 +4,13 @@ "compatibilityLevel": "JAVA_8", "refmap": "create.refmap.json", "client": [ - "OnRemoveTileMixin", + "AddRemoveTileMixin", "ShaderCloseMixin", "CancelTileEntityRenderMixin", "LightUpdateMixin", "RenderHooksMixin", - "FogColorTrackerMixin" + "FogColorTrackerMixin", + "NetworkLightUpdateMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/ponder/adjustable_pulse_repeater.nbt b/src/main/resources/ponder/adjustable_pulse_repeater.nbt new file mode 100644 index 000000000..bac67f6a1 Binary files /dev/null and b/src/main/resources/ponder/adjustable_pulse_repeater.nbt differ diff --git a/src/main/resources/ponder/adjustable_repeater.nbt b/src/main/resources/ponder/adjustable_repeater.nbt new file mode 100644 index 000000000..feb341477 Binary files /dev/null and b/src/main/resources/ponder/adjustable_repeater.nbt differ diff --git a/src/main/resources/ponder/analog_lever.nbt b/src/main/resources/ponder/analog_lever.nbt new file mode 100644 index 000000000..07bfc5e29 Binary files /dev/null and b/src/main/resources/ponder/analog_lever.nbt differ diff --git a/src/main/resources/ponder/belt/connect.nbt b/src/main/resources/ponder/belt/connect.nbt new file mode 100644 index 000000000..b1009a9ce Binary files /dev/null and b/src/main/resources/ponder/belt/connect.nbt differ diff --git a/src/main/resources/ponder/belt/directions.nbt b/src/main/resources/ponder/belt/directions.nbt new file mode 100644 index 000000000..fde59d365 Binary files /dev/null and b/src/main/resources/ponder/belt/directions.nbt differ diff --git a/src/main/resources/ponder/belt/encasing.nbt b/src/main/resources/ponder/belt/encasing.nbt new file mode 100644 index 000000000..1ce0d762d Binary files /dev/null and b/src/main/resources/ponder/belt/encasing.nbt differ diff --git a/src/main/resources/ponder/belt/transport.nbt b/src/main/resources/ponder/belt/transport.nbt new file mode 100644 index 000000000..784df024a Binary files /dev/null and b/src/main/resources/ponder/belt/transport.nbt differ diff --git a/src/main/resources/ponder/cart_assembler/anchor.nbt b/src/main/resources/ponder/cart_assembler/anchor.nbt new file mode 100644 index 000000000..de8bc0bd1 Binary files /dev/null and b/src/main/resources/ponder/cart_assembler/anchor.nbt differ diff --git a/src/main/resources/ponder/cart_assembler/dual.nbt b/src/main/resources/ponder/cart_assembler/dual.nbt new file mode 100644 index 000000000..b7110b581 Binary files /dev/null and b/src/main/resources/ponder/cart_assembler/dual.nbt differ diff --git a/src/main/resources/ponder/cart_assembler/modes.nbt b/src/main/resources/ponder/cart_assembler/modes.nbt new file mode 100644 index 000000000..a287d78be Binary files /dev/null and b/src/main/resources/ponder/cart_assembler/modes.nbt differ diff --git a/src/main/resources/ponder/cart_assembler/rails.nbt b/src/main/resources/ponder/cart_assembler/rails.nbt new file mode 100644 index 000000000..783075672 Binary files /dev/null and b/src/main/resources/ponder/cart_assembler/rails.nbt differ diff --git a/src/main/resources/ponder/chain_drive/gearshift.nbt b/src/main/resources/ponder/chain_drive/gearshift.nbt new file mode 100644 index 000000000..f9176ac82 Binary files /dev/null and b/src/main/resources/ponder/chain_drive/gearshift.nbt differ diff --git a/src/main/resources/ponder/chain_drive/relay.nbt b/src/main/resources/ponder/chain_drive/relay.nbt new file mode 100644 index 000000000..94eba9f2b Binary files /dev/null and b/src/main/resources/ponder/chain_drive/relay.nbt differ diff --git a/src/main/resources/ponder/chassis/linear_attachment.nbt b/src/main/resources/ponder/chassis/linear_attachment.nbt new file mode 100644 index 000000000..f7ef01bc6 Binary files /dev/null and b/src/main/resources/ponder/chassis/linear_attachment.nbt differ diff --git a/src/main/resources/ponder/chassis/linear_group.nbt b/src/main/resources/ponder/chassis/linear_group.nbt new file mode 100644 index 000000000..cfde348fb Binary files /dev/null and b/src/main/resources/ponder/chassis/linear_group.nbt differ diff --git a/src/main/resources/ponder/chassis/radial.nbt b/src/main/resources/ponder/chassis/radial.nbt new file mode 100644 index 000000000..17413d4a1 Binary files /dev/null and b/src/main/resources/ponder/chassis/radial.nbt differ diff --git a/src/main/resources/ponder/clockwork_bearing.nbt b/src/main/resources/ponder/clockwork_bearing.nbt new file mode 100644 index 000000000..43b4c4f93 Binary files /dev/null and b/src/main/resources/ponder/clockwork_bearing.nbt differ diff --git a/src/main/resources/ponder/clutch.nbt b/src/main/resources/ponder/clutch.nbt new file mode 100644 index 000000000..351af5afb Binary files /dev/null and b/src/main/resources/ponder/clutch.nbt differ diff --git a/src/main/resources/ponder/cog/large.nbt b/src/main/resources/ponder/cog/large.nbt new file mode 100644 index 000000000..3f55bd447 Binary files /dev/null and b/src/main/resources/ponder/cog/large.nbt differ diff --git a/src/main/resources/ponder/cog/small.nbt b/src/main/resources/ponder/cog/small.nbt new file mode 100644 index 000000000..90e235e2c Binary files /dev/null and b/src/main/resources/ponder/cog/small.nbt differ diff --git a/src/main/resources/ponder/cog/speedup.nbt b/src/main/resources/ponder/cog/speedup.nbt new file mode 100644 index 000000000..2a5687aee Binary files /dev/null and b/src/main/resources/ponder/cog/speedup.nbt differ diff --git a/src/main/resources/ponder/creative_motor.nbt b/src/main/resources/ponder/creative_motor.nbt new file mode 100644 index 000000000..58a94c9d1 Binary files /dev/null and b/src/main/resources/ponder/creative_motor.nbt differ diff --git a/src/main/resources/ponder/debug/scene_1.nbt b/src/main/resources/ponder/debug/scene_1.nbt new file mode 100644 index 000000000..2252fa1c3 Binary files /dev/null and b/src/main/resources/ponder/debug/scene_1.nbt differ diff --git a/src/main/resources/ponder/debug/scene_2.nbt b/src/main/resources/ponder/debug/scene_2.nbt new file mode 100644 index 000000000..16f82250c Binary files /dev/null and b/src/main/resources/ponder/debug/scene_2.nbt differ diff --git a/src/main/resources/ponder/debug/scene_3.nbt b/src/main/resources/ponder/debug/scene_3.nbt new file mode 100644 index 000000000..aedc65d0e Binary files /dev/null and b/src/main/resources/ponder/debug/scene_3.nbt differ diff --git a/src/main/resources/ponder/debug/scene_4.nbt b/src/main/resources/ponder/debug/scene_4.nbt new file mode 100644 index 000000000..589150451 Binary files /dev/null and b/src/main/resources/ponder/debug/scene_4.nbt differ diff --git a/src/main/resources/ponder/debug/scene_5.nbt b/src/main/resources/ponder/debug/scene_5.nbt new file mode 100644 index 000000000..be49148df Binary files /dev/null and b/src/main/resources/ponder/debug/scene_5.nbt differ diff --git a/src/main/resources/ponder/debug/scene_6.nbt b/src/main/resources/ponder/debug/scene_6.nbt new file mode 100644 index 000000000..6a7f63510 Binary files /dev/null and b/src/main/resources/ponder/debug/scene_6.nbt differ diff --git a/src/main/resources/ponder/debug/scene_7.nbt b/src/main/resources/ponder/debug/scene_7.nbt new file mode 100644 index 000000000..d0b4f88f6 Binary files /dev/null and b/src/main/resources/ponder/debug/scene_7.nbt differ diff --git a/src/main/resources/ponder/debug/scene_8.nbt b/src/main/resources/ponder/debug/scene_8.nbt new file mode 100644 index 000000000..eb2a7ac88 Binary files /dev/null and b/src/main/resources/ponder/debug/scene_8.nbt differ diff --git a/src/main/resources/ponder/debug/scene_9.nbt b/src/main/resources/ponder/debug/scene_9.nbt new file mode 100644 index 000000000..e981d81ed Binary files /dev/null and b/src/main/resources/ponder/debug/scene_9.nbt differ diff --git a/src/main/resources/ponder/deployer/contraption.nbt b/src/main/resources/ponder/deployer/contraption.nbt new file mode 100644 index 000000000..e92a1a98b Binary files /dev/null and b/src/main/resources/ponder/deployer/contraption.nbt differ diff --git a/src/main/resources/ponder/deployer/filter.nbt b/src/main/resources/ponder/deployer/filter.nbt new file mode 100644 index 000000000..78fc6138e Binary files /dev/null and b/src/main/resources/ponder/deployer/filter.nbt differ diff --git a/src/main/resources/ponder/deployer/modes.nbt b/src/main/resources/ponder/deployer/modes.nbt new file mode 100644 index 000000000..da15f4de6 Binary files /dev/null and b/src/main/resources/ponder/deployer/modes.nbt differ diff --git a/src/main/resources/ponder/deployer/redstone.nbt b/src/main/resources/ponder/deployer/redstone.nbt new file mode 100644 index 000000000..ea260becc Binary files /dev/null and b/src/main/resources/ponder/deployer/redstone.nbt differ diff --git a/src/main/resources/ponder/fan/direction.nbt b/src/main/resources/ponder/fan/direction.nbt new file mode 100644 index 000000000..08e9d0236 Binary files /dev/null and b/src/main/resources/ponder/fan/direction.nbt differ diff --git a/src/main/resources/ponder/fan/processing.nbt b/src/main/resources/ponder/fan/processing.nbt new file mode 100644 index 000000000..00de4c3fe Binary files /dev/null and b/src/main/resources/ponder/fan/processing.nbt differ diff --git a/src/main/resources/ponder/fan/source.nbt b/src/main/resources/ponder/fan/source.nbt new file mode 100644 index 000000000..0c351c645 Binary files /dev/null and b/src/main/resources/ponder/fan/source.nbt differ diff --git a/src/main/resources/ponder/funnels/brass.nbt b/src/main/resources/ponder/funnels/brass.nbt new file mode 100644 index 000000000..f5dc748bc Binary files /dev/null and b/src/main/resources/ponder/funnels/brass.nbt differ diff --git a/src/main/resources/ponder/funnels/compat.nbt b/src/main/resources/ponder/funnels/compat.nbt new file mode 100644 index 000000000..73e10aa15 Binary files /dev/null and b/src/main/resources/ponder/funnels/compat.nbt differ diff --git a/src/main/resources/ponder/funnels/direction.nbt b/src/main/resources/ponder/funnels/direction.nbt new file mode 100644 index 000000000..b9f65898e Binary files /dev/null and b/src/main/resources/ponder/funnels/direction.nbt differ diff --git a/src/main/resources/ponder/funnels/intro.nbt b/src/main/resources/ponder/funnels/intro.nbt new file mode 100644 index 000000000..8f1f190f5 Binary files /dev/null and b/src/main/resources/ponder/funnels/intro.nbt differ diff --git a/src/main/resources/ponder/funnels/redstone.nbt b/src/main/resources/ponder/funnels/redstone.nbt new file mode 100644 index 000000000..f30d0417f Binary files /dev/null and b/src/main/resources/ponder/funnels/redstone.nbt differ diff --git a/src/main/resources/ponder/funnels/transposer.nbt b/src/main/resources/ponder/funnels/transposer.nbt new file mode 100644 index 000000000..fd13cd84c Binary files /dev/null and b/src/main/resources/ponder/funnels/transposer.nbt differ diff --git a/src/main/resources/ponder/furnace_engine.nbt b/src/main/resources/ponder/furnace_engine.nbt new file mode 100644 index 000000000..fe916ecc7 Binary files /dev/null and b/src/main/resources/ponder/furnace_engine.nbt differ diff --git a/src/main/resources/ponder/gantry/direction.nbt b/src/main/resources/ponder/gantry/direction.nbt new file mode 100644 index 000000000..689314cd0 Binary files /dev/null and b/src/main/resources/ponder/gantry/direction.nbt differ diff --git a/src/main/resources/ponder/gantry/intro.nbt b/src/main/resources/ponder/gantry/intro.nbt new file mode 100644 index 000000000..20f0b8c2d Binary files /dev/null and b/src/main/resources/ponder/gantry/intro.nbt differ diff --git a/src/main/resources/ponder/gantry/redstone.nbt b/src/main/resources/ponder/gantry/redstone.nbt new file mode 100644 index 000000000..856d89863 Binary files /dev/null and b/src/main/resources/ponder/gantry/redstone.nbt differ diff --git a/src/main/resources/ponder/gantry/subgantry.nbt b/src/main/resources/ponder/gantry/subgantry.nbt new file mode 100644 index 000000000..09302c0a5 Binary files /dev/null and b/src/main/resources/ponder/gantry/subgantry.nbt differ diff --git a/src/main/resources/ponder/gearbox.nbt b/src/main/resources/ponder/gearbox.nbt new file mode 100644 index 000000000..39e5c6cd5 Binary files /dev/null and b/src/main/resources/ponder/gearbox.nbt differ diff --git a/src/main/resources/ponder/gearshift.nbt b/src/main/resources/ponder/gearshift.nbt new file mode 100644 index 000000000..957cec183 Binary files /dev/null and b/src/main/resources/ponder/gearshift.nbt differ diff --git a/src/main/resources/ponder/hand_crank.nbt b/src/main/resources/ponder/hand_crank.nbt new file mode 100644 index 000000000..2057ec700 Binary files /dev/null and b/src/main/resources/ponder/hand_crank.nbt differ diff --git a/src/main/resources/ponder/harvester.nbt b/src/main/resources/ponder/harvester.nbt new file mode 100644 index 000000000..44b584700 Binary files /dev/null and b/src/main/resources/ponder/harvester.nbt differ diff --git a/src/main/resources/ponder/mechanical_bearing/anchor.nbt b/src/main/resources/ponder/mechanical_bearing/anchor.nbt new file mode 100644 index 000000000..3ae522be0 Binary files /dev/null and b/src/main/resources/ponder/mechanical_bearing/anchor.nbt differ diff --git a/src/main/resources/ponder/mechanical_bearing/modes.nbt b/src/main/resources/ponder/mechanical_bearing/modes.nbt new file mode 100644 index 000000000..a3e80f13f Binary files /dev/null and b/src/main/resources/ponder/mechanical_bearing/modes.nbt differ diff --git a/src/main/resources/ponder/mechanical_bearing/stabilized.nbt b/src/main/resources/ponder/mechanical_bearing/stabilized.nbt new file mode 100644 index 000000000..59ac0501c Binary files /dev/null and b/src/main/resources/ponder/mechanical_bearing/stabilized.nbt differ diff --git a/src/main/resources/ponder/mechanical_drill/breaker.nbt b/src/main/resources/ponder/mechanical_drill/breaker.nbt new file mode 100644 index 000000000..8d3766251 Binary files /dev/null and b/src/main/resources/ponder/mechanical_drill/breaker.nbt differ diff --git a/src/main/resources/ponder/mechanical_drill/contraption.nbt b/src/main/resources/ponder/mechanical_drill/contraption.nbt new file mode 100644 index 000000000..656173bcd Binary files /dev/null and b/src/main/resources/ponder/mechanical_drill/contraption.nbt differ diff --git a/src/main/resources/ponder/mechanical_piston/anchor.nbt b/src/main/resources/ponder/mechanical_piston/anchor.nbt new file mode 100644 index 000000000..7bbee5cc9 Binary files /dev/null and b/src/main/resources/ponder/mechanical_piston/anchor.nbt differ diff --git a/src/main/resources/ponder/mechanical_piston/modes.nbt b/src/main/resources/ponder/mechanical_piston/modes.nbt new file mode 100644 index 000000000..f9755f1ed Binary files /dev/null and b/src/main/resources/ponder/mechanical_piston/modes.nbt differ diff --git a/src/main/resources/ponder/mechanical_piston/piston_pole.nbt b/src/main/resources/ponder/mechanical_piston/piston_pole.nbt new file mode 100644 index 000000000..710f5930a Binary files /dev/null and b/src/main/resources/ponder/mechanical_piston/piston_pole.nbt differ diff --git a/src/main/resources/ponder/mechanical_saw/breaker.nbt b/src/main/resources/ponder/mechanical_saw/breaker.nbt new file mode 100644 index 000000000..f9d4b030c Binary files /dev/null and b/src/main/resources/ponder/mechanical_saw/breaker.nbt differ diff --git a/src/main/resources/ponder/mechanical_saw/contraption.nbt b/src/main/resources/ponder/mechanical_saw/contraption.nbt new file mode 100644 index 000000000..f8a1daa01 Binary files /dev/null and b/src/main/resources/ponder/mechanical_saw/contraption.nbt differ diff --git a/src/main/resources/ponder/mechanical_saw/processing.nbt b/src/main/resources/ponder/mechanical_saw/processing.nbt new file mode 100644 index 000000000..35d6a03f6 Binary files /dev/null and b/src/main/resources/ponder/mechanical_saw/processing.nbt differ diff --git a/src/main/resources/ponder/nixie_tube.nbt b/src/main/resources/ponder/nixie_tube.nbt new file mode 100644 index 000000000..7d858b35f Binary files /dev/null and b/src/main/resources/ponder/nixie_tube.nbt differ diff --git a/src/main/resources/ponder/plough.nbt b/src/main/resources/ponder/plough.nbt new file mode 100644 index 000000000..24f190e64 Binary files /dev/null and b/src/main/resources/ponder/plough.nbt differ diff --git a/src/main/resources/ponder/portable_interface/redstone.nbt b/src/main/resources/ponder/portable_interface/redstone.nbt new file mode 100644 index 000000000..799754288 Binary files /dev/null and b/src/main/resources/ponder/portable_interface/redstone.nbt differ diff --git a/src/main/resources/ponder/portable_interface/transfer.nbt b/src/main/resources/ponder/portable_interface/transfer.nbt new file mode 100644 index 000000000..a7d61c927 Binary files /dev/null and b/src/main/resources/ponder/portable_interface/transfer.nbt differ diff --git a/src/main/resources/ponder/powered_latch.nbt b/src/main/resources/ponder/powered_latch.nbt new file mode 100644 index 000000000..846de16e2 Binary files /dev/null and b/src/main/resources/ponder/powered_latch.nbt differ diff --git a/src/main/resources/ponder/powered_toggle_latch.nbt b/src/main/resources/ponder/powered_toggle_latch.nbt new file mode 100644 index 000000000..e17715e41 Binary files /dev/null and b/src/main/resources/ponder/powered_toggle_latch.nbt differ diff --git a/src/main/resources/ponder/pulse_repeater.nbt b/src/main/resources/ponder/pulse_repeater.nbt new file mode 100644 index 000000000..0da9edef3 Binary files /dev/null and b/src/main/resources/ponder/pulse_repeater.nbt differ diff --git a/src/main/resources/ponder/redstone_contact.nbt b/src/main/resources/ponder/redstone_contact.nbt new file mode 100644 index 000000000..73e656bba Binary files /dev/null and b/src/main/resources/ponder/redstone_contact.nbt differ diff --git a/src/main/resources/ponder/redstone_link.nbt b/src/main/resources/ponder/redstone_link.nbt new file mode 100644 index 000000000..6535d7930 Binary files /dev/null and b/src/main/resources/ponder/redstone_link.nbt differ diff --git a/src/main/resources/ponder/rope_pulley/anchor.nbt b/src/main/resources/ponder/rope_pulley/anchor.nbt new file mode 100644 index 000000000..2aa175277 Binary files /dev/null and b/src/main/resources/ponder/rope_pulley/anchor.nbt differ diff --git a/src/main/resources/ponder/rope_pulley/attachment.nbt b/src/main/resources/ponder/rope_pulley/attachment.nbt new file mode 100644 index 000000000..e61952ab2 Binary files /dev/null and b/src/main/resources/ponder/rope_pulley/attachment.nbt differ diff --git a/src/main/resources/ponder/rope_pulley/modes.nbt b/src/main/resources/ponder/rope_pulley/modes.nbt new file mode 100644 index 000000000..6da97dd80 Binary files /dev/null and b/src/main/resources/ponder/rope_pulley/modes.nbt differ diff --git a/src/main/resources/ponder/sequenced_gearshift.nbt b/src/main/resources/ponder/sequenced_gearshift.nbt new file mode 100644 index 000000000..3d91ad485 Binary files /dev/null and b/src/main/resources/ponder/sequenced_gearshift.nbt differ diff --git a/src/main/resources/ponder/shaft/encasing.nbt b/src/main/resources/ponder/shaft/encasing.nbt new file mode 100644 index 000000000..ab1fa5605 Binary files /dev/null and b/src/main/resources/ponder/shaft/encasing.nbt differ diff --git a/src/main/resources/ponder/shaft/relay.nbt b/src/main/resources/ponder/shaft/relay.nbt new file mode 100644 index 000000000..548effb1d Binary files /dev/null and b/src/main/resources/ponder/shaft/relay.nbt differ diff --git a/src/main/resources/ponder/speed_controller.nbt b/src/main/resources/ponder/speed_controller.nbt new file mode 100644 index 000000000..cd64ee59b Binary files /dev/null and b/src/main/resources/ponder/speed_controller.nbt differ diff --git a/src/main/resources/ponder/sticker.nbt b/src/main/resources/ponder/sticker.nbt new file mode 100644 index 000000000..92063f497 Binary files /dev/null and b/src/main/resources/ponder/sticker.nbt differ diff --git a/src/main/resources/ponder/super_glue.nbt b/src/main/resources/ponder/super_glue.nbt new file mode 100644 index 000000000..46f30a682 Binary files /dev/null and b/src/main/resources/ponder/super_glue.nbt differ diff --git a/src/main/resources/ponder/valve_handle.nbt b/src/main/resources/ponder/valve_handle.nbt new file mode 100644 index 000000000..fe6af755d Binary files /dev/null and b/src/main/resources/ponder/valve_handle.nbt differ diff --git a/src/main/resources/ponder/water_wheel.nbt b/src/main/resources/ponder/water_wheel.nbt new file mode 100644 index 000000000..8c45937dd Binary files /dev/null and b/src/main/resources/ponder/water_wheel.nbt differ diff --git a/src/main/resources/ponder/windmill_bearing/source.nbt b/src/main/resources/ponder/windmill_bearing/source.nbt new file mode 100644 index 000000000..7426cb759 Binary files /dev/null and b/src/main/resources/ponder/windmill_bearing/source.nbt differ diff --git a/src/main/resources/ponder/windmill_bearing/structure.nbt b/src/main/resources/ponder/windmill_bearing/structure.nbt new file mode 100644 index 000000000..431a49b09 Binary files /dev/null and b/src/main/resources/ponder/windmill_bearing/structure.nbt differ