mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-03-04 06:44:40 +01:00
Merge branch 'mc1.20.1/dev' into mc1.20.1/feature-dev
This commit is contained in:
commit
3af2403d5e
107 changed files with 2588 additions and 173 deletions
24
build.gradle
24
build.gradle
|
@ -177,6 +177,22 @@ repositories {
|
|||
name = "squiddev"
|
||||
url = "https://squiddev.cc/maven/"
|
||||
}
|
||||
maven {
|
||||
name = "ftb"
|
||||
url = "https://maven.saps.dev/releases"
|
||||
}
|
||||
maven {
|
||||
name = "architectury"
|
||||
url = "https://maven.architectury.dev/"
|
||||
}
|
||||
maven {
|
||||
url = "https://jm.gserv.me/repository/maven-public/"
|
||||
content {
|
||||
includeGroup "info.journeymap"
|
||||
includeGroup "mysticdrew"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
maven {
|
||||
url = 'https://www.cursemaven.com'
|
||||
|
@ -259,6 +275,14 @@ dependencies {
|
|||
// implementation fg.deobf("curse.maven:ic2-classic-242942:5555152")
|
||||
// implementation fg.deobf("curse.maven:druidcraft-340991:3101903")
|
||||
// implementation fg.deobf("com.railwayteam.railways:railways-1.19.2-1.6.4:all") { transitive = false }
|
||||
|
||||
implementation fg.deobf("dev.architectury:architectury-forge:9.1.12")
|
||||
implementation fg.deobf("dev.ftb.mods:ftb-chunks-forge:2001.3.1")
|
||||
implementation fg.deobf("dev.ftb.mods:ftb-teams-forge:2001.3.0")
|
||||
implementation fg.deobf("dev.ftb.mods:ftb-library-forge:2001.2.4")
|
||||
|
||||
implementation fg.deobf("curse.maven:journeymap-32274:5457831")
|
||||
// implementation fg.deobf("ignored:journeymap-1.20.1-5.10.1-forge")
|
||||
|
||||
// runtimeOnly fg.deobf("curse.maven:framedblocks-441647:5399211")
|
||||
// runtimeOnly fg.deobf("curse.maven:galosphere-631098:4574834")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.3560692 Create's Sequenced Assembly Recipes
|
||||
// 1.20.1 2024-10-09T12:24:59.2666858 Create's Sequenced Assembly Recipes
|
||||
dbaca5a5aa312f3bc7b826e51e665d32e798a5d7 data/create/recipes/sequenced_assembly/precision_mechanism.json
|
||||
dacafdb106304d183b00e21fb01517ac45eca800 data/create/recipes/sequenced_assembly/sturdy_sheet.json
|
||||
1274315b5c570722d6f5b2ed7f5e53fe01b6288a data/create/recipes/sequenced_assembly/track.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.3056283 Registrate Provider for create [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)]
|
||||
// 1.20.1 2024-09-03T11:32:11.6637155 Registrate Provider for create [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)]
|
||||
60bbdf92d2ac9824ea6144955c74043a6005f79d assets/create/blockstates/acacia_window.json
|
||||
6a67703c2697d81b7dc83e9d72a66f9c9ff08383 assets/create/blockstates/acacia_window_pane.json
|
||||
c3ae87b62e81d8e9476eccd793bb1548d74c66a1 assets/create/blockstates/adjustable_chain_gearshift.json
|
||||
|
@ -585,8 +585,8 @@ b0d8f08968763a5f74e5cd5644377a76a9f39753 assets/create/blockstates/yellow_toolbo
|
|||
fe8c497aacc641c2f01cec90bba9f19e59cc2ed2 assets/create/blockstates/yellow_valve_handle.json
|
||||
e819e93fdcbe9fd9c050a052d2718ff3b3539365 assets/create/blockstates/zinc_block.json
|
||||
64121dcb216381c83b4fe28aa361ea07c24c9ad0 assets/create/blockstates/zinc_ore.json
|
||||
d3d30a92e4f63e8acb6aa3e3358b6e8340aa8cc1 assets/create/lang/en_ud.json
|
||||
a50be2f8a02b0fdd2b5a8aae9cf8df1490015707 assets/create/lang/en_us.json
|
||||
1195fdc4fb51659c921e2bbe744a35107f787aa2 assets/create/lang/en_ud.json
|
||||
632d1aac7255fc0f4804f4df138ce9926134d2f9 assets/create/lang/en_us.json
|
||||
a97e1060e00ae701a02e39cd4ef8054cf345fac4 assets/create/models/block/acacia_window.json
|
||||
103e032c0b1a0a6a27c67da8c91179a564bd281c assets/create/models/block/acacia_window_pane_noside.json
|
||||
fb00b627abda76ad4fea867ca57dbfadd24fffa3 assets/create/models/block/acacia_window_pane_noside_alt.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.2861383 Create's Advancements
|
||||
// 1.20.1 2024-10-09T12:24:59.1794112 Create's Advancements
|
||||
2661a689fdcf729494f46e3c719f71c62e31582e data/create/advancements/andesite_alloy.json
|
||||
fa16c4afe0496edc3f157858a6e0ff177a1622ff data/create/advancements/andesite_casing.json
|
||||
5a694002d0a663bc869b09d15924a10c43dc522f data/create/advancements/anvil_plough.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.2891201 Create Train Hat Information
|
||||
// 1.20.1 2024-10-09T12:24:59.1824022 Create Train Hat Information
|
||||
be16d47aa64e673b1107a36ce06475016e316fca assets/minecraft/train_hat_info/axolotl.json
|
||||
b8ae6d9c8014439f4049622e0d6e79b9d6716260 assets/minecraft/train_hat_info/bat.json
|
||||
5053a6c9fb412dfac1bf17eb0f57f9fd314198e4 assets/minecraft/train_hat_info/bee.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.3630513 Create's Mechanical Crafting Recipes
|
||||
// 1.20.1 2024-10-09T12:24:59.2726698 Create's Mechanical Crafting Recipes
|
||||
f076d64d9f30709bed34775136c9241097b28aa9 data/create/recipes/mechanical_crafting/crushing_wheel.json
|
||||
694dca9dcff246bb7f560b3304fcc244c53217d5 data/create/recipes/mechanical_crafting/extendo_grip.json
|
||||
c03bc27f537e2d6531438bf58a17d977a7e16c7b data/create/recipes/mechanical_crafting/potato_cannon.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.358065 Create's Standard Recipes
|
||||
// 1.20.1 2024-10-09T12:24:59.2686824 Create's Standard Recipes
|
||||
a8cc4af26f6c7c45a9eef12e92af1452fe042454 data/create/advancements/recipes/combat/crafting/appliances/netherite_backtank.json
|
||||
2c2639c7b307ee7c7a4e97e5efebf496788998ad data/create/advancements/recipes/combat/crafting/appliances/netherite_backtank_from_netherite.json
|
||||
81dcf0cb1aa99e39bc7d1a386e07cad4cee7d8b9 data/create/advancements/recipes/combat/crafting/appliances/netherite_diving_boots.json
|
||||
|
@ -7,7 +7,7 @@ a8cc4af26f6c7c45a9eef12e92af1452fe042454 data/create/advancements/recipes/combat
|
|||
c1f2e6d1d955fb2d6d7ccc7a6d45d051bbcab315 data/create/advancements/recipes/combat/crafting/appliances/netherite_diving_helmet_from_netherite.json
|
||||
6418408e9fe53c03eae1e2b17b2229a548abc226 data/create/advancements/recipes/misc/blasting/copper_ingot_from_crushed.json
|
||||
d88c5c8b6751f389d9eea30acbd566c120e77705 data/create/advancements/recipes/misc/blasting/gold_ingot_from_crushed.json
|
||||
c5eabab1b28eaf8d83007b303480f12d8c319c4d data/create/advancements/recipes/misc/blasting/ingot_aluminum_compat_ic2.json
|
||||
ea97407030aed9f2da5720fe7f68dd0c87f68944 data/create/advancements/recipes/misc/blasting/ingot_aluminium_compat_ic2.json
|
||||
2532dd0af4124639c26525b6c4bbaf8059132903 data/create/advancements/recipes/misc/blasting/ingot_aluminum_compat_immersiveengineering.json
|
||||
6b62cf9551e30b3560349e8d905cd10b446a98fd data/create/advancements/recipes/misc/blasting/ingot_lead_compat_immersiveengineering.json
|
||||
4568168d851832c9eefd177c64a2de9c40e9954b data/create/advancements/recipes/misc/blasting/ingot_lead_compat_mekanism.json
|
||||
|
@ -217,7 +217,7 @@ bb87cb8787644e20b3418d6f57726f2ca70b0aae data/create/advancements/recipes/misc/s
|
|||
70342b3f5c5482caa82e0afcd559c7b200d9f247 data/create/advancements/recipes/misc/smelting/glass_pane_from_tiled_glass_pane.json
|
||||
8635e2becb91b0e4e754fd79d231300492b8afce data/create/advancements/recipes/misc/smelting/glass_pane_from_vertical_framed_glass_pane.json
|
||||
d76d08c3efcf9174ee2980796aa04c67fe9443eb data/create/advancements/recipes/misc/smelting/gold_ingot_from_crushed.json
|
||||
6a53b4a956a5560dfa7a6ed3d3279fe502a45574 data/create/advancements/recipes/misc/smelting/ingot_aluminum_compat_ic2.json
|
||||
5e222928aadd0a91f9996b0a104ec4b80646058c data/create/advancements/recipes/misc/smelting/ingot_aluminium_compat_ic2.json
|
||||
1e88edf27ed1f83031f9d71cad8f3f4388f57b85 data/create/advancements/recipes/misc/smelting/ingot_aluminum_compat_immersiveengineering.json
|
||||
2b6b739a2f0ad1f33db8090aa0e77c8149d67dbf data/create/advancements/recipes/misc/smelting/ingot_lead_compat_immersiveengineering.json
|
||||
7392d585e5409438f70ddb43ebba58b35609265b data/create/advancements/recipes/misc/smelting/ingot_lead_compat_mekanism.json
|
||||
|
@ -246,7 +246,7 @@ b8d5ef1eba4521441658d4c051861ecf9cc96102 data/create/advancements/recipes/misc/s
|
|||
42f1375bf3004cfd891a5fbb05352f578636dd75 data/create/advancements/recipes/misc/smoking/bread.json
|
||||
3c9dcf347eef42d0cca69ae5bc4a61fe90fb27c8 data/create/recipes/blasting/copper_ingot_from_crushed.json
|
||||
cbd86c583643e65a0d9b7950dcf593cdf6d43d77 data/create/recipes/blasting/gold_ingot_from_crushed.json
|
||||
053d94339f3b64e02b0eae56fe714b6f4a05986f data/create/recipes/blasting/ingot_aluminum_compat_ic2.json
|
||||
4dccb0aaf5316c75f4dd03b497fb43bf20f7e279 data/create/recipes/blasting/ingot_aluminium_compat_ic2.json
|
||||
5b1b7981636b211a956e37356423c2ba65c8042c data/create/recipes/blasting/ingot_aluminum_compat_immersiveengineering.json
|
||||
f794d2eab3922ea7765866d473eb61c74a2678c5 data/create/recipes/blasting/ingot_lead_compat_immersiveengineering.json
|
||||
7acb7c5bc88b238e914abc07f979c33f8d33123e data/create/recipes/blasting/ingot_lead_compat_mekanism.json
|
||||
|
@ -451,7 +451,7 @@ d849fafedd10c68e6bc6dc1e5a85be82aae1b139 data/create/recipes/crafting/palettes/s
|
|||
9a687ee9dab44c439ab669aa596117064fb13457 data/create/recipes/crafting/schematics/schematicannon.json
|
||||
4a20356c9ce01ebfbcacbdc5d3c31094a5599a17 data/create/recipes/crafting/schematics/schematic_and_quill.json
|
||||
4a297162a630b48407dbc8ff8ca713387dcd3206 data/create/recipes/crafting/schematics/schematic_table.json
|
||||
dd2b5bfb7ebd836e8b5639894736c226f2cac8c0 data/create/recipes/crafting/tree_fertilizer.json
|
||||
2cf06129b47d1a2b733619514dc9e8cf1d8967f2 data/create/recipes/crafting/tree_fertilizer.json
|
||||
78526658ca5ccaa3729c967b5283069945d183b7 data/create/recipes/smelting/bread.json
|
||||
04bb0c80f3b5a6fe86fc4a8ed5293fc74c2d9aba data/create/recipes/smelting/copper_ingot_from_crushed.json
|
||||
d5b29fa27977691c3c50eb36c28bfe33b8462d09 data/create/recipes/smelting/glass_from_framed_glass.json
|
||||
|
@ -463,7 +463,7 @@ ab1a181eb787f501ae7b8a8c6da2d3adb35a8f2b data/create/recipes/smelting/glass_pane
|
|||
ad412d18c2084dc74fff8a079a2e7ffb20f9a0c6 data/create/recipes/smelting/glass_pane_from_tiled_glass_pane.json
|
||||
67c1143c7aac88a9cc91b98dbca60770cb1422a5 data/create/recipes/smelting/glass_pane_from_vertical_framed_glass_pane.json
|
||||
461e4dede50a4a318281ae9c086c8094470e21a1 data/create/recipes/smelting/gold_ingot_from_crushed.json
|
||||
ae05209f9f639c7709bb25d0ff5f09f1af6cffcf data/create/recipes/smelting/ingot_aluminum_compat_ic2.json
|
||||
0ceeee303ca8993c394fc597cdd7c5ef44d84ad0 data/create/recipes/smelting/ingot_aluminium_compat_ic2.json
|
||||
fa0d3d6f50d344aa83ddf4ac8abf4a80deb9fb32 data/create/recipes/smelting/ingot_aluminum_compat_immersiveengineering.json
|
||||
4e8cf8775719219849b1a0e95903a3605b665015 data/create/recipes/smelting/ingot_lead_compat_immersiveengineering.json
|
||||
cfa90e7ba56d1ec6caa11bd019244bddd51da841 data/create/recipes/smelting/ingot_lead_compat_mekanism.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.3560692 Create's Damage Type Tags
|
||||
// 1.20.1 2024-10-09T12:24:59.2656887 Create's Damage Type Tags
|
||||
7884716b2f4bb1330ff215366bb4bab06e4728c2 data/minecraft/tags/damage_type/bypasses_armor.json
|
||||
1fcad1f89265fba8bdb05b03a1dfcc88d7b7a550 data/minecraft/tags/damage_type/is_explosion.json
|
||||
08324c61115b72bb8a6370d7f34d84d9a31afd16 data/minecraft/tags/damage_type/is_fire.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.2901169 Create's Processing Recipes
|
||||
// 1.20.1 2024-10-09T12:24:59.1833995 Create's Processing Recipes
|
||||
3c94326fb730f68c1e44fe1e2ef09c9db6ffd92b data/create/recipes/compacting/andesite_from_flint.json
|
||||
8d3d5b31f3601b9f681ff710e0545a483a1494c6 data/create/recipes/compacting/blaze_cake.json
|
||||
8bd7f4e3a686ab520b2d55594d2018d0e9a50c91 data/create/recipes/compacting/chocolate.json
|
||||
|
@ -792,22 +792,22 @@ e383106ff8f877b5995e20c03af5e41e3db541d9 data/create/recipes/milling/compat/biom
|
|||
213e079f32baa2879702b72bdf08f146877a0bb9 data/create/recipes/milling/compat/biomesoplenty/violet.json
|
||||
b3f041e005491582f055da15871891357908d998 data/create/recipes/milling/compat/biomesoplenty/wildflower.json
|
||||
d08c4fcebb79e2e02ac9cb4623124332a05ed661 data/create/recipes/milling/compat/biomesoplenty/wilted_lily.json
|
||||
ca03746c39143de7867aeab2fb450fe0a67b69e3 data/create/recipes/milling/compat/botania/black_petal.json
|
||||
3192777eeb363a55174a0eb58197ee686b2e02c7 data/create/recipes/milling/compat/botania/blue_petal.json
|
||||
ee99c9bdcc4da8d160fc762ce7b394848d6a86d1 data/create/recipes/milling/compat/botania/brown_petal.json
|
||||
1d8dab24913945268f819c24e132d8bb74f792c2 data/create/recipes/milling/compat/botania/cyan_petal.json
|
||||
010a111f9810f142315bc94dfb1be03ee02508c4 data/create/recipes/milling/compat/botania/gray_petal.json
|
||||
dee8b4c26d6b78aceeb8e5a264693dad4e81dbcb data/create/recipes/milling/compat/botania/green_petal.json
|
||||
285a24e440d6a8cf34f2925a3eed7fa1d16e102b data/create/recipes/milling/compat/botania/light_blue_petal.json
|
||||
3cc232966240394aaf5a3a5d16a3ceebd41597a0 data/create/recipes/milling/compat/botania/light_gray_petal.json
|
||||
1225119a7dc1f69dfaf2cec32a0267b1d47ef72d data/create/recipes/milling/compat/botania/lime_petal.json
|
||||
09e114685483329a78c3cecf8b312f16d26cd981 data/create/recipes/milling/compat/botania/magenta_petal.json
|
||||
ae3e7eb55dda1846b8fd849ea1c8f1cbd37b9fca data/create/recipes/milling/compat/botania/orange_petal.json
|
||||
bf13e9807a96efc1ef684f0129cc21110e44cc4c data/create/recipes/milling/compat/botania/pink_petal.json
|
||||
7e0a167201b9c915579ede71ee7128bccdeee9c2 data/create/recipes/milling/compat/botania/purple_petal.json
|
||||
4e7c1ae95f10bb3466dd542a2e04c726c599ecd9 data/create/recipes/milling/compat/botania/red_petal.json
|
||||
28cbeb278022b2ac62cae2f3deaa65cb375c6456 data/create/recipes/milling/compat/botania/white_petal.json
|
||||
dd1e35234c419b1576410a2590fd33d88c8bb9bd data/create/recipes/milling/compat/botania/yellow_petal.json
|
||||
4994095300eabfe98a86036e7fbba6c12cddb078 data/create/recipes/milling/compat/botania/black_petal.json
|
||||
3516555e62ce7d6f0b5a57375339e69b4de41f83 data/create/recipes/milling/compat/botania/blue_petal.json
|
||||
deb37dcb4b323590fbb76f21732e5b9016028f7d data/create/recipes/milling/compat/botania/brown_petal.json
|
||||
d831337c28b89ce25a2be50e06719ab3be9400b6 data/create/recipes/milling/compat/botania/cyan_petal.json
|
||||
1ec99d5ee65becc6c921827956e26f286398b1ba data/create/recipes/milling/compat/botania/gray_petal.json
|
||||
7bcbd91fae49452fe30966b350c6830ad5bb588c data/create/recipes/milling/compat/botania/green_petal.json
|
||||
5819b1ff0c54851d4bf7c60228ce2e31b8d8ffee data/create/recipes/milling/compat/botania/light_blue_petal.json
|
||||
94b6cb826923907527c57e079d08fb410720b008 data/create/recipes/milling/compat/botania/light_gray_petal.json
|
||||
4fe3b309902b0d59971d351d6e4a8066908df195 data/create/recipes/milling/compat/botania/lime_petal.json
|
||||
b8f8ea5d52ae9cbdd59d60aabbac660859190855 data/create/recipes/milling/compat/botania/magenta_petal.json
|
||||
eab4d51ba92d5a2f172de76bca72cf2746359b68 data/create/recipes/milling/compat/botania/orange_petal.json
|
||||
c8cf3978e3bf0ffeccd18c1b16ea26c5e1c18634 data/create/recipes/milling/compat/botania/pink_petal.json
|
||||
9ee958eb5fb176902255aa606517a362670f3d60 data/create/recipes/milling/compat/botania/purple_petal.json
|
||||
3239b0a1ef91f61ab32f42ac3935ee99316089c5 data/create/recipes/milling/compat/botania/red_petal.json
|
||||
15afbebf247ea66e0b023ea84aa5c5dad8ac8466 data/create/recipes/milling/compat/botania/white_petal.json
|
||||
9c500a9d6cadb4f673ca63de38c1d3713dab061c data/create/recipes/milling/compat/botania/yellow_petal.json
|
||||
c7d2b07396448628123b81e1f34a8b131aa99c83 data/create/recipes/milling/compat/buzzier_bees/buttercup.json
|
||||
0c4a3c7da1e151868740db2037504e35a02af3d0 data/create/recipes/milling/compat/buzzier_bees/pink_clover.json
|
||||
355e89a3e003ae65ff06a9277c05699220eec569 data/create/recipes/milling/compat/buzzier_bees/white_clover.json
|
||||
|
@ -1033,7 +1033,7 @@ e3f12ec5d449caa54ebe1c453a89373492b8f48a data/create/recipes/splashing/endergeti
|
|||
64535aaa3a5d4b98791337b1a8ce50ad3d39a8ac data/create/recipes/splashing/gravel.json
|
||||
dd9508767f68cc8b5cc2f642690961e0c22c9985 data/create/recipes/splashing/gray_concrete_powder.json
|
||||
8908b452e6bc1290ebb8cfefc2c066460de93bff data/create/recipes/splashing/green_concrete_powder.json
|
||||
869a639fd7069495693fd2106165b57ce674201b data/create/recipes/splashing/ic2/crushed_raw_aluminum.json
|
||||
9764857ea6ee8d31ec37e6022f89dbe662e88591 data/create/recipes/splashing/ic2/crushed_raw_aluminum.json
|
||||
6fd01478f838507f9e0daf7eb0a19e8315e03cb8 data/create/recipes/splashing/ic2/crushed_raw_silver.json
|
||||
b5a0a0fc79bf310965aa16e78044b3f6a8a9998f data/create/recipes/splashing/ic2/crushed_raw_tin.json
|
||||
00b8d0c2577cc36da1c862234b61fb7d1cfe3e65 data/create/recipes/splashing/ic2/crushed_raw_uranium.json
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.3041196 Create's Custom Sounds
|
||||
// 1.20.1 2024-10-09T12:24:59.2018604 Create's Custom Sounds
|
||||
bcfd9320f8ed54f3282b1757a41da0d1753e1754 assets/create/sounds.json
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.3550723 Create's Recipe Serializer Tags
|
||||
// 1.20.1 2024-10-09T12:24:59.2646915 Create's Recipe Serializer Tags
|
||||
0d8718f7383761bc5d7bc45306ed266ebf25dc1d data/create/tags/recipe_serializer/automation_ignore.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-09-02T22:36:27.3570669 Create's Generated Registry Entries
|
||||
// 1.20.1 2024-10-09T12:24:59.2666858 Create's Generated Registry Entries
|
||||
030ede1044384c4117ac1e491bf5c78bbd2842f5 data/create/damage_type/crush.json
|
||||
92b0416950ffeb3ba68811e587177c2f8811c2c5 data/create/damage_type/cuckoo_surprise.json
|
||||
d2a4fdb64f4ba817e13a7b20c73fd1ca34b825fc data/create/damage_type/fan_fire.json
|
||||
|
|
|
@ -2460,6 +2460,7 @@
|
|||
"create.station.remove_auto_schedule": "ǝןnpǝɥɔS-oʇnⱯ pɹɐɔsıᗡ",
|
||||
"create.station.remove_schedule": "ǝןnpǝɥɔS ǝʌǝıɹʇǝᴚ",
|
||||
"create.station.retry": "ʎɹʇǝɹ puɐ sıɥʇ ǝʌןosǝᴚ",
|
||||
"create.station.train_map_color": "sdɐW uo ɹoןoƆ",
|
||||
"create.station.train_not_aligned": "'ǝןqɯǝssɐsıp ʇouuɐƆ",
|
||||
"create.station.train_not_aligned_1": "pǝubıןɐ sǝbɐıɹɹɐɔ ןןɐ ʇou",
|
||||
"create.subtitle.blaze_munch": "sǝɥɔunɯ ɹǝuɹnᗺ ǝzɐןᗺ",
|
||||
|
@ -2631,6 +2632,21 @@
|
|||
"create.train_assembly.sideways_controls": "sʎɐʍǝpıs ǝɔɐɟ ʇouuɐɔ sןoɹʇuoƆ uıɐɹ⟘",
|
||||
"create.train_assembly.single_bogey_carriage": "uʍo sʇı uo ǝbɐıɹɹɐɔ ɐ ʇɹoddns ʇouuɐɔ ǝdʎʇ ʎǝboᗺ sıɥ⟘",
|
||||
"create.train_assembly.too_many_bogeys": "%1$s :pǝɥɔɐʇʇɐ sʎǝboᗺ ʎuɐɯ oo⟘",
|
||||
"create.train_map.cannot_traverse_section": "ǝsɹǝʌɐɹʇ ʎןןnɟ ʇouuɐƆ ",
|
||||
"create.train_map.conductor_missing": "buıssıW ɹoʇɔnpuoƆ >¡< ",
|
||||
"create.train_map.derailed": "pǝןıɐɹǝᗡ >¡< ",
|
||||
"create.train_map.for_other_train": "%1$s ɹoɟ ",
|
||||
"create.train_map.fuel_boosted": "✔ pǝʇsooq ןǝnℲ ",
|
||||
"create.train_map.navigation_failed": "pǝןıɐℲ uoıʇɐbıʌɐN >¡< ",
|
||||
"create.train_map.player_controlled": "ɹǝʎɐןԀ ʎq pǝןןoɹʇuoƆ >- ",
|
||||
"create.train_map.redstone_powered": "pǝɹǝʍoԀ ǝuoʇspǝᴚ ",
|
||||
"create.train_map.schedule_interrupted": "pǝʇdnɹɹǝʇuI ǝןnpǝɥɔS >¡< ",
|
||||
"create.train_map.section_reserved": "pǝʌɹǝsǝɹ uoıʇɔǝS ",
|
||||
"create.train_map.toggle": "ʎɐןɹǝʌo ʞɹoʍʇǝu uıɐɹ⟘",
|
||||
"create.train_map.train_at_station": "%1$s |> ",
|
||||
"create.train_map.train_moving_to_station": ")ɯ%2$s( %1$s >> ",
|
||||
"create.train_map.train_owned_by": "%1$s ʎq",
|
||||
"create.train_map.waiting_at_signal": "ןɐubıS ʇɐ buıʇıɐM ",
|
||||
"create.tunnel.selection_mode.forced_round_robin": "uıqoᴚ punoᴚ pǝɔɹoℲ",
|
||||
"create.tunnel.selection_mode.forced_split": "ʇıןdS pǝɔɹoℲ",
|
||||
"create.tunnel.selection_mode.prefer_nearest": "ʇsǝɹɐǝN ɹǝɟǝɹԀ",
|
||||
|
|
|
@ -2460,6 +2460,7 @@
|
|||
"create.station.remove_auto_schedule": "Discard Auto-Schedule",
|
||||
"create.station.remove_schedule": "Retrieve Schedule",
|
||||
"create.station.retry": "Resolve this and retry",
|
||||
"create.station.train_map_color": "Color on Maps",
|
||||
"create.station.train_not_aligned": "Cannot disassemble,",
|
||||
"create.station.train_not_aligned_1": "not all carriages aligned",
|
||||
"create.subtitle.blaze_munch": "Blaze Burner munches",
|
||||
|
@ -2631,6 +2632,21 @@
|
|||
"create.train_assembly.sideways_controls": "Train Controls cannot face sideways",
|
||||
"create.train_assembly.single_bogey_carriage": "This Bogey type cannot support a carriage on its own",
|
||||
"create.train_assembly.too_many_bogeys": "Too many Bogeys attached: %1$s",
|
||||
"create.train_map.cannot_traverse_section": " Cannot fully traverse",
|
||||
"create.train_map.conductor_missing": " <!> Conductor Missing",
|
||||
"create.train_map.derailed": " <!> Derailed",
|
||||
"create.train_map.for_other_train": " for %1$s",
|
||||
"create.train_map.fuel_boosted": " Fuel boosted ✔",
|
||||
"create.train_map.navigation_failed": " <!> Navigation Failed",
|
||||
"create.train_map.player_controlled": " -> Controlled by Player",
|
||||
"create.train_map.redstone_powered": " Redstone Powered",
|
||||
"create.train_map.schedule_interrupted": " <!> Schedule Interrupted",
|
||||
"create.train_map.section_reserved": " Section reserved",
|
||||
"create.train_map.toggle": "Train network overlay",
|
||||
"create.train_map.train_at_station": " >| %1$s",
|
||||
"create.train_map.train_moving_to_station": " >> %1$s (%2$sm)",
|
||||
"create.train_map.train_owned_by": "by %1$s",
|
||||
"create.train_map.waiting_at_signal": " Waiting at Signal",
|
||||
"create.tunnel.selection_mode.forced_round_robin": "Forced Round Robin",
|
||||
"create.tunnel.selection_mode.forced_split": "Forced Split",
|
||||
"create.tunnel.selection_mode.prefer_nearest": "Prefer Nearest",
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
},
|
||||
"has_the_recipe": {
|
||||
"conditions": {
|
||||
"recipe": "create:blasting/ingot_aluminum_compat_ic2"
|
||||
"recipe": "create:blasting/ingot_aluminium_compat_ic2"
|
||||
},
|
||||
"trigger": "minecraft:recipe_unlocked"
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
|||
],
|
||||
"rewards": {
|
||||
"recipes": [
|
||||
"create:blasting/ingot_aluminum_compat_ic2"
|
||||
"create:blasting/ingot_aluminium_compat_ic2"
|
||||
]
|
||||
},
|
||||
"sends_telemetry_event": false
|
|
@ -15,7 +15,7 @@
|
|||
},
|
||||
"has_the_recipe": {
|
||||
"conditions": {
|
||||
"recipe": "create:smelting/ingot_aluminum_compat_ic2"
|
||||
"recipe": "create:smelting/ingot_aluminium_compat_ic2"
|
||||
},
|
||||
"trigger": "minecraft:recipe_unlocked"
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
|||
],
|
||||
"rewards": {
|
||||
"recipes": [
|
||||
"create:smelting/ingot_aluminum_compat_ic2"
|
||||
"create:smelting/ingot_aluminium_compat_ic2"
|
||||
]
|
||||
},
|
||||
"sends_telemetry_event": false
|
|
@ -12,5 +12,5 @@
|
|||
"ingredient": {
|
||||
"item": "create:crushed_raw_aluminum"
|
||||
},
|
||||
"result": "ic2:ingot_aluminum"
|
||||
"result": "ic2:ingot_aluminium"
|
||||
}
|
|
@ -1,6 +1,12 @@
|
|||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "upgrade_aquatic"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "minecraft:small_flowers"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/black"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/blue"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/brown"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/cyan"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/gray"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/green"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/light_blue"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/light_gray"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/lime"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/magenta"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/orange"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/pink"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/purple"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/red"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/white"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "botania"
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"tag": "botania:petals/yellow"
|
||||
|
|
|
@ -12,5 +12,5 @@
|
|||
"ingredient": {
|
||||
"item": "create:crushed_raw_aluminum"
|
||||
},
|
||||
"result": "ic2:ingot_aluminum"
|
||||
"result": "ic2:ingot_aluminium"
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
"results": [
|
||||
{
|
||||
"count": 9,
|
||||
"item": "ic2:nugget_aluminum"
|
||||
"item": "ic2:nugget_aluminium"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -8,6 +8,8 @@ import java.util.function.Function;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.compat.computercraft.AttachedComputerPacket;
|
||||
import com.simibubi.create.compat.trainmap.TrainMapSyncPacket;
|
||||
import com.simibubi.create.compat.trainmap.TrainMapSyncRequestPacket;
|
||||
import com.simibubi.create.content.contraptions.ContraptionBlockChangedPacket;
|
||||
import com.simibubi.create.content.contraptions.ContraptionColliderLockPacket;
|
||||
import com.simibubi.create.content.contraptions.ContraptionColliderLockPacket.ContraptionColliderLockPacketRequest;
|
||||
|
@ -166,6 +168,7 @@ public enum AllPackets {
|
|||
ContraptionColliderLockPacketRequest::new, PLAY_TO_SERVER),
|
||||
RADIAL_WRENCH_MENU_SUBMIT(RadialWrenchMenuSubmitPacket.class, RadialWrenchMenuSubmitPacket::new,
|
||||
PLAY_TO_SERVER),
|
||||
TRAIN_MAP_REQUEST(TrainMapSyncRequestPacket.class, TrainMapSyncRequestPacket::new, PLAY_TO_SERVER),
|
||||
|
||||
// Server to Client
|
||||
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),
|
||||
|
@ -209,7 +212,8 @@ public enum AllPackets {
|
|||
CONTRAPTION_ACTOR_TOGGLE(ContraptionDisableActorPacket.class, ContraptionDisableActorPacket::new, PLAY_TO_CLIENT),
|
||||
CONTRAPTION_COLLIDER_LOCK(ContraptionColliderLockPacket.class, ContraptionColliderLockPacket::new, PLAY_TO_CLIENT),
|
||||
ATTACHED_COMPUTER(AttachedComputerPacket.class, AttachedComputerPacket::new, PLAY_TO_CLIENT),
|
||||
SERVER_DEBUG_INFO(ServerDebugInfoPacket.class, ServerDebugInfoPacket::new, PLAY_TO_CLIENT)
|
||||
SERVER_DEBUG_INFO(ServerDebugInfoPacket.class, ServerDebugInfoPacket::new, PLAY_TO_CLIENT),
|
||||
TRAIN_MAP_SYNC(TrainMapSyncPacket.class, TrainMapSyncPacket::new, PLAY_TO_CLIENT)
|
||||
;
|
||||
|
||||
static {
|
||||
|
|
|
@ -30,7 +30,9 @@ public enum Mods {
|
|||
TCONSTRUCT,
|
||||
FRAMEDBLOCKS,
|
||||
XLPACKETS,
|
||||
MODERNUI;
|
||||
MODERNUI,
|
||||
FTBCHUNKS,
|
||||
JOURNEYMAP;
|
||||
|
||||
private final String id;
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ public class StationPeripheral extends SyncedPeripheral<StationBlockEntity> {
|
|||
public final void setTrainName(String name) throws LuaException {
|
||||
Train train = getTrainOrThrow();
|
||||
train.name = Components.literal(name);
|
||||
AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainEditPacket.TrainEditReturnPacket(train.id, name, train.icon.getId()));
|
||||
AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainEditPacket.TrainEditReturnPacket(train.id, name, train.icon.getId(), train.mapColorIndex));
|
||||
}
|
||||
|
||||
@LuaFunction
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
package com.simibubi.create.compat.trainmap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.foundation.gui.RemovedGuiUtils;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
|
||||
import dev.ftb.mods.ftbchunks.client.gui.LargeMapScreen;
|
||||
import dev.ftb.mods.ftbchunks.client.gui.RegionMapPanel;
|
||||
import dev.ftb.mods.ftblibrary.ui.ScreenWrapper;
|
||||
import dev.ftb.mods.ftblibrary.ui.Widget;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.renderer.Rect2i;
|
||||
import net.minecraft.network.chat.FormattedText;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraftforge.client.event.InputEvent;
|
||||
import net.minecraftforge.client.event.RenderTooltipEvent;
|
||||
import net.minecraftforge.client.event.ScreenEvent;
|
||||
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
|
||||
|
||||
public class FTBChunksTrainMap {
|
||||
|
||||
private static int cancelTooltips = 0;
|
||||
private static boolean renderingTooltip = false;
|
||||
private static boolean requesting;
|
||||
|
||||
public static void tick() {
|
||||
if (cancelTooltips > 0)
|
||||
cancelTooltips--;
|
||||
if (!AllConfigs.client().showTrainMapOverlay.get()
|
||||
|| getAsLargeMapScreen(Minecraft.getInstance().screen) == null) {
|
||||
if (requesting)
|
||||
TrainMapSyncClient.stopRequesting();
|
||||
requesting = false;
|
||||
return;
|
||||
}
|
||||
TrainMapManager.tick();
|
||||
requesting = true;
|
||||
TrainMapSyncClient.requestData();
|
||||
}
|
||||
|
||||
public static void cancelTooltips(RenderTooltipEvent.Pre event) {
|
||||
if (getAsLargeMapScreen(Minecraft.getInstance().screen) == null)
|
||||
return;
|
||||
if (renderingTooltip || cancelTooltips == 0)
|
||||
return;
|
||||
event.setCanceled(true);
|
||||
}
|
||||
|
||||
public static void mouseClick(InputEvent.MouseButton.Pre event) {
|
||||
LargeMapScreen screen = getAsLargeMapScreen(Minecraft.getInstance().screen);
|
||||
if (screen == null)
|
||||
return;
|
||||
if (TrainMapManager.handleToggleWidgetClick(screen.getMouseX(), screen.getMouseY(), 20, 2))
|
||||
event.setCanceled(true);
|
||||
}
|
||||
|
||||
public static void renderGui(ScreenEvent.Render.Post event) {
|
||||
LargeMapScreen largeMapScreen = getAsLargeMapScreen(event.getScreen());
|
||||
if (largeMapScreen == null)
|
||||
return;
|
||||
Object panel = ObfuscationReflectionHelper.getPrivateValue(LargeMapScreen.class, largeMapScreen, "regionPanel");
|
||||
if (!(panel instanceof RegionMapPanel regionMapPanel))
|
||||
return;
|
||||
GuiGraphics graphics = event.getGuiGraphics();
|
||||
if (!AllConfigs.client().showTrainMapOverlay.get()) {
|
||||
renderToggleWidgetAndTooltip(event, largeMapScreen, graphics);
|
||||
return;
|
||||
}
|
||||
|
||||
int blocksPerRegion = 16 * 32;
|
||||
int minX = Mth.floor(regionMapPanel.getScrollX());
|
||||
int minY = Mth.floor(regionMapPanel.getScrollY());
|
||||
float regionTileSize = largeMapScreen.getRegionTileSize() / (float) blocksPerRegion;
|
||||
int regionMinX =
|
||||
ObfuscationReflectionHelper.getPrivateValue(RegionMapPanel.class, regionMapPanel, "regionMinX");
|
||||
int regionMinZ =
|
||||
ObfuscationReflectionHelper.getPrivateValue(RegionMapPanel.class, regionMapPanel, "regionMinZ");
|
||||
float mouseX = event.getMouseX();
|
||||
float mouseY = event.getMouseY();
|
||||
|
||||
boolean linearFiltering = largeMapScreen.getRegionTileSize() * Minecraft.getInstance()
|
||||
.getWindow()
|
||||
.getGuiScale() < 512D;
|
||||
|
||||
PoseStack pose = graphics.pose();
|
||||
pose.pushPose();
|
||||
|
||||
pose.translate(-minX, -minY, 0);
|
||||
pose.scale(regionTileSize, regionTileSize, 1);
|
||||
pose.translate(-regionMinX * blocksPerRegion, -regionMinZ * blocksPerRegion, 0);
|
||||
|
||||
mouseX += minX;
|
||||
mouseY += minY;
|
||||
mouseX /= regionTileSize;
|
||||
mouseY /= regionTileSize;
|
||||
mouseX += regionMinX * blocksPerRegion;
|
||||
mouseY += regionMinZ * blocksPerRegion;
|
||||
|
||||
Rect2i bounds = new Rect2i(Mth.floor(minX / regionTileSize + regionMinX * blocksPerRegion),
|
||||
Mth.floor(minY / regionTileSize + regionMinZ * blocksPerRegion),
|
||||
Mth.floor(largeMapScreen.width / regionTileSize), Mth.floor(largeMapScreen.height / regionTileSize));
|
||||
|
||||
List<FormattedText> tooltip = TrainMapManager.renderAndPick(graphics, Mth.floor(mouseX), Mth.floor(mouseY),
|
||||
event.getPartialTick(), linearFiltering, bounds);
|
||||
|
||||
pose.popPose();
|
||||
|
||||
if (!renderToggleWidgetAndTooltip(event, largeMapScreen, graphics) && tooltip != null) {
|
||||
renderingTooltip = true;
|
||||
RemovedGuiUtils.drawHoveringText(graphics, tooltip, event.getMouseX(), event.getMouseY(),
|
||||
largeMapScreen.width, largeMapScreen.height, 256, Minecraft.getInstance().font);
|
||||
renderingTooltip = false;
|
||||
cancelTooltips = 5;
|
||||
}
|
||||
|
||||
pose.pushPose();
|
||||
pose.translate(0, 0, 300);
|
||||
for (Widget widget : largeMapScreen.getWidgets()) {
|
||||
if (!widget.isEnabled())
|
||||
continue;
|
||||
if (widget == panel)
|
||||
continue;
|
||||
widget.draw(graphics, largeMapScreen.getTheme(), widget.getPosX(), widget.getPosY(), widget.getWidth(),
|
||||
widget.getHeight());
|
||||
}
|
||||
pose.popPose();
|
||||
}
|
||||
|
||||
private static boolean renderToggleWidgetAndTooltip(ScreenEvent.Render.Post event, LargeMapScreen largeMapScreen,
|
||||
GuiGraphics graphics) {
|
||||
TrainMapManager.renderToggleWidget(graphics, 20, 2);
|
||||
if (!TrainMapManager.isToggleWidgetHovered(event.getMouseX(), event.getMouseY(), 20, 2))
|
||||
return false;
|
||||
|
||||
renderingTooltip = true;
|
||||
RemovedGuiUtils.drawHoveringText(graphics, List.of(Lang.translate("train_map.toggle")
|
||||
.component()), event.getMouseX(), event.getMouseY() + 20, largeMapScreen.width, largeMapScreen.height, 256,
|
||||
Minecraft.getInstance().font);
|
||||
renderingTooltip = false;
|
||||
cancelTooltips = 5;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static LargeMapScreen getAsLargeMapScreen(Screen screen) {
|
||||
if (!(screen instanceof ScreenWrapper screenWrapper))
|
||||
return null;
|
||||
Object wrapped = ObfuscationReflectionHelper.getPrivateValue(ScreenWrapper.class, screenWrapper, "wrappedGui");
|
||||
if (!(wrapped instanceof LargeMapScreen largeMapScreen))
|
||||
return null;
|
||||
return largeMapScreen;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package com.simibubi.create.compat.trainmap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mojang.blaze3d.platform.Window;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.foundation.gui.RemovedGuiUtils;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
|
||||
import journeymap.client.api.display.Context.UI;
|
||||
import journeymap.client.api.util.UIState;
|
||||
import journeymap.client.ui.fullscreen.Fullscreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.Rect2i;
|
||||
import net.minecraft.network.chat.FormattedText;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraftforge.client.event.InputEvent;
|
||||
|
||||
public class JourneyTrainMap {
|
||||
|
||||
private static boolean requesting;
|
||||
|
||||
public static void tick() {
|
||||
if (!AllConfigs.client().showTrainMapOverlay.get() || !(Minecraft.getInstance().screen instanceof Fullscreen)) {
|
||||
if (requesting)
|
||||
TrainMapSyncClient.stopRequesting();
|
||||
requesting = false;
|
||||
return;
|
||||
}
|
||||
TrainMapManager.tick();
|
||||
requesting = true;
|
||||
TrainMapSyncClient.requestData();
|
||||
}
|
||||
|
||||
public static void mouseClick(InputEvent.MouseButton.Pre event) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (!(mc.screen instanceof Fullscreen screen))
|
||||
return;
|
||||
|
||||
Window window = mc.getWindow();
|
||||
double mX = mc.mouseHandler.xpos() * window.getGuiScaledWidth() / window.getScreenWidth();
|
||||
double mY = mc.mouseHandler.ypos() * window.getGuiScaledHeight() / window.getScreenHeight();
|
||||
|
||||
if (TrainMapManager.handleToggleWidgetClick(Mth.floor(mX), Mth.floor(mY), 3, 30))
|
||||
event.setCanceled(true);
|
||||
}
|
||||
|
||||
// Called by JourneyFullscreenMapMixin
|
||||
public static void onRender(GuiGraphics graphics, Fullscreen screen, double x, double z, int mX, int mY, float pt) {
|
||||
UIState state = screen.getUiState();
|
||||
if (state == null)
|
||||
return;
|
||||
if (state.ui != UI.Fullscreen)
|
||||
return;
|
||||
if (!state.active)
|
||||
return;
|
||||
if (!AllConfigs.client().showTrainMapOverlay.get()) {
|
||||
renderToggleWidgetAndTooltip(graphics, screen, mX, mY);
|
||||
return;
|
||||
}
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
Window window = mc.getWindow();
|
||||
|
||||
double guiScale = (double) window.getScreenWidth() / window.getGuiScaledWidth();
|
||||
double scale = state.blockSize / guiScale;
|
||||
|
||||
PoseStack pose = graphics.pose();
|
||||
pose.pushPose();
|
||||
|
||||
pose.translate(screen.width / 2.0f, screen.height / 2.0f, 0);
|
||||
pose.scale((float) scale, (float) scale, 1);
|
||||
pose.translate(-x, -z, 0);
|
||||
|
||||
float mouseX = mX - screen.width / 2.0f;
|
||||
float mouseY = mY - screen.height / 2.0f;
|
||||
mouseX /= scale;
|
||||
mouseY /= scale;
|
||||
mouseX += x;
|
||||
mouseY += z;
|
||||
|
||||
Rect2i bounds =
|
||||
new Rect2i(Mth.floor(-screen.width / 2.0f / scale + x), Mth.floor(-screen.height / 2.0f / scale + z),
|
||||
Mth.floor(screen.width / scale), Mth.floor(screen.height / scale));
|
||||
|
||||
List<FormattedText> tooltip =
|
||||
TrainMapManager.renderAndPick(graphics, Mth.floor(mouseX), Mth.floor(mouseY), pt, false, bounds);
|
||||
|
||||
pose.popPose();
|
||||
|
||||
if (!renderToggleWidgetAndTooltip(graphics, screen, mX, mY) && tooltip != null)
|
||||
RemovedGuiUtils.drawHoveringText(graphics, tooltip, mX, mY, screen.width, screen.height, 256, mc.font);
|
||||
}
|
||||
|
||||
private static boolean renderToggleWidgetAndTooltip(GuiGraphics graphics, Fullscreen screen, int mouseX,
|
||||
int mouseY) {
|
||||
TrainMapManager.renderToggleWidget(graphics, 3, 30);
|
||||
if (!TrainMapManager.isToggleWidgetHovered(mouseX, mouseY, 3, 30))
|
||||
return false;
|
||||
|
||||
RemovedGuiUtils.drawHoveringText(graphics, List.of(Lang.translate("train_map.toggle")
|
||||
.component()), mouseX, mouseY + 20, screen.width, screen.height, 256, Minecraft.getInstance().font);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.simibubi.create.compat.trainmap;
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import com.simibubi.create.compat.Mods;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.InputEvent;
|
||||
import net.minecraftforge.client.event.RenderTooltipEvent;
|
||||
import net.minecraftforge.client.event.ScreenEvent;
|
||||
import net.minecraftforge.event.TickEvent.ClientTickEvent;
|
||||
import net.minecraftforge.event.TickEvent.Phase;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber(value = Dist.CLIENT)
|
||||
public class TrainMapEvents {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void tick(ClientTickEvent event) {
|
||||
if (event.phase == Phase.START)
|
||||
return;
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.level == null)
|
||||
return;
|
||||
|
||||
if (Mods.FTBCHUNKS.isLoaded())
|
||||
FTBChunksTrainMap.tick();
|
||||
if (Mods.JOURNEYMAP.isLoaded())
|
||||
JourneyTrainMap.tick();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void mouseClick(InputEvent.MouseButton.Pre event) {
|
||||
if (event.getAction() != InputConstants.PRESS)
|
||||
return;
|
||||
|
||||
if (Mods.FTBCHUNKS.isLoaded())
|
||||
FTBChunksTrainMap.mouseClick(event);
|
||||
if (Mods.JOURNEYMAP.isLoaded())
|
||||
JourneyTrainMap.mouseClick(event);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void cancelTooltips(RenderTooltipEvent.Pre event) {
|
||||
if (Mods.FTBCHUNKS.isLoaded())
|
||||
FTBChunksTrainMap.cancelTooltips(event);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void renderGui(ScreenEvent.Render.Post event) {
|
||||
if (Mods.FTBCHUNKS.isLoaded())
|
||||
FTBChunksTrainMap.renderGui(event);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,730 @@
|
|||
package com.simibubi.create.compat.trainmap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.compat.trainmap.TrainMapSync.SignalState;
|
||||
import com.simibubi.create.compat.trainmap.TrainMapSync.TrainMapSyncEntry;
|
||||
import com.simibubi.create.compat.trainmap.TrainMapSync.TrainState;
|
||||
import com.simibubi.create.content.trains.entity.Carriage;
|
||||
import com.simibubi.create.content.trains.entity.Train;
|
||||
import com.simibubi.create.content.trains.graph.EdgePointType;
|
||||
import com.simibubi.create.content.trains.graph.TrackEdge;
|
||||
import com.simibubi.create.content.trains.graph.TrackGraph;
|
||||
import com.simibubi.create.content.trains.graph.TrackNode;
|
||||
import com.simibubi.create.content.trains.graph.TrackNodeLocation;
|
||||
import com.simibubi.create.content.trains.station.GlobalStation;
|
||||
import com.simibubi.create.content.trains.track.BezierConnection;
|
||||
import com.simibubi.create.foundation.gui.AllGuiTextures;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.Components;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
import com.simibubi.create.infrastructure.config.CClient;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.Rect2i;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.FormattedText;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.util.FastColor;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class TrainMapManager {
|
||||
|
||||
public static void tick() {
|
||||
TrainMapRenderer map = TrainMapRenderer.INSTANCE;
|
||||
if (map.trackingVersion != CreateClient.RAILWAYS.version
|
||||
|| map.trackingDim != Minecraft.getInstance().level.dimension()
|
||||
|| map.trackingTheme != AllConfigs.client().trainMapColorTheme.get()) {
|
||||
redrawAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<FormattedText> renderAndPick(GuiGraphics graphics, int mouseX, int mouseY, float pt,
|
||||
boolean linearFiltering, Rect2i bounds) {
|
||||
Object hoveredElement = null;
|
||||
|
||||
int offScreenMargin = 32;
|
||||
bounds.setX(bounds.getX() - offScreenMargin);
|
||||
bounds.setY(bounds.getY() - offScreenMargin);
|
||||
bounds.setWidth(bounds.getWidth() + 2 * offScreenMargin);
|
||||
bounds.setHeight(bounds.getHeight() + 2 * offScreenMargin);
|
||||
|
||||
TrainMapRenderer.INSTANCE.render(graphics, mouseX, mouseY, pt, linearFiltering, bounds);
|
||||
hoveredElement = drawTrains(graphics, mouseX, mouseY, pt, hoveredElement, bounds);
|
||||
hoveredElement = drawPoints(graphics, mouseX, mouseY, pt, hoveredElement, bounds);
|
||||
|
||||
graphics.bufferSource()
|
||||
.endBatch();
|
||||
|
||||
if (hoveredElement instanceof GlobalStation station)
|
||||
return List.of(Components.literal(station.name));
|
||||
|
||||
if (hoveredElement instanceof Train train)
|
||||
return listTrainDetails(train);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void renderToggleWidget(GuiGraphics graphics, int x, int y) {
|
||||
boolean enabled = AllConfigs.client().showTrainMapOverlay.get();
|
||||
if (CreateClient.RAILWAYS.trackNetworks.isEmpty())
|
||||
return;
|
||||
RenderSystem.enableBlend();
|
||||
PoseStack pose = graphics.pose();
|
||||
pose.pushPose();
|
||||
pose.translate(0, 0, 300);
|
||||
AllGuiTextures.TRAINMAP_TOGGLE_PANEL.render(graphics, x, y);
|
||||
(enabled ? AllGuiTextures.TRAINMAP_TOGGLE_ON : AllGuiTextures.TRAINMAP_TOGGLE_OFF).render(graphics, x + 18,
|
||||
y + 3);
|
||||
pose.popPose();
|
||||
}
|
||||
|
||||
public static boolean handleToggleWidgetClick(int mouseX, int mouseY, int x, int y) {
|
||||
if (!isToggleWidgetHovered(mouseX, mouseY, x, y))
|
||||
return false;
|
||||
CClient config = AllConfigs.client();
|
||||
config.showTrainMapOverlay.set(!config.showTrainMapOverlay.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isToggleWidgetHovered(int mouseX, int mouseY, int x, int y) {
|
||||
if (CreateClient.RAILWAYS.trackNetworks.isEmpty())
|
||||
return false;
|
||||
if (mouseX < x || mouseX >= x + AllGuiTextures.TRAINMAP_TOGGLE_PANEL.width)
|
||||
return false;
|
||||
if (mouseY < y || mouseY >= y + AllGuiTextures.TRAINMAP_TOGGLE_PANEL.height)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static List<FormattedText> listTrainDetails(Train train) {
|
||||
List<FormattedText> output = new ArrayList<>();
|
||||
int blue = 0xD3DEDC;
|
||||
int darkBlue = 0x92A9BD;
|
||||
int bright = 0xFFEFEF;
|
||||
int orange = 0xFFAD60;
|
||||
|
||||
TrainMapSyncEntry trainEntry = TrainMapSyncClient.currentData.get(train.id);
|
||||
if (trainEntry == null)
|
||||
return Collections.emptyList();
|
||||
TrainState state = trainEntry.state;
|
||||
SignalState signalState = trainEntry.signalState;
|
||||
|
||||
Lang.text(train.name.getString())
|
||||
.color(bright)
|
||||
.addTo(output);
|
||||
|
||||
if (!trainEntry.ownerName.isBlank())
|
||||
Lang.translate("train_map.train_owned_by", trainEntry.ownerName)
|
||||
.color(blue)
|
||||
.addTo(output);
|
||||
|
||||
switch (state) {
|
||||
|
||||
case CONDUCTOR_MISSING:
|
||||
Lang.translate("train_map.conductor_missing")
|
||||
.color(orange)
|
||||
.addTo(output);
|
||||
return output;
|
||||
case DERAILED:
|
||||
Lang.translate("train_map.derailed")
|
||||
.color(orange)
|
||||
.addTo(output);
|
||||
return output;
|
||||
case NAVIGATION_FAILED:
|
||||
Lang.translate("train_map.navigation_failed")
|
||||
.color(orange)
|
||||
.addTo(output);
|
||||
return output;
|
||||
case SCHEDULE_INTERRUPTED:
|
||||
Lang.translate("train_map.schedule_interrupted")
|
||||
.color(orange)
|
||||
.addTo(output);
|
||||
return output;
|
||||
case RUNNING_MANUALLY:
|
||||
Lang.translate("train_map.player_controlled")
|
||||
.color(blue)
|
||||
.addTo(output);
|
||||
break;
|
||||
|
||||
case RUNNING:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
String currentStation = trainEntry.targetStationName;
|
||||
int targetStationDistance = trainEntry.targetStationDistance;
|
||||
|
||||
if (!currentStation.isBlank()) {
|
||||
if (targetStationDistance == 0)
|
||||
Lang.translate("train_map.train_at_station", currentStation)
|
||||
.color(darkBlue)
|
||||
.addTo(output);
|
||||
else
|
||||
Lang.translate("train_map.train_moving_to_station", currentStation, targetStationDistance)
|
||||
.color(darkBlue)
|
||||
.addTo(output);
|
||||
}
|
||||
|
||||
if (signalState != SignalState.NOT_WAITING) {
|
||||
boolean chainSignal = signalState == SignalState.CHAIN_SIGNAL;
|
||||
Lang.translate("train_map.waiting_at_signal")
|
||||
.color(orange)
|
||||
.addTo(output);
|
||||
|
||||
if (signalState == SignalState.WAITING_FOR_REDSTONE)
|
||||
Lang.translate("train_map.redstone_powered")
|
||||
.color(blue)
|
||||
.addTo(output);
|
||||
else {
|
||||
UUID waitingFor = trainEntry.waitingForTrain;
|
||||
boolean trainFound = false;
|
||||
|
||||
if (waitingFor != null) {
|
||||
Train trainWaitingFor = CreateClient.RAILWAYS.trains.get(waitingFor);
|
||||
if (trainWaitingFor != null) {
|
||||
Lang.translate("train_map.for_other_train", trainWaitingFor.name.getString())
|
||||
.color(blue)
|
||||
.addTo(output);
|
||||
trainFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!trainFound) {
|
||||
if (chainSignal)
|
||||
Lang.translate("train_map.cannot_traverse_section")
|
||||
.color(blue)
|
||||
.addTo(output);
|
||||
else
|
||||
Lang.translate("train_map.section_reserved")
|
||||
.color(blue)
|
||||
.addTo(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trainEntry.fueled)
|
||||
Lang.translate("train_map.fuel_boosted")
|
||||
.color(darkBlue)
|
||||
.addTo(output);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static Object drawPoints(GuiGraphics graphics, int mouseX, int mouseY, float pt, Object hoveredElement,
|
||||
Rect2i bounds) {
|
||||
PoseStack pose = graphics.pose();
|
||||
RenderSystem.enableDepthTest();
|
||||
|
||||
for (TrackGraph graph : CreateClient.RAILWAYS.trackNetworks.values()) {
|
||||
for (GlobalStation station : graph.getPoints(EdgePointType.STATION)) {
|
||||
|
||||
Couple<TrackNodeLocation> edgeLocation = station.edgeLocation;
|
||||
TrackNode node = graph.locateNode(edgeLocation.getFirst());
|
||||
TrackNode other = graph.locateNode(edgeLocation.getSecond());
|
||||
if (node == null || other == null)
|
||||
continue;
|
||||
if (node.getLocation().dimension != TrainMapRenderer.INSTANCE.trackingDim)
|
||||
continue;
|
||||
|
||||
TrackEdge edge = graph.getConnection(Couple.create(node, other));
|
||||
if (edge == null)
|
||||
continue;
|
||||
|
||||
double tLength = station.getLocationOn(edge);
|
||||
double t = tLength / edge.getLength();
|
||||
Vec3 position = edge.getPosition(graph, t);
|
||||
|
||||
int x = Mth.floor(position.x());
|
||||
int y = Mth.floor(position.z());
|
||||
|
||||
if (!bounds.contains(x, y))
|
||||
continue;
|
||||
|
||||
Vec3 diff = edge.getDirectionAt(tLength)
|
||||
.normalize();
|
||||
int rotation = Mth.positiveModulo(Mth.floor(0.5
|
||||
+ (Math.atan2(diff.z, diff.x) * Mth.RAD_TO_DEG + 90 + (station.isPrimary(node) ? 180 : 0)) / 45),
|
||||
8);
|
||||
|
||||
AllGuiTextures sprite = AllGuiTextures.TRAINMAP_STATION_ORTHO;
|
||||
AllGuiTextures highlightSprite = AllGuiTextures.TRAINMAP_STATION_ORTHO_HIGHLIGHT;
|
||||
if (rotation % 2 != 0) {
|
||||
sprite = AllGuiTextures.TRAINMAP_STATION_DIAGO;
|
||||
highlightSprite = AllGuiTextures.TRAINMAP_STATION_DIAGO_HIGHLIGHT;
|
||||
}
|
||||
|
||||
boolean highlight = hoveredElement == null && Math.max(Math.abs(mouseX - x), Math.abs(mouseY - y)) < 3;
|
||||
|
||||
pose.pushPose();
|
||||
pose.translate(x - 2, y - 2, 5);
|
||||
|
||||
pose.translate(sprite.width / 2.0, sprite.height / 2.0, 0);
|
||||
pose.mulPose(Axis.ZP.rotationDegrees(90 * (rotation / 2)));
|
||||
pose.translate(-sprite.width / 2.0, -sprite.height / 2.0, 0);
|
||||
|
||||
sprite.render(graphics, 0, 0);
|
||||
sprite.render(graphics, 0, 0);
|
||||
|
||||
if (highlight) {
|
||||
pose.translate(0, 0, 5);
|
||||
highlightSprite.render(graphics, -1, -1);
|
||||
hoveredElement = station;
|
||||
}
|
||||
|
||||
pose.popPose();
|
||||
}
|
||||
}
|
||||
|
||||
return hoveredElement;
|
||||
}
|
||||
|
||||
private static Object drawTrains(GuiGraphics graphics, int mouseX, int mouseY, float pt, Object hoveredElement,
|
||||
Rect2i bounds) {
|
||||
PoseStack pose = graphics.pose();
|
||||
RenderSystem.enableDepthTest();
|
||||
RenderSystem.enableBlend();
|
||||
|
||||
int spriteYOffset = -3;
|
||||
|
||||
double time = AnimationTickHolder.getTicks();
|
||||
time += AnimationTickHolder.getPartialTicks();
|
||||
time -= TrainMapSyncClient.lastPacket;
|
||||
time /= TrainMapSync.lightPacketInterval;
|
||||
time = Mth.clamp(time, 0, 1);
|
||||
|
||||
int[] sliceXShiftByRotationIndex = new int[] { 0, 1, 2, 2, 3, -2, -2, -1 };
|
||||
int[] sliceYShiftByRotationIndex = new int[] { 3, 2, 2, 1, 0, 1, 2, 2 };
|
||||
|
||||
for (Train train : CreateClient.RAILWAYS.trains.values()) {
|
||||
TrainMapSyncEntry trainEntry = TrainMapSyncClient.currentData.get(train.id);
|
||||
if (trainEntry == null)
|
||||
continue;
|
||||
|
||||
Vec3 frontPos = Vec3.ZERO;
|
||||
List<Carriage> carriages = train.carriages;
|
||||
boolean otherDim = true;
|
||||
double avgY = 0;
|
||||
|
||||
for (int i = 0; i < carriages.size(); i++) {
|
||||
for (boolean firstBogey : Iterate.trueAndFalse)
|
||||
avgY += trainEntry.getPosition(i, firstBogey, time)
|
||||
.y();
|
||||
}
|
||||
|
||||
avgY /= carriages.size() * 2;
|
||||
|
||||
for (int i = 0; i < carriages.size(); i++) {
|
||||
Carriage carriage = carriages.get(i);
|
||||
|
||||
Vec3 pos1 = trainEntry.getPosition(i, true, time);
|
||||
Vec3 pos2 = trainEntry.getPosition(i, false, time);
|
||||
|
||||
ResourceKey<Level> dim = trainEntry.dimensions.get(i);
|
||||
if (dim == null || dim != TrainMapRenderer.INSTANCE.trackingDim)
|
||||
continue;
|
||||
if (!bounds.contains(Mth.floor(pos1.x()), Mth.floor(pos1.z()))
|
||||
&& !bounds.contains(Mth.floor(pos2.x()), Mth.floor(pos2.z())))
|
||||
continue;
|
||||
|
||||
otherDim = false;
|
||||
|
||||
if (!trainEntry.backwards && i == 0)
|
||||
frontPos = pos1;
|
||||
if (trainEntry.backwards && i == train.carriages.size() - 1)
|
||||
frontPos = pos2;
|
||||
|
||||
Vec3 diff = pos2.subtract(pos1);
|
||||
int size = carriage.bogeySpacing + 1;
|
||||
Vec3 center = pos1.add(pos2)
|
||||
.scale(0.5);
|
||||
|
||||
double pX = center.x;
|
||||
double pY = center.z;
|
||||
int rotation =
|
||||
Mth.positiveModulo(Mth.floor(0.5 + (Math.atan2(diff.x, diff.z) * Mth.RAD_TO_DEG) / 22.5), 8);
|
||||
|
||||
if (trainEntry.state == TrainState.DERAILED)
|
||||
rotation =
|
||||
Mth.positiveModulo((AnimationTickHolder.getTicks() / 8 + i * 3) * (i % 2 == 0 ? 1 : -1), 8);
|
||||
|
||||
AllGuiTextures sprite = AllGuiTextures.TRAINMAP_SPRITES;
|
||||
|
||||
int slices = 2;
|
||||
|
||||
if (rotation == 0 || rotation == 4) {
|
||||
// Orthogonal, slices add 3 pixels
|
||||
slices += Mth.floor((size - 2) / (3.0) + 0.5);
|
||||
}
|
||||
|
||||
else if (rotation == 2 || rotation == 6) {
|
||||
// Diagonal, slices add 2*sqrt(2) pixels
|
||||
slices += Mth.floor((size - (5 - 2 * Mth.SQRT_OF_TWO)) / (2 * Mth.SQRT_OF_TWO) + 0.5);
|
||||
}
|
||||
|
||||
else {
|
||||
// Slanty, slices add sqrt(5) pixels
|
||||
slices += Mth.floor((size - (5 - Mth.sqrt(5))) / (Mth.sqrt(5)) + 0.5);
|
||||
}
|
||||
|
||||
slices = Math.max(2, slices);
|
||||
|
||||
sprite.bind();
|
||||
pose.pushPose();
|
||||
|
||||
float pivotX = 7.5f + (slices - 3) * sliceXShiftByRotationIndex[rotation] / 2.0f;
|
||||
float pivotY = 6.5f + (slices - 3) * sliceYShiftByRotationIndex[rotation] / 2.0f;
|
||||
// Ysort at home
|
||||
pose.translate(pX - pivotX, pY - pivotY, 10 + (avgY / 512.0) + (1024.0 + center.z() % 8192.0) / 1024.0);
|
||||
|
||||
int trainColorIndex = train.mapColorIndex;
|
||||
int colorRow = trainColorIndex / 4;
|
||||
int colorCol = trainColorIndex % 4;
|
||||
|
||||
for (int slice = 0; slice < slices; slice++) {
|
||||
int row = slice == 0 ? 1 : slice == slices - 1 ? 2 : 3;
|
||||
int sliceShifts = slice == 0 ? 0 : slice == slices - 1 ? slice - 2 : slice - 1;
|
||||
int col = rotation;
|
||||
|
||||
int positionX = sliceShifts * sliceXShiftByRotationIndex[rotation];
|
||||
int positionY = sliceShifts * sliceYShiftByRotationIndex[rotation] + spriteYOffset;
|
||||
int sheetX = col * 16 + colorCol * 128;
|
||||
int sheetY = row * 16 + colorRow * 64;
|
||||
|
||||
graphics.blit(sprite.location, positionX, positionY, sheetX, sheetY, 16, 16, sprite.width,
|
||||
sprite.height);
|
||||
}
|
||||
|
||||
pose.popPose();
|
||||
|
||||
int margin = 1;
|
||||
int sizeX = 8 + (slices - 3) * sliceXShiftByRotationIndex[rotation];
|
||||
int sizeY = 12 + (slices - 3) * sliceYShiftByRotationIndex[rotation];
|
||||
double pXm = pX - sizeX / 2;
|
||||
double pYm = pY - sizeY / 2 + spriteYOffset;
|
||||
if (hoveredElement == null && mouseX < pXm + margin + sizeX && mouseX > pXm - margin
|
||||
&& mouseY < pYm + margin + sizeY && mouseY > pYm - margin)
|
||||
hoveredElement = train;
|
||||
}
|
||||
|
||||
if (otherDim)
|
||||
continue;
|
||||
|
||||
if (trainEntry.signalState != SignalState.NOT_WAITING) {
|
||||
pose.pushPose();
|
||||
pose.translate(frontPos.x - 0.5, frontPos.z - 0.5, 20 + (1024.0 + frontPos.z() % 8192.0) / 1024.0);
|
||||
AllGuiTextures.TRAINMAP_SIGNAL.render(graphics, 0, -3);
|
||||
pose.popPose();
|
||||
}
|
||||
}
|
||||
|
||||
return hoveredElement;
|
||||
}
|
||||
|
||||
// Background first so we can mindlessly paint over it
|
||||
static final int PHASE_BACKGROUND = 0;
|
||||
// Straights before curves so that curves anti-alias properly at the transition
|
||||
static final int PHASE_STRAIGHTS = 1;
|
||||
static final int PHASE_CURVES = 2;
|
||||
|
||||
public static void redrawAll() {
|
||||
TrainMapRenderer map = TrainMapRenderer.INSTANCE;
|
||||
map.trackingVersion = CreateClient.RAILWAYS.version;
|
||||
map.trackingDim = Minecraft.getInstance().level.dimension();
|
||||
map.trackingTheme = AllConfigs.client().trainMapColorTheme.get();
|
||||
map.startDrawing();
|
||||
|
||||
int mainColor = 0xFF_7C57D4;
|
||||
int darkerColor = 0xFF_70437D;
|
||||
int darkerColorShadow = 0xFF_4A2754;
|
||||
|
||||
switch (map.trackingTheme) {
|
||||
case GREY:
|
||||
mainColor = 0xFF_A8B5B5;
|
||||
darkerColor = 0xFF_776E6C;
|
||||
darkerColorShadow = 0xFF_56504E;
|
||||
break;
|
||||
case WHITE:
|
||||
mainColor = 0xFF_E8F9F9;
|
||||
darkerColor = 0xFF_889595;
|
||||
darkerColorShadow = 0xFF_56504E;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
List<Couple<Integer>> collisions = new ObjectArrayList<>();
|
||||
|
||||
for (int phase = 0; phase <= 2; phase++)
|
||||
renderPhase(map, collisions, mainColor, darkerColor, phase);
|
||||
|
||||
highlightYDifferences(map, collisions, mainColor, darkerColor, darkerColor, darkerColorShadow);
|
||||
|
||||
map.finishDrawing();
|
||||
}
|
||||
|
||||
private static void renderPhase(TrainMapRenderer map, List<Couple<Integer>> collisions, int mainColor,
|
||||
int darkerColor, int phase) {
|
||||
int outlineColor = 0xFF_000000;
|
||||
|
||||
int portalFrameColor = 0xFF_4C2D5B;
|
||||
int portalColor = 0xFF_FF7FD6;
|
||||
|
||||
for (TrackGraph graph : CreateClient.RAILWAYS.trackNetworks.values()) {
|
||||
for (TrackNodeLocation nodeLocation : graph.getNodes()) {
|
||||
if (nodeLocation.dimension != map.trackingDim)
|
||||
continue;
|
||||
TrackNode node = graph.locateNode(nodeLocation);
|
||||
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node);
|
||||
|
||||
int hashCode = node.hashCode();
|
||||
for (Entry<TrackNode, TrackEdge> entry : connectionsFrom.entrySet()) {
|
||||
TrackNode other = entry.getKey();
|
||||
TrackNodeLocation otherLocation = other.getLocation();
|
||||
TrackEdge edge = entry.getValue();
|
||||
BezierConnection turn = edge.getTurn();
|
||||
|
||||
// Portal track
|
||||
if (edge.isInterDimensional()) {
|
||||
Vec3 vec = node.getLocation()
|
||||
.getLocation();
|
||||
int x = Mth.floor(vec.x);
|
||||
int z = Mth.floor(vec.z);
|
||||
if (phase == PHASE_CURVES)
|
||||
continue;
|
||||
if (phase == PHASE_BACKGROUND) {
|
||||
map.setPixels(x - 3, z - 2, x + 3, z + 2, outlineColor);
|
||||
map.setPixels(x - 2, z - 3, x + 2, z + 3, outlineColor);
|
||||
continue;
|
||||
}
|
||||
|
||||
int a = mapYtoAlpha(Mth.floor(vec.y()));
|
||||
for (int xi = x - 2; xi <= x + 2; xi++) {
|
||||
for (int zi = z - 2; zi <= z + 2; zi++) {
|
||||
int alphaAt = map.alphaAt(xi, zi);
|
||||
if (alphaAt > 0 && alphaAt != a)
|
||||
collisions.add(Couple.create(xi, zi));
|
||||
int c = (xi - x) * (xi - x) + (zi - z) * (zi - z) > 2 ? portalFrameColor : portalColor;
|
||||
if (alphaAt <= a) {
|
||||
map.setPixel(xi, zi, markY(c, vec.y()));
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (other.hashCode() > hashCode)
|
||||
continue;
|
||||
|
||||
if (turn == null) {
|
||||
if (phase == PHASE_CURVES)
|
||||
continue;
|
||||
|
||||
float x1 = nodeLocation.getX();
|
||||
float z1 = nodeLocation.getZ();
|
||||
float x2 = otherLocation.getX();
|
||||
float z2 = otherLocation.getZ();
|
||||
|
||||
double y1 = nodeLocation.getLocation()
|
||||
.y();
|
||||
double y2 = otherLocation.getLocation()
|
||||
.y();
|
||||
|
||||
float xDiffSign = Math.signum(x2 - x1);
|
||||
float zDiffSign = Math.signum(z2 - z1);
|
||||
boolean diagonal = xDiffSign != 0 && zDiffSign != 0;
|
||||
|
||||
if (xDiffSign != 0) {
|
||||
x2 -= xDiffSign * .25;
|
||||
x1 += xDiffSign * .25;
|
||||
}
|
||||
|
||||
if (zDiffSign != 0) {
|
||||
z2 -= zDiffSign * .25;
|
||||
z1 += zDiffSign * .25;
|
||||
}
|
||||
|
||||
x1 /= 2;
|
||||
x2 /= 2;
|
||||
z1 /= 2;
|
||||
z2 /= 2;
|
||||
|
||||
int y = Mth.floor(y1);
|
||||
int a = mapYtoAlpha(y);
|
||||
|
||||
// Diagonal
|
||||
if (diagonal) {
|
||||
int z = Mth.floor(z1);
|
||||
int x = Mth.floor(x1);
|
||||
|
||||
for (int s = 0; s <= Math.abs(x1 - x2); s++) {
|
||||
if (phase == PHASE_BACKGROUND) {
|
||||
map.setPixels(x - 1, z, x + 1, z + 1, outlineColor);
|
||||
map.setPixels(x, z - 1, x, z + 2, outlineColor);
|
||||
x += xDiffSign;
|
||||
z += zDiffSign;
|
||||
continue;
|
||||
}
|
||||
|
||||
int alphaAt = map.alphaAt(x, z);
|
||||
if (alphaAt > 0 && alphaAt != a)
|
||||
collisions.add(Couple.create(x, z));
|
||||
if (alphaAt <= a) {
|
||||
map.setPixel(x, z, markY(mainColor, y));
|
||||
}
|
||||
|
||||
if (map.alphaAt(x, z + 1) < a) {
|
||||
map.setPixel(x, z + 1, markY(darkerColor, y));
|
||||
}
|
||||
|
||||
x += xDiffSign;
|
||||
z += zDiffSign;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Straight
|
||||
if (phase == PHASE_BACKGROUND) {
|
||||
int x1i = Mth.floor(Math.min(x1, x2));
|
||||
int z1i = Mth.floor(Math.min(z1, z2));
|
||||
int x2i = Mth.floor(Math.max(x1, x2));
|
||||
int z2i = Mth.floor(Math.max(z1, z2));
|
||||
|
||||
map.setPixels(x1i - 1, z1i, x2i + 1, z2i, outlineColor);
|
||||
map.setPixels(x1i, z1i - 1, x2i, z2i + 1, outlineColor);
|
||||
continue;
|
||||
}
|
||||
|
||||
int z = Mth.floor(z1);
|
||||
int x = Mth.floor(x1);
|
||||
float diff = Math.max(Math.abs(x1 - x2), Math.abs(z1 - z2));
|
||||
double yStep = (y2 - y1) / diff;
|
||||
|
||||
for (int s = 0; s <= diff; s++) {
|
||||
int alphaAt = map.alphaAt(x, z);
|
||||
if (alphaAt > 0 && alphaAt != a)
|
||||
collisions.add(Couple.create(x, z));
|
||||
if (alphaAt <= a) {
|
||||
map.setPixel(x, z, markY(mainColor, y));
|
||||
}
|
||||
x += xDiffSign;
|
||||
y += yStep;
|
||||
z += zDiffSign;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (phase == PHASE_STRAIGHTS)
|
||||
continue;
|
||||
|
||||
BlockPos origin = turn.bePositions.getFirst();
|
||||
Map<Pair<Integer, Integer>, Double> rasterise = turn.rasterise();
|
||||
|
||||
for (boolean antialias : Iterate.falseAndTrue) {
|
||||
for (Entry<Pair<Integer, Integer>, Double> offset : rasterise.entrySet()) {
|
||||
Pair<Integer, Integer> xz = offset.getKey();
|
||||
int x = origin.getX() + xz.getFirst();
|
||||
int y = Mth.floor(origin.getY() + offset.getValue() + 0.5);
|
||||
int z = origin.getZ() + xz.getSecond();
|
||||
|
||||
if (phase == PHASE_BACKGROUND) {
|
||||
map.setPixels(x - 1, z, x + 1, z, outlineColor);
|
||||
map.setPixels(x, z - 1, x, z + 1, outlineColor);
|
||||
continue;
|
||||
}
|
||||
|
||||
int a = mapYtoAlpha(y);
|
||||
|
||||
if (!antialias) {
|
||||
int alphaAt = map.alphaAt(x, z);
|
||||
if (alphaAt > 0 && alphaAt != a)
|
||||
collisions.add(Couple.create(x, z));
|
||||
if (alphaAt > a)
|
||||
continue;
|
||||
|
||||
map.setPixel(x, z, markY(mainColor, y));
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean mainColorBelowLeft =
|
||||
map.is(x + 1, z + 1, mainColor) && Math.abs(map.alphaAt(x + 1, z + 1) - a) <= 1;
|
||||
boolean mainColorBelowRight =
|
||||
map.is(x - 1, z + 1, mainColor) && Math.abs(map.alphaAt(x - 1, z + 1) - a) <= 1;
|
||||
|
||||
if (mainColorBelowLeft || mainColorBelowRight) {
|
||||
int alphaAt = map.alphaAt(x, z + 1);
|
||||
if (alphaAt > 0 && alphaAt != a)
|
||||
collisions.add(Couple.create(x, z));
|
||||
if (alphaAt >= a)
|
||||
continue;
|
||||
|
||||
map.setPixel(x, z + 1, markY(darkerColor, y));
|
||||
|
||||
// Adjust background
|
||||
if (map.isEmpty(x + 1, z + 1))
|
||||
map.setPixel(x + 1, z + 1, outlineColor);
|
||||
if (map.isEmpty(x - 1, z + 1))
|
||||
map.setPixel(x - 1, z + 1, outlineColor);
|
||||
if (map.isEmpty(x, z + 2))
|
||||
map.setPixel(x, z + 2, outlineColor);
|
||||
}
|
||||
}
|
||||
if (phase == PHASE_BACKGROUND)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void highlightYDifferences(TrainMapRenderer map, List<Couple<Integer>> collisions, int mainColor,
|
||||
int darkerColor, int mainColorShadow, int darkerColorShadow) {
|
||||
for (Couple<Integer> couple : collisions) {
|
||||
int x = couple.getFirst();
|
||||
int z = couple.getSecond();
|
||||
int a = map.alphaAt(x, z);
|
||||
if (a == 0)
|
||||
continue;
|
||||
|
||||
for (int xi = x - 2; xi <= x + 2; xi++) {
|
||||
for (int zi = z - 2; zi <= z + 2; zi++) {
|
||||
if (map.alphaAt(xi, zi) >= a)
|
||||
continue;
|
||||
if (map.is(xi, zi, mainColor))
|
||||
map.setPixel(xi, zi, FastColor.ABGR32.color(a, mainColorShadow));
|
||||
else if (map.is(xi, zi, darkerColor))
|
||||
map.setPixel(xi, zi, FastColor.ABGR32.color(a, darkerColorShadow));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int mapYtoAlpha(double y) {
|
||||
int minY = Minecraft.getInstance().level.getMinBuildHeight();
|
||||
return Mth.clamp(32 + Mth.floor((y - minY) / 4.0), 0, 255);
|
||||
}
|
||||
|
||||
private static int markY(int color, double y) {
|
||||
return FastColor.ABGR32.color(mapYtoAlpha(y), color);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
package com.simibubi.create.compat.trainmap;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.simibubi.create.foundation.render.RenderTypes;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.infrastructure.config.CClient;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.MultiBufferSource.BufferSource;
|
||||
import net.minecraft.client.renderer.Rect2i;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.FastColor;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public class TrainMapRenderer implements AutoCloseable {
|
||||
|
||||
public static final TrainMapRenderer INSTANCE = new TrainMapRenderer();
|
||||
public static final int WIDTH = 128, HEIGHT = 128;
|
||||
private Object2ObjectMap<Couple<Integer>, TrainMapInstance> maps = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
public int trackingVersion;
|
||||
public ResourceKey<Level> trackingDim;
|
||||
public CClient.TrainMapTheme trackingTheme;
|
||||
|
||||
//
|
||||
|
||||
private TrainMapInstance previouslyAccessed;
|
||||
|
||||
public void startDrawing() {
|
||||
previouslyAccessed = null;
|
||||
maps.values()
|
||||
.forEach(tmi -> {
|
||||
tmi.getImage()
|
||||
.fillRect(0, 0, WIDTH, HEIGHT, 0);
|
||||
tmi.untouched = true;
|
||||
});
|
||||
}
|
||||
|
||||
public Object2ObjectMap<Couple<Integer>, TrainMapInstance> getMaps() {
|
||||
return maps;
|
||||
}
|
||||
|
||||
public void setPixel(int xCoord, int zCoord, int color) {
|
||||
TrainMapInstance instance = getOrCreateAt(xCoord, zCoord);
|
||||
xCoord = Mth.positiveModulo(xCoord, WIDTH);
|
||||
zCoord = Mth.positiveModulo(zCoord, HEIGHT);
|
||||
instance.getImage()
|
||||
.setPixelRGBA(xCoord, zCoord, color);
|
||||
}
|
||||
|
||||
public int getPixel(int xCoord, int zCoord) {
|
||||
Couple<Integer> sectionKey = toSectionKey(xCoord, zCoord);
|
||||
if (!maps.containsKey(sectionKey))
|
||||
return 0;
|
||||
|
||||
TrainMapInstance instance = getOrCreateAt(xCoord, zCoord);
|
||||
xCoord = Mth.positiveModulo(xCoord, WIDTH);
|
||||
zCoord = Mth.positiveModulo(zCoord, HEIGHT);
|
||||
return instance.getImage()
|
||||
.getPixelRGBA(xCoord, zCoord);
|
||||
}
|
||||
|
||||
public void setPixels(int xCoordFrom, int zCoordFrom, int xCoordTo, int zCoordTo, int color) {
|
||||
for (int x = Math.min(xCoordFrom, xCoordTo); x <= Math.max(xCoordFrom, xCoordTo); x++)
|
||||
for (int z = Math.min(zCoordFrom, zCoordTo); z <= Math.max(zCoordFrom, zCoordTo); z++)
|
||||
setPixel(x, z, color);
|
||||
}
|
||||
|
||||
public void blendPixel(int xCoord, int zCoord, int color, int alpha) {
|
||||
TrainMapInstance instance = getOrCreateAt(xCoord, zCoord);
|
||||
xCoord = Mth.positiveModulo(xCoord, WIDTH);
|
||||
zCoord = Mth.positiveModulo(zCoord, HEIGHT);
|
||||
instance.getImage()
|
||||
.blendPixel(xCoord, zCoord, FastColor.ABGR32.color(alpha, color));
|
||||
}
|
||||
|
||||
public void blendPixels(int xCoordFrom, int zCoordFrom, int xCoordTo, int zCoordTo, int color, int alpha) {
|
||||
for (int x = Math.min(xCoordFrom, xCoordTo); x <= Math.max(xCoordFrom, xCoordTo); x++)
|
||||
for (int z = Math.min(zCoordFrom, zCoordTo); z <= Math.max(zCoordFrom, zCoordTo); z++)
|
||||
blendPixel(x, z, color, alpha);
|
||||
}
|
||||
|
||||
public void finishDrawing() {
|
||||
previouslyAccessed = null;
|
||||
Set<Couple<Integer>> stale = new HashSet<>();
|
||||
|
||||
maps.forEach((key, tmi) -> {
|
||||
if (!tmi.untouched)
|
||||
return;
|
||||
tmi.close();
|
||||
stale.add(key);
|
||||
});
|
||||
|
||||
stale.forEach(key -> {
|
||||
TrainMapInstance tmi = maps.remove(key);
|
||||
if (tmi != null)
|
||||
tmi.close();
|
||||
});
|
||||
}
|
||||
|
||||
public boolean is(int x, int z, int color) {
|
||||
return (getPixel(x, z) & 0xFFFFFF) == (color & 0xFFFFFF);
|
||||
}
|
||||
|
||||
public boolean isEmpty(int x, int z) {
|
||||
return getPixel(x, z) == 0;
|
||||
}
|
||||
|
||||
public int alphaAt(int x, int z) {
|
||||
int pixel = getPixel(x, z);
|
||||
return ((pixel & 0xFFFFFF) != 0) ? ((pixel >>> 24) & 0xFF) : 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float pt, boolean linearFiltering, Rect2i bounds) {
|
||||
BufferSource bufferSource = graphics.bufferSource();
|
||||
PoseStack pose = graphics.pose();
|
||||
maps.forEach((key, tmi) -> {
|
||||
if (tmi.canBeSkipped(bounds))
|
||||
return;
|
||||
int x = key.getFirst();
|
||||
int y = key.getSecond();
|
||||
pose.pushPose();
|
||||
pose.translate(x * WIDTH, y * HEIGHT, 0);
|
||||
tmi.draw(pose, bufferSource, linearFiltering);
|
||||
pose.popPose();
|
||||
});
|
||||
}
|
||||
|
||||
public TrainMapInstance getOrCreateAt(int xCoord, int zCoord) {
|
||||
Couple<Integer> sectionKey = toSectionKey(xCoord, zCoord);
|
||||
if (previouslyAccessed != null && previouslyAccessed.sectionKey.equals(sectionKey))
|
||||
return previouslyAccessed;
|
||||
return maps.compute(sectionKey, (key, instance) -> instance == null ? new TrainMapInstance(key) : instance);
|
||||
}
|
||||
|
||||
public Couple<Integer> toSectionKey(int xCoord, int zCoord) {
|
||||
return Couple.create(Mth.floor(xCoord / (float) WIDTH), Mth.floor(zCoord / (float) HEIGHT));
|
||||
}
|
||||
|
||||
public void resetData() {
|
||||
for (TrainMapInstance instance : maps.values())
|
||||
instance.close();
|
||||
maps.clear();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
this.resetData();
|
||||
}
|
||||
|
||||
public class TrainMapInstance implements AutoCloseable {
|
||||
|
||||
private DynamicTexture texture;
|
||||
private RenderType renderType;
|
||||
private boolean requiresUpload;
|
||||
private boolean linearFiltering;
|
||||
private Rect2i bounds;
|
||||
|
||||
private boolean untouched;
|
||||
private Couple<Integer> sectionKey;
|
||||
|
||||
public ResourceLocation location;
|
||||
|
||||
public TrainMapInstance(Couple<Integer> sectionKey) {
|
||||
TextureManager textureManager = Minecraft.getInstance()
|
||||
.getTextureManager();
|
||||
|
||||
this.sectionKey = sectionKey;
|
||||
untouched = false;
|
||||
requiresUpload = true;
|
||||
texture = new DynamicTexture(128, 128, true);
|
||||
linearFiltering = false;
|
||||
location = textureManager
|
||||
.register("create_trainmap/" + sectionKey.getFirst() + "_" + sectionKey.getSecond(), texture);
|
||||
renderType = RenderTypes.TRAIN_MAP.apply(location, linearFiltering);
|
||||
bounds = new Rect2i(sectionKey.getFirst() * WIDTH, sectionKey.getSecond() * HEIGHT, WIDTH, HEIGHT);
|
||||
}
|
||||
|
||||
public boolean canBeSkipped(Rect2i bounds) {
|
||||
return bounds.getX() + bounds.getWidth() < this.bounds.getX()
|
||||
|| this.bounds.getX() + this.bounds.getWidth() < bounds.getX()
|
||||
|| bounds.getY() + bounds.getHeight() < this.bounds.getY()
|
||||
|| this.bounds.getY() + this.bounds.getHeight() < bounds.getY();
|
||||
}
|
||||
|
||||
public NativeImage getImage() {
|
||||
untouched = false;
|
||||
requiresUpload = true;
|
||||
return texture.getPixels();
|
||||
}
|
||||
|
||||
public void draw(PoseStack pPoseStack, MultiBufferSource pBufferSource, boolean linearFiltering) {
|
||||
if (texture.getPixels() == null)
|
||||
return;
|
||||
|
||||
if (requiresUpload) {
|
||||
texture.upload();
|
||||
requiresUpload = false;
|
||||
}
|
||||
|
||||
if (pPoseStack == null)
|
||||
return;
|
||||
|
||||
if (linearFiltering != this.linearFiltering) {
|
||||
this.linearFiltering = linearFiltering;
|
||||
renderType = RenderTypes.TRAIN_MAP.apply(location, linearFiltering);
|
||||
}
|
||||
|
||||
int pPackedLight = LightTexture.FULL_BRIGHT;
|
||||
|
||||
Matrix4f matrix4f = pPoseStack.last()
|
||||
.pose();
|
||||
VertexConsumer vertexconsumer = pBufferSource.getBuffer(renderType);
|
||||
vertexconsumer.vertex(matrix4f, 0.0F, HEIGHT, 0)
|
||||
.color(255, 255, 255, 255)
|
||||
.uv(0.0F, 1.0F)
|
||||
.uv2(pPackedLight)
|
||||
.endVertex();
|
||||
vertexconsumer.vertex(matrix4f, WIDTH, HEIGHT, 0)
|
||||
.color(255, 255, 255, 255)
|
||||
.uv(1.0F, 1.0F)
|
||||
.uv2(pPackedLight)
|
||||
.endVertex();
|
||||
vertexconsumer.vertex(matrix4f, WIDTH, 0.0F, 0)
|
||||
.color(255, 255, 255, 255)
|
||||
.uv(1.0F, 0.0F)
|
||||
.uv2(pPackedLight)
|
||||
.endVertex();
|
||||
vertexconsumer.vertex(matrix4f, 0.0F, 0.0F, 0)
|
||||
.color(255, 255, 255, 255)
|
||||
.uv(0.0F, 0.0F)
|
||||
.uv2(pPackedLight)
|
||||
.endVertex();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
texture.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,353 @@
|
|||
package com.simibubi.create.compat.trainmap;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.simibubi.create.AllPackets;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.trains.entity.Carriage;
|
||||
import com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity;
|
||||
import com.simibubi.create.content.trains.entity.Train;
|
||||
import com.simibubi.create.content.trains.entity.TravellingPoint;
|
||||
import com.simibubi.create.content.trains.graph.DimensionPalette;
|
||||
import com.simibubi.create.content.trains.graph.EdgePointType;
|
||||
import com.simibubi.create.content.trains.schedule.ScheduleRuntime;
|
||||
import com.simibubi.create.content.trains.signal.SignalBlock.SignalType;
|
||||
import com.simibubi.create.content.trains.signal.SignalBoundary;
|
||||
import com.simibubi.create.content.trains.signal.SignalEdgeGroup;
|
||||
import com.simibubi.create.content.trains.station.GlobalStation;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.event.TickEvent.ServerTickEvent;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
|
||||
public class TrainMapSync {
|
||||
|
||||
public static final int lightPacketInterval = 5;
|
||||
public static final int fullPacketInterval = 10;
|
||||
|
||||
public static int ticks;
|
||||
|
||||
public enum TrainState {
|
||||
RUNNING, RUNNING_MANUALLY, DERAILED, SCHEDULE_INTERRUPTED, CONDUCTOR_MISSING, NAVIGATION_FAILED
|
||||
}
|
||||
|
||||
public enum SignalState {
|
||||
NOT_WAITING, WAITING_FOR_REDSTONE, BLOCK_SIGNAL, CHAIN_SIGNAL
|
||||
}
|
||||
|
||||
public static class TrainMapSyncEntry {
|
||||
|
||||
// Clientside
|
||||
public float[] prevPositions;
|
||||
public List<ResourceKey<Level>> prevDims;
|
||||
|
||||
// Updated every 5 ticks
|
||||
public float[] positions;
|
||||
public List<ResourceKey<Level>> dimensions;
|
||||
public TrainState state = TrainState.RUNNING;
|
||||
public SignalState signalState = SignalState.NOT_WAITING;
|
||||
public boolean fueled = false;
|
||||
public boolean backwards = false;
|
||||
public int targetStationDistance = 0;
|
||||
|
||||
// Updated every 10 ticks
|
||||
public String ownerName = "";
|
||||
public String targetStationName = "";
|
||||
public UUID waitingForTrain = null;
|
||||
|
||||
public void gatherDimensions(DimensionPalette dimensionPalette) {
|
||||
for (ResourceKey<Level> resourceKey : dimensions)
|
||||
if (resourceKey != null)
|
||||
dimensionPalette.encode(resourceKey);
|
||||
}
|
||||
|
||||
public void send(FriendlyByteBuf buffer, DimensionPalette dimensionPalette, boolean light) {
|
||||
buffer.writeVarInt(positions.length);
|
||||
for (float f : positions)
|
||||
buffer.writeFloat(f);
|
||||
|
||||
buffer.writeVarInt(dimensions.size());
|
||||
for (ResourceKey<Level> resourceKey : dimensions)
|
||||
buffer.writeVarInt(resourceKey == null ? -1 : dimensionPalette.encode(resourceKey));
|
||||
|
||||
buffer.writeVarInt(state.ordinal());
|
||||
buffer.writeVarInt(signalState.ordinal());
|
||||
buffer.writeBoolean(fueled);
|
||||
buffer.writeBoolean(backwards);
|
||||
buffer.writeVarInt(targetStationDistance);
|
||||
|
||||
if (light)
|
||||
return;
|
||||
|
||||
buffer.writeUtf(ownerName);
|
||||
buffer.writeUtf(targetStationName);
|
||||
|
||||
buffer.writeBoolean(waitingForTrain != null);
|
||||
if (waitingForTrain != null)
|
||||
buffer.writeUUID(waitingForTrain);
|
||||
}
|
||||
|
||||
public void receive(FriendlyByteBuf buffer, DimensionPalette dimensionPalette, boolean light) {
|
||||
positions = new float[buffer.readVarInt()];
|
||||
for (int i = 0; i < positions.length; i++)
|
||||
positions[i] = buffer.readFloat();
|
||||
|
||||
dimensions = new ArrayList<>();
|
||||
int dimensionsSize = buffer.readVarInt();
|
||||
for (int i = 0; i < dimensionsSize; i++) {
|
||||
int index = buffer.readVarInt();
|
||||
dimensions.add(index == -1 ? null : dimensionPalette.decode(index));
|
||||
}
|
||||
|
||||
state = TrainState.values()[buffer.readVarInt()];
|
||||
signalState = SignalState.values()[buffer.readVarInt()];
|
||||
fueled = buffer.readBoolean();
|
||||
backwards = buffer.readBoolean();
|
||||
targetStationDistance = buffer.readVarInt();
|
||||
|
||||
if (light)
|
||||
return;
|
||||
|
||||
ownerName = buffer.readUtf();
|
||||
targetStationName = buffer.readUtf();
|
||||
|
||||
waitingForTrain = null;
|
||||
if (buffer.readBoolean())
|
||||
waitingForTrain = buffer.readUUID();
|
||||
}
|
||||
|
||||
public void updateFrom(TrainMapSyncEntry other, boolean light) {
|
||||
prevPositions = positions;
|
||||
prevDims = dimensions;
|
||||
|
||||
positions = other.positions;
|
||||
dimensions = other.dimensions;
|
||||
state = other.state;
|
||||
signalState = other.signalState;
|
||||
fueled = other.fueled;
|
||||
backwards = other.backwards;
|
||||
targetStationDistance = other.targetStationDistance;
|
||||
|
||||
if (prevDims != null)
|
||||
for (int i = 0; i < Math.min(prevDims.size(), dimensions.size()); i++)
|
||||
if (prevDims.get(i) != dimensions.get(i))
|
||||
for (int j = 0; j < 6; j++)
|
||||
prevPositions[i * 6 + j] = positions[i * 6 + j];
|
||||
|
||||
if (light)
|
||||
return;
|
||||
|
||||
ownerName = other.ownerName;
|
||||
targetStationName = other.targetStationName;
|
||||
waitingForTrain = other.waitingForTrain;
|
||||
}
|
||||
|
||||
public Vec3 getPosition(int carriageIndex, boolean firstBogey, double time) {
|
||||
int startIndex = carriageIndex * 6 + (firstBogey ? 0 : 3);
|
||||
if (positions == null || positions.length <= startIndex + 2)
|
||||
return Vec3.ZERO;
|
||||
Vec3 position = new Vec3(positions[startIndex], positions[startIndex + 1], positions[startIndex + 2]);
|
||||
if (prevPositions == null || prevPositions.length <= startIndex + 2)
|
||||
return position;
|
||||
Vec3 prevPosition =
|
||||
new Vec3(prevPositions[startIndex], prevPositions[startIndex + 1], prevPositions[startIndex + 2]);
|
||||
return prevPosition.lerp(position, time);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Cache<UUID, WeakReference<ServerPlayer>> requestingPlayers = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(Duration.ofSeconds(1))
|
||||
.build();
|
||||
|
||||
public static void requestReceived(ServerPlayer sender) {
|
||||
boolean sendImmediately = requestingPlayers.getIfPresent(sender.getUUID()) == null;
|
||||
requestingPlayers.put(sender.getUUID(), new WeakReference<>(sender));
|
||||
if (sendImmediately)
|
||||
send(sender.server, false);
|
||||
}
|
||||
|
||||
public static void serverTick(ServerTickEvent event) {
|
||||
ticks++;
|
||||
if (ticks % fullPacketInterval == 0)
|
||||
send(event.getServer(), false);
|
||||
else if (ticks % lightPacketInterval == 0)
|
||||
send(event.getServer(), true);
|
||||
}
|
||||
|
||||
public static void send(MinecraftServer minecraftServer, boolean light) {
|
||||
if (requestingPlayers.size() == 0)
|
||||
return;
|
||||
|
||||
TrainMapSyncPacket packet = new TrainMapSyncPacket(light);
|
||||
for (Train train : Create.RAILWAYS.trains.values())
|
||||
packet.add(train.id, createEntry(minecraftServer, train));
|
||||
|
||||
for (WeakReference<ServerPlayer> weakReference : requestingPlayers.asMap()
|
||||
.values()) {
|
||||
ServerPlayer player = weakReference.get();
|
||||
if (player == null)
|
||||
continue;
|
||||
AllPackets.getChannel()
|
||||
.send(PacketDistributor.PLAYER.with(() -> player), packet);
|
||||
}
|
||||
}
|
||||
|
||||
private static TrainMapSyncEntry createEntry(MinecraftServer minecraftServer, Train train) {
|
||||
TrainMapSyncEntry entry = new TrainMapSyncEntry();
|
||||
boolean stopped = Math.abs(train.speed) < 0.05;
|
||||
|
||||
entry.positions = new float[train.carriages.size() * 6];
|
||||
entry.dimensions = new ArrayList<>();
|
||||
|
||||
List<Carriage> carriages = train.carriages;
|
||||
for (int i = 0; i < carriages.size(); i++) {
|
||||
Carriage carriage = carriages.get(i);
|
||||
Vec3 leadingPos;
|
||||
Vec3 trailingPos;
|
||||
|
||||
if (train.graph == null) {
|
||||
|
||||
// Train is derailed
|
||||
Pair<ResourceKey<Level>, DimensionalCarriageEntity> dimCarriage =
|
||||
carriage.anyAvailableDimensionalCarriage();
|
||||
if (dimCarriage == null || carriage.presentInMultipleDimensions()) {
|
||||
entry.dimensions.add(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
leadingPos = dimCarriage.getSecond().rotationAnchors.getFirst();
|
||||
trailingPos = dimCarriage.getSecond().rotationAnchors.getSecond();
|
||||
|
||||
if (leadingPos == null || trailingPos == null) {
|
||||
entry.dimensions.add(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
entry.dimensions.add(dimCarriage.getFirst());
|
||||
|
||||
} else {
|
||||
|
||||
// Train is on Track
|
||||
TravellingPoint leading = carriage.getLeadingPoint();
|
||||
TravellingPoint trailing = carriage.getTrailingPoint();
|
||||
if (leading == null || trailing == null || leading.edge == null || trailing.edge == null) {
|
||||
entry.dimensions.add(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceKey<Level> leadingDim =
|
||||
(leading.node1 == null || leading.edge == null || leading.edge.isInterDimensional()) ? null
|
||||
: leading.node1.getLocation()
|
||||
.getDimension();
|
||||
|
||||
ResourceKey<Level> trailingDim =
|
||||
(trailing.node1 == null || trailing.edge == null || trailing.edge.isInterDimensional()) ? null
|
||||
: trailing.node1.getLocation()
|
||||
.getDimension();
|
||||
|
||||
ResourceKey<Level> carriageDim = (leadingDim == null || leadingDim != trailingDim) ? null : leadingDim;
|
||||
entry.dimensions.add(carriageDim);
|
||||
|
||||
leadingPos = leading.getPosition(train.graph);
|
||||
trailingPos = trailing.getPosition(train.graph);
|
||||
}
|
||||
|
||||
entry.positions[i * 6] = (float) leadingPos.x();
|
||||
entry.positions[i * 6 + 1] = (float) leadingPos.y();
|
||||
entry.positions[i * 6 + 2] = (float) leadingPos.z();
|
||||
|
||||
entry.positions[i * 6 + 3] = (float) trailingPos.x();
|
||||
entry.positions[i * 6 + 4] = (float) trailingPos.y();
|
||||
entry.positions[i * 6 + 5] = (float) trailingPos.z();
|
||||
}
|
||||
|
||||
entry.backwards = train.currentlyBackwards;
|
||||
|
||||
if (train.owner != null) {
|
||||
ServerPlayer owner = minecraftServer.getPlayerList()
|
||||
.getPlayer(train.owner);
|
||||
if (owner != null)
|
||||
entry.ownerName = owner.getName()
|
||||
.getString();
|
||||
}
|
||||
|
||||
if (train.derailed) {
|
||||
entry.state = TrainState.DERAILED;
|
||||
return entry;
|
||||
}
|
||||
|
||||
ScheduleRuntime runtime = train.runtime;
|
||||
if (runtime.getSchedule() != null && stopped) {
|
||||
if (runtime.paused) {
|
||||
entry.state = TrainState.SCHEDULE_INTERRUPTED;
|
||||
return entry;
|
||||
}
|
||||
|
||||
if (train.status.conductor) {
|
||||
entry.state = TrainState.CONDUCTOR_MISSING;
|
||||
return entry;
|
||||
}
|
||||
|
||||
if (train.status.navigation) {
|
||||
entry.state = TrainState.NAVIGATION_FAILED;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
if ((runtime.getSchedule() == null || runtime.paused) && train.speed != 0)
|
||||
entry.state = TrainState.RUNNING_MANUALLY;
|
||||
|
||||
GlobalStation currentStation = train.getCurrentStation();
|
||||
if (currentStation != null) {
|
||||
entry.targetStationName = currentStation.name;
|
||||
entry.targetStationDistance = 0;
|
||||
} else if (train.navigation.destination != null && !runtime.paused) {
|
||||
entry.targetStationName = train.navigation.destination.name;
|
||||
entry.targetStationDistance = Math.max(0, Mth.floor(train.navigation.distanceToDestination));
|
||||
}
|
||||
|
||||
if (stopped && train.navigation.waitingForSignal != null) {
|
||||
UUID signalId = train.navigation.waitingForSignal.getFirst();
|
||||
boolean side = train.navigation.waitingForSignal.getSecond();
|
||||
SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, signalId);
|
||||
|
||||
if (signal != null) {
|
||||
boolean chainSignal = signal.types.get(side) == SignalType.CROSS_SIGNAL;
|
||||
entry.signalState = chainSignal ? SignalState.CHAIN_SIGNAL : SignalState.BLOCK_SIGNAL;
|
||||
if (signal.isForcedRed(side))
|
||||
entry.signalState = SignalState.WAITING_FOR_REDSTONE;
|
||||
else {
|
||||
SignalEdgeGroup group = Create.RAILWAYS.signalEdgeGroups.get(signal.groups.get(side));
|
||||
if (group != null) {
|
||||
for (Train other : group.trains) {
|
||||
if (other == train)
|
||||
continue;
|
||||
entry.waitingForTrain = other.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (train.fuelTicks > 0 && !stopped)
|
||||
entry.fueled = true;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.simibubi.create.compat.trainmap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.AllPackets;
|
||||
import com.simibubi.create.compat.trainmap.TrainMapSync.TrainMapSyncEntry;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
public class TrainMapSyncClient {
|
||||
|
||||
public static Map<UUID, TrainMapSyncEntry> currentData = new HashMap<>();
|
||||
|
||||
public static double lastPacket;
|
||||
|
||||
private static int ticks;
|
||||
|
||||
public static void requestData() {
|
||||
ticks++;
|
||||
if (ticks % 5 == 0)
|
||||
AllPackets.getChannel()
|
||||
.sendToServer(new TrainMapSyncRequestPacket());
|
||||
}
|
||||
|
||||
public static void stopRequesting() {
|
||||
ticks = 0;
|
||||
currentData.clear();
|
||||
}
|
||||
|
||||
public static void receive(TrainMapSyncPacket packet) {
|
||||
if (ticks == 0)
|
||||
return;
|
||||
|
||||
lastPacket = AnimationTickHolder.getTicks();
|
||||
lastPacket += AnimationTickHolder.getPartialTicks();
|
||||
|
||||
Set<UUID> staleEntries = new HashSet<>();
|
||||
staleEntries.addAll(currentData.keySet());
|
||||
|
||||
for (Pair<UUID, TrainMapSyncEntry> pair : packet.entries) {
|
||||
UUID id = pair.getFirst();
|
||||
TrainMapSyncEntry entry = pair.getSecond();
|
||||
staleEntries.remove(id);
|
||||
currentData.computeIfAbsent(id, $ -> entry)
|
||||
.updateFrom(entry, packet.light);
|
||||
}
|
||||
|
||||
for (UUID uuid : staleEntries)
|
||||
currentData.remove(uuid);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.simibubi.create.compat.trainmap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.compat.trainmap.TrainMapSync.TrainMapSyncEntry;
|
||||
import com.simibubi.create.content.trains.graph.DimensionPalette;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent.Context;
|
||||
|
||||
public class TrainMapSyncPacket extends SimplePacketBase {
|
||||
|
||||
public List<Pair<UUID, TrainMapSyncEntry>> entries = new ArrayList<>();
|
||||
public boolean light;
|
||||
|
||||
public TrainMapSyncPacket(boolean light) {
|
||||
this.light = light;
|
||||
}
|
||||
|
||||
public void add(UUID trainId, TrainMapSyncEntry data) {
|
||||
entries.add(Pair.of(trainId, data));
|
||||
}
|
||||
|
||||
public TrainMapSyncPacket(FriendlyByteBuf buffer) {
|
||||
DimensionPalette dimensionPalette = DimensionPalette.receive(buffer);
|
||||
light = buffer.readBoolean();
|
||||
|
||||
int size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
UUID id = buffer.readUUID();
|
||||
TrainMapSyncEntry entry = new TrainMapSyncEntry();
|
||||
entry.receive(buffer, dimensionPalette, light);
|
||||
entries.add(Pair.of(id, entry));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
DimensionPalette dimensionPalette = new DimensionPalette();
|
||||
for (Pair<UUID, TrainMapSyncEntry> pair : entries)
|
||||
pair.getSecond()
|
||||
.gatherDimensions(dimensionPalette);
|
||||
|
||||
dimensionPalette.send(buffer);
|
||||
buffer.writeBoolean(light);
|
||||
|
||||
buffer.writeVarInt(entries.size());
|
||||
for (Pair<UUID, TrainMapSyncEntry> pair : entries) {
|
||||
buffer.writeUUID(pair.getFirst());
|
||||
pair.getSecond()
|
||||
.send(buffer, dimensionPalette, light);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(Context context) {
|
||||
context.enqueueWork(() -> TrainMapSyncClient.receive(this));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.simibubi.create.compat.trainmap;
|
||||
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent.Context;
|
||||
|
||||
public class TrainMapSyncRequestPacket extends SimplePacketBase {
|
||||
|
||||
public TrainMapSyncRequestPacket() {}
|
||||
|
||||
public TrainMapSyncRequestPacket(FriendlyByteBuf buffer) {}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {}
|
||||
|
||||
@Override
|
||||
public boolean handle(Context context) {
|
||||
context.enqueueWork(() -> TrainMapSync.requestReceived(context.getSender()));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1143,6 +1143,7 @@ public abstract class Contraption {
|
|||
if (blockEntity instanceof IMultiBlockEntityContainer) {
|
||||
if (tag.contains("LastKnownPos") || capturedMultiblocks.isEmpty()) {
|
||||
tag.put("LastKnownPos", NbtUtils.writeBlockPos(BlockPos.ZERO.below(Integer.MAX_VALUE - 1)));
|
||||
tag.remove("Controller");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1199,6 +1200,9 @@ public abstract class Contraption {
|
|||
// swap nbt data to the new controller position
|
||||
StructureBlockInfo prevControllerInfo = blocks.get(controllerPos);
|
||||
StructureBlockInfo newControllerInfo = blocks.get(otherPos);
|
||||
if (prevControllerInfo == null || newControllerInfo == null)
|
||||
return;
|
||||
|
||||
blocks.put(otherPos, new StructureBlockInfo(newControllerInfo.pos(), newControllerInfo.state(), prevControllerInfo.nbt()));
|
||||
blocks.put(controllerPos, new StructureBlockInfo(prevControllerInfo.pos(), prevControllerInfo.state(), newControllerInfo.nbt()));
|
||||
});
|
||||
|
@ -1384,6 +1388,9 @@ public abstract class Contraption {
|
|||
|
||||
private void gatherBBsOffThread() {
|
||||
getContraptionWorld();
|
||||
if (simplifiedEntityColliderProvider != null) {
|
||||
simplifiedEntityColliderProvider.cancel(false);
|
||||
}
|
||||
simplifiedEntityColliderProvider = CompletableFuture.supplyAsync(() -> {
|
||||
VoxelShape combinedShape = Shapes.empty();
|
||||
for (Entry<BlockPos, StructureBlockInfo> entry : blocks.entrySet()) {
|
||||
|
@ -1400,7 +1407,6 @@ public abstract class Contraption {
|
|||
})
|
||||
.thenAccept(r -> {
|
||||
simplifiedEntityColliders = Optional.of(r);
|
||||
simplifiedEntityColliderProvider = null;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions;
|
|||
|
||||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.AllTags.AllBlockTags;
|
||||
import com.simibubi.create.content.equipment.toolbox.ToolboxInventory;
|
||||
import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlockEntity;
|
||||
import com.simibubi.create.content.logistics.crate.BottomlessItemHandler;
|
||||
import com.simibubi.create.content.logistics.vault.ItemVaultBlockEntity;
|
||||
|
@ -176,6 +177,8 @@ public class MountedStorage {
|
|||
CompoundTag tag = handler.serializeNBT();
|
||||
if (noFuel)
|
||||
NBTHelper.putMarker(tag, "NoFuel");
|
||||
if (handler instanceof ToolboxInventory)
|
||||
NBTHelper.putMarker(tag, "Toolbox");
|
||||
if (!(handler instanceof BottomlessItemHandler))
|
||||
return tag;
|
||||
|
||||
|
@ -190,6 +193,9 @@ public class MountedStorage {
|
|||
storage.handler = new ItemStackHandler();
|
||||
if (nbt == null)
|
||||
return storage;
|
||||
if (nbt.contains("Toolbox"))
|
||||
storage.handler = new ToolboxInventory(null);
|
||||
|
||||
storage.valid = true;
|
||||
storage.noFuel = nbt.contains("NoFuel");
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@ public class ClipboardBlockEntity extends SmartBlockEntity {
|
|||
protected void read(CompoundTag tag, boolean clientPacket) {
|
||||
super.read(tag, clientPacket);
|
||||
dataContainer = ItemStack.of(tag.getCompound("Item"));
|
||||
if (!AllBlocks.CLIPBOARD.isIn(dataContainer))
|
||||
dataContainer = AllBlocks.CLIPBOARD.asStack();
|
||||
|
||||
if (clientPacket)
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> readClientSide(tag));
|
||||
|
|
|
@ -52,19 +52,13 @@ public class SymmetryHandler {
|
|||
if (event.getLevel()
|
||||
.isClientSide())
|
||||
return;
|
||||
if (!(event.getEntity() instanceof Player))
|
||||
if (!(event.getEntity() instanceof Player player))
|
||||
return;
|
||||
|
||||
Player player = (Player) event.getEntity();
|
||||
Inventory inv = player.getInventory();
|
||||
for (int i = 0; i < Inventory.getSelectionSize(); i++) {
|
||||
if (!inv.getItem(i)
|
||||
.isEmpty()
|
||||
&& inv.getItem(i)
|
||||
.getItem() == AllItems.WAND_OF_SYMMETRY.get()) {
|
||||
for (int i = 0; i < Inventory.getSelectionSize(); i++)
|
||||
if (AllItems.WAND_OF_SYMMETRY.isIn(inv.getItem(i)))
|
||||
SymmetryWandItem.apply(player.level(), inv.getItem(i), player, event.getPos(), event.getPlacedBlock());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
|
@ -75,12 +69,9 @@ public class SymmetryHandler {
|
|||
|
||||
Player player = event.getPlayer();
|
||||
Inventory inv = player.getInventory();
|
||||
for (int i = 0; i < Inventory.getSelectionSize(); i++) {
|
||||
if (!inv.getItem(i)
|
||||
.isEmpty() && AllItems.WAND_OF_SYMMETRY.isIn(inv.getItem(i))) {
|
||||
for (int i = 0; i < Inventory.getSelectionSize(); i++)
|
||||
if (AllItems.WAND_OF_SYMMETRY.isIn(inv.getItem(i)))
|
||||
SymmetryWandItem.remove(player.level(), inv.getItem(i), player, event.getPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.util.function.Consumer;
|
|||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllPackets;
|
||||
import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlock;
|
||||
import com.simibubi.create.content.equipment.symmetryWand.mirror.CrossPlaneMirror;
|
||||
|
@ -27,6 +28,7 @@ import net.minecraft.nbt.CompoundTag;
|
|||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
@ -328,5 +330,13 @@ public class SymmetryWandItem extends Item {
|
|||
public void initializeClient(Consumer<IClientItemExtensions> consumer) {
|
||||
consumer.accept(SimpleCustomRenderer.create(this, new SymmetryWandItemRenderer()));
|
||||
}
|
||||
|
||||
public static boolean presentInHotbar(Player player) {
|
||||
Inventory inv = player.getInventory();
|
||||
for (int i = 0; i < Inventory.getSelectionSize(); i++)
|
||||
if (AllItems.WAND_OF_SYMMETRY.isIn(inv.getItem(i)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ public class ToolboxInventory extends ItemStackHandler {
|
|||
}
|
||||
}
|
||||
settling = false;
|
||||
blockEntity.sendData();
|
||||
notifyUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,7 +109,7 @@ public class ToolboxInventory extends ItemStackHandler {
|
|||
if (!stack.isEmpty() && filters.get(compartment)
|
||||
.isEmpty()) {
|
||||
filters.set(compartment, ItemHandlerHelper.copyStackWithSize(stack, 1));
|
||||
blockEntity.sendData();
|
||||
notifyUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ public class ToolboxInventory extends ItemStackHandler {
|
|||
if (!stack.isEmpty() && filters.get(compartment)
|
||||
.isEmpty()) {
|
||||
filters.set(compartment, ItemHandlerHelper.copyStackWithSize(stack, 1));
|
||||
blockEntity.sendData();
|
||||
notifyUpdate();
|
||||
}
|
||||
}
|
||||
return insertItem;
|
||||
|
@ -136,10 +136,9 @@ public class ToolboxInventory extends ItemStackHandler {
|
|||
|
||||
@Override
|
||||
protected void onContentsChanged(int slot) {
|
||||
if (!settling && !blockEntity.getLevel().isClientSide)
|
||||
if (!settling && (blockEntity == null || !blockEntity.getLevel().isClientSide))
|
||||
settle(slot / STACKS_PER_COMPARTMENT);
|
||||
blockEntity.sendData();
|
||||
blockEntity.setChanged();
|
||||
notifyUpdate();
|
||||
super.onContentsChanged(slot);
|
||||
}
|
||||
|
||||
|
@ -208,4 +207,9 @@ public class ToolboxInventory extends ItemStackHandler {
|
|||
return ItemHandlerHelper.canItemStacksStack(stack1, stack2);
|
||||
}
|
||||
|
||||
private void notifyUpdate() {
|
||||
if (blockEntity != null)
|
||||
blockEntity.notifyUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.fluids.drain;
|
|||
|
||||
import com.simibubi.create.content.fluids.transfer.GenericItemEmptying;
|
||||
import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
@ -38,7 +39,8 @@ public class ItemDrainItemHandler implements IItemHandler {
|
|||
if (stack.getCount() > 1 && GenericItemEmptying.canItemBeEmptied(blockEntity.getLevel(), stack)) {
|
||||
returned = ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - 1);
|
||||
stack = ItemHandlerHelper.copyStackWithSize(stack, 1);
|
||||
}
|
||||
} else
|
||||
returned = ItemHelper.limitCountToMaxStackSize(stack, simulate);
|
||||
|
||||
if (!simulate) {
|
||||
TransportedItemStack heldItem = new TransportedItemStack(stack);
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.simibubi.create.content.fluids.tank;
|
|||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.api.connectivity.ConnectivityHandler;
|
||||
import com.simibubi.create.content.equipment.symmetryWand.SymmetryWandItem;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
|
@ -75,6 +76,8 @@ public class FluidTankItem extends BlockItem {
|
|||
|
||||
if (!FluidTankBlock.isTank(placedOnState))
|
||||
return;
|
||||
if (SymmetryWandItem.presentInHotbar(player))
|
||||
return;
|
||||
boolean creative = getBlock().equals(AllBlocks.CREATIVE_FLUID_TANK.get());
|
||||
FluidTankBlockEntity tankAt = ConnectivityHandler.partAt(
|
||||
creative ? AllBlockEntityTypes.CREATIVE_FLUID_TANK.get() : AllBlockEntityTypes.FLUID_TANK.get(), world, placedOnPos
|
||||
|
|
|
@ -73,9 +73,8 @@ public abstract class GeneratingKineticBlockEntity extends KineticBlockEntity {
|
|||
float speed = getTheoreticalSpeed();
|
||||
if (speed != getGeneratedSpeed() && speed != 0)
|
||||
stressBase *= getGeneratedSpeed() / speed;
|
||||
speed = Math.abs(speed);
|
||||
|
||||
float stressTotal = stressBase * speed;
|
||||
float stressTotal = Math.abs(stressBase * speed);
|
||||
|
||||
CreateLang.number(stressTotal)
|
||||
.translate("generic.unit.stress")
|
||||
|
|
|
@ -218,6 +218,8 @@ public class BeltBlock extends HorizontalKineticBlock
|
|||
.copy(), false);
|
||||
if (remainder.isEmpty())
|
||||
itemEntity.discard();
|
||||
else if (remainder.getCount() != itemEntity.getItem().getCount())
|
||||
itemEntity.setItem(remainder);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ public class BeltRenderer extends SafeBlockEntityRenderer<BeltBlockEntity> {
|
|||
be.getBlockPos().getZ())
|
||||
.add(offsetVec);
|
||||
|
||||
if (this.shouldCullItem(itemPos)) {
|
||||
if (this.shouldCullItem(itemPos, be.getLevel())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.simibubi.create.content.kinetics.belt.transport;
|
||||
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
|
@ -29,6 +31,7 @@ public class ItemHandlerBeltSegment implements IItemHandler {
|
|||
@Override
|
||||
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
|
||||
if (this.beltInventory.canInsertAt(offset)) {
|
||||
ItemStack remainder = ItemHelper.limitCountToMaxStackSize(stack, simulate);
|
||||
if (!simulate) {
|
||||
TransportedItemStack newStack = new TransportedItemStack(stack);
|
||||
newStack.insertedAt = offset;
|
||||
|
@ -38,7 +41,7 @@ public class ItemHandlerBeltSegment implements IItemHandler {
|
|||
this.beltInventory.belt.setChanged();
|
||||
this.beltInventory.belt.sendData();
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
return remainder;
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
|
|
@ -120,6 +120,12 @@ public class MechanicalCrafterBlockEntity extends KineticBlockEntity {
|
|||
registerAwardables(behaviours, AllAdvancements.CRAFTER, AllAdvancements.CRAFTER_LAZY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
inserting.removeListener();
|
||||
super.invalidateCaps();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeedChanged(float previousSpeed) {
|
||||
super.onSpeedChanged(previousSpeed);
|
||||
|
@ -132,6 +138,7 @@ public class MechanicalCrafterBlockEntity extends KineticBlockEntity {
|
|||
|
||||
public void blockChanged() {
|
||||
removeBehaviour(InvManipulationBehaviour.TYPE);
|
||||
inserting.removeListener();
|
||||
inserting = new InvManipulationBehaviour(this, this::getTargetFace);
|
||||
attachBehaviourLate(inserting);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.simibubi.create.content.kinetics.deployer;
|
||||
|
||||
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
@ -52,9 +53,10 @@ public class DeployerItemHandler implements IItemHandlerModifiable {
|
|||
|
||||
ItemStack held = getHeld();
|
||||
if (held.isEmpty()) {
|
||||
ItemStack remainder = ItemHelper.limitCountToMaxStackSize(stack, simulate);
|
||||
if (!simulate)
|
||||
set(stack);
|
||||
return ItemStack.EMPTY;
|
||||
return remainder;
|
||||
}
|
||||
|
||||
if (!ItemHandlerHelper.canItemStacksStack(held, stack))
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.simibubi.create.content.logistics.chute;
|
||||
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
|
@ -25,9 +27,10 @@ public class ChuteItemHandler implements IItemHandler {
|
|||
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
|
||||
if (!blockEntity.canAcceptItem(stack))
|
||||
return stack;
|
||||
ItemStack remainder = ItemHelper.limitCountToMaxStackSize(stack, simulate);
|
||||
if (!simulate)
|
||||
blockEntity.setItem(stack);
|
||||
return ItemStack.EMPTY;
|
||||
return remainder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -93,7 +93,7 @@ public abstract class FunnelBlock extends AbstractDirectionalFunnelBlock {
|
|||
withBlockEntityDo(worldIn, pos, be -> {
|
||||
ItemStack toInsert = heldItem.copy();
|
||||
ItemStack remainder = tryInsert(worldIn, pos, toInsert, false);
|
||||
if (!ItemStack.matches(remainder, toInsert))
|
||||
if (!ItemStack.matches(remainder, toInsert) || remainder.getCount() != heldItem.getCount())
|
||||
player.setItemInHand(handIn, remainder);
|
||||
});
|
||||
return InteractionResult.SUCCESS;
|
||||
|
|
|
@ -273,6 +273,12 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
|
|||
registerAwardables(behaviours, AllAdvancements.FUNNEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
invManipulation.removeListener();
|
||||
super.invalidateCaps();
|
||||
}
|
||||
|
||||
private boolean supportsAmountOnFilter() {
|
||||
BlockState blockState = getBlockState();
|
||||
boolean beltFunnelsupportsAmount = false;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.simibubi.create.content.logistics.tunnel;
|
||||
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
@ -33,9 +35,11 @@ public class BrassTunnelItemHandler implements IItemHandler {
|
|||
|
||||
if (!blockEntity.canTakeItems())
|
||||
return stack;
|
||||
|
||||
ItemStack remainder = ItemHelper.limitCountToMaxStackSize(stack, simulate);
|
||||
if (!simulate)
|
||||
blockEntity.setStackToDistribute(stack, null);
|
||||
return ItemStack.EMPTY;
|
||||
return remainder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.vault;
|
|||
|
||||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.api.connectivity.ConnectivityHandler;
|
||||
import com.simibubi.create.content.equipment.symmetryWand.SymmetryWandItem;
|
||||
|
||||
import net.createmod.catnip.utility.VecHelper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -65,6 +66,8 @@ public class ItemVaultItem extends BlockItem {
|
|||
|
||||
if (!ItemVaultBlock.isVault(placedOnState))
|
||||
return;
|
||||
if (SymmetryWandItem.presentInHotbar(player))
|
||||
return;
|
||||
ItemVaultBlockEntity tankAt = ConnectivityHandler.partAt(AllBlockEntityTypes.ITEM_VAULT.get(), world, placedOnPos);
|
||||
if (tankAt == null)
|
||||
return;
|
||||
|
|
|
@ -411,7 +411,8 @@ public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
|
|||
if (filter != null && !filter.test(itemStack))
|
||||
continue;
|
||||
|
||||
visualizedOutputItems.add(IntAttached.withZero(itemStack));
|
||||
if (visualizedOutputItems.size() < 3)
|
||||
visualizedOutputItems.add(IntAttached.withZero(itemStack));
|
||||
update = true;
|
||||
|
||||
remainder = ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), false);
|
||||
|
@ -445,7 +446,8 @@ public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
|
|||
|
||||
update = true;
|
||||
iterator.remove();
|
||||
visualizedOutputFluids.add(IntAttached.withZero(fluidStack));
|
||||
if (visualizedOutputFluids.size() < 3)
|
||||
visualizedOutputFluids.add(IntAttached.withZero(fluidStack));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStat
|
|||
import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity;
|
||||
import com.simibubi.create.content.trains.display.FlapDisplayLayout;
|
||||
import com.simibubi.create.foundation.gui.ModularGuiLineBuilder;
|
||||
import com.simibubi.create.foundation.utility.NBTProcessors;
|
||||
|
||||
import net.createmod.catnip.utility.lang.Components;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
@ -38,6 +39,12 @@ public abstract class DisplaySource extends DisplayBehaviour {
|
|||
List<MutableComponent> text = provideText(context, stats);
|
||||
if (text.isEmpty())
|
||||
text = EMPTY;
|
||||
|
||||
if (activeTarget.requiresComponentSanitization())
|
||||
for (MutableComponent component : text)
|
||||
if (NBTProcessors.textComponentHasClickEvent(component))
|
||||
return; // Naughty
|
||||
|
||||
activeTarget.acceptText(line, text, context);
|
||||
}
|
||||
|
||||
|
|
|
@ -67,5 +67,9 @@ public abstract class DisplayTarget extends DisplayBehaviour {
|
|||
tag.remove("DisplayLink");
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean requiresComponentSanitization() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -80,5 +80,10 @@ public class LecternDisplayTarget extends DisplayTarget {
|
|||
|
||||
return written;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresComponentSanitization() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,5 +41,10 @@ public class SignDisplayTarget extends DisplayTarget {
|
|||
public DisplayTargetStats provideStats(DisplayLinkContext context) {
|
||||
return new DisplayTargetStats(4, 15, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresComponentSanitization() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,6 +56,13 @@ public class SmartObserverBlockEntity extends SmartBlockEntity {
|
|||
behaviours.add(observedTank = new TankManipulationBehaviour(this, towardBlockFacing).bypassSidedness());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
observedInventory.removeListener();
|
||||
observedTank.removeListener();
|
||||
super.invalidateCaps();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
|
|
@ -233,6 +233,13 @@ public class ThresholdSwitchBlockEntity extends SmartBlockEntity {
|
|||
behaviours.add(observedTank = new TankManipulationBehaviour(this, towardBlockFacing).bypassSidedness());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
observedInventory.removeListener();
|
||||
observedTank.removeListener();
|
||||
super.invalidateCaps();
|
||||
}
|
||||
|
||||
public float getLevelForDisplay() {
|
||||
return currentLevel == -1 ? 0 : currentLevel;
|
||||
}
|
||||
|
|
|
@ -169,6 +169,7 @@ public class SchematicHandler implements IGuiOverlay {
|
|||
schematic.placeInWorld(w, pos, pos, placementSettings, w.getRandom(), Block.UPDATE_CLIENTS);
|
||||
for (BlockEntity blockEntity : w.getBlockEntities())
|
||||
blockEntity.setLevel(w);
|
||||
w.fixControllerBlockEntities();
|
||||
} catch (Exception e) {
|
||||
Minecraft.getInstance().player.displayClientMessage(CreateLang.translate("schematic.error")
|
||||
.component(), false);
|
||||
|
@ -183,6 +184,7 @@ public class SchematicHandler implements IGuiOverlay {
|
|||
placementSettings.getMirror());
|
||||
for (BlockEntity be : wMirroredFB.getRenderedBlockEntities())
|
||||
transform.apply(be);
|
||||
wMirroredFB.fixControllerBlockEntities();
|
||||
|
||||
placementSettings.setMirror(Mirror.LEFT_RIGHT);
|
||||
pos = BlockPos.ZERO.south(size.getZ() - 1);
|
||||
|
@ -191,6 +193,7 @@ public class SchematicHandler implements IGuiOverlay {
|
|||
placementSettings.getMirror());
|
||||
for (BlockEntity be : wMirroredLR.getRenderedBlockEntities())
|
||||
transform.apply(be);
|
||||
wMirroredLR.fixControllerBlockEntities();
|
||||
|
||||
renderers.get(0)
|
||||
.display(w);
|
||||
|
|
|
@ -48,6 +48,8 @@ public class GlobalRailwayManager {
|
|||
private List<Train> waitingTrains;
|
||||
|
||||
private RailwaySavedData savedData;
|
||||
|
||||
public int version;
|
||||
|
||||
public GlobalRailwayManager() {
|
||||
cleanUp();
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.simibubi.create.foundation.advancement.AllAdvancements;
|
|||
import net.createmod.catnip.utility.Couple;
|
||||
import net.createmod.catnip.utility.Iterate;
|
||||
import net.createmod.catnip.utility.NBTHelper;
|
||||
import net.createmod.catnip.utility.Pair;
|
||||
import net.createmod.catnip.utility.VecHelper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -431,6 +432,13 @@ public class Carriage {
|
|||
return null;
|
||||
}
|
||||
|
||||
public Pair<ResourceKey<Level>, DimensionalCarriageEntity> anyAvailableDimensionalCarriage() {
|
||||
for (Entry<ResourceKey<Level>, DimensionalCarriageEntity> entry : entities.entrySet())
|
||||
if (entry.getValue().entity.get() != null)
|
||||
return Pair.of(entry.getKey(), entry.getValue());
|
||||
return null;
|
||||
}
|
||||
|
||||
public void forEachPresentEntity(Consumer<CarriageContraptionEntity> callback) {
|
||||
for (DimensionalCarriageEntity dimensionalCarriageEntity : entities.values()) {
|
||||
CarriageContraptionEntity entity = dimensionalCarriageEntity.entity.get();
|
||||
|
|
|
@ -95,6 +95,7 @@ public class Train {
|
|||
public Navigation navigation;
|
||||
public ScheduleRuntime runtime;
|
||||
public TrainIconType icon;
|
||||
public int mapColorIndex;
|
||||
public Component name;
|
||||
public TrainStatus status;
|
||||
|
||||
|
@ -932,6 +933,8 @@ public class Train {
|
|||
|
||||
@Nullable
|
||||
public LivingEntity getOwner(Level level) {
|
||||
if (level.getServer() == null)
|
||||
return null;
|
||||
try {
|
||||
UUID uuid = owner;
|
||||
return uuid == null ? null
|
||||
|
@ -1130,6 +1133,7 @@ public class Train {
|
|||
tag.putInt("Fuel", fuelTicks);
|
||||
tag.putDouble("TargetSpeed", targetSpeed);
|
||||
tag.putString("IconType", icon.id.toString());
|
||||
tag.putInt("MapColorIndex", mapColorIndex);
|
||||
tag.putString("Name", Component.Serializer.toJson(name));
|
||||
if (currentStation != null)
|
||||
tag.putUUID("Station", currentStation);
|
||||
|
@ -1182,6 +1186,7 @@ public class Train {
|
|||
train.speedBeforeStall = tag.getDouble("SpeedBeforeStall");
|
||||
train.targetSpeed = tag.getDouble("TargetSpeed");
|
||||
train.icon = TrainIconType.byId(new ResourceLocation(tag.getString("IconType")));
|
||||
train.mapColorIndex = tag.getInt("MapColorIndex");
|
||||
train.name = Component.Serializer.fromJson(tag.getString("Name"));
|
||||
train.currentStation = tag.contains("Station") ? tag.getUUID("Station") : null;
|
||||
train.currentlyBackwards = tag.getBoolean("Backwards");
|
||||
|
|
|
@ -68,6 +68,7 @@ public class TrainPacket extends SimplePacketBase {
|
|||
|
||||
train.name = Component.Serializer.fromJson(buffer.readUtf());
|
||||
train.icon = TrainIconType.byId(buffer.readResourceLocation());
|
||||
train.mapColorIndex = buffer.readVarInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,6 +106,7 @@ public class TrainPacket extends SimplePacketBase {
|
|||
buffer.writeBoolean(train.doubleEnded);
|
||||
buffer.writeUtf(Component.Serializer.toJson(train.name));
|
||||
buffer.writeResourceLocation(train.icon.id);
|
||||
buffer.writeVarInt(train.mapColorIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,9 +21,9 @@ public class TrainStatus {
|
|||
|
||||
Train train;
|
||||
|
||||
boolean navigation;
|
||||
boolean track;
|
||||
boolean conductor;
|
||||
public boolean navigation;
|
||||
public boolean track;
|
||||
public boolean conductor;
|
||||
|
||||
List<StatusMessage> queued = new ArrayList<>();
|
||||
|
||||
|
|
|
@ -171,6 +171,8 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
|||
|
||||
@Override
|
||||
protected void handle(GlobalRailwayManager manager, TrackGraph graph) {
|
||||
manager.version++;
|
||||
|
||||
if (packetDeletesGraph) {
|
||||
manager.removeGraph(graph);
|
||||
return;
|
||||
|
|
|
@ -49,7 +49,7 @@ public class AssemblyScreen extends AbstractStationScreen {
|
|||
iconTypes = TrainIconType.REGISTRY.keySet()
|
||||
.stream()
|
||||
.toList();
|
||||
iconTypeScroll = new ScrollInput(x + 4, y + 17, 184, 14).titled(CreateLang.translateDirect("station.icon_type"));
|
||||
iconTypeScroll = new ScrollInput(x + 4, y + 17, 162, 14).titled(CreateLang.translateDirect("station.icon_type"));
|
||||
iconTypeScroll.withRange(0, iconTypes.size());
|
||||
iconTypeScroll.withStepFunction(ctx -> -iconTypeScroll.standardStep()
|
||||
.apply(ctx));
|
||||
|
@ -164,7 +164,7 @@ public class AssemblyScreen extends AbstractStationScreen {
|
|||
ResourceLocation iconId = iconTypes.get(iconTypeScroll.getState());
|
||||
train.icon = TrainIconType.byId(iconId);
|
||||
AllPackets.getChannel()
|
||||
.sendToServer(new TrainEditPacket(train.id, "", iconId));
|
||||
.sendToServer(new TrainEditPacket(train.id, "", iconId, train.mapColorIndex));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -466,6 +466,18 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
itemEntity.setDeltaMovement(Vec3.ZERO);
|
||||
getLevel().addFreshEntity(itemEntity);
|
||||
}
|
||||
|
||||
public void updateMapColor(int color) {
|
||||
GlobalStation station = getStation();
|
||||
if (station == null)
|
||||
return;
|
||||
|
||||
Train train = station.getPresentTrain();
|
||||
if (train == null)
|
||||
return;
|
||||
|
||||
train.mapColorIndex = color;
|
||||
}
|
||||
|
||||
private boolean updateStationState(Consumer<GlobalStation> updateState) {
|
||||
GlobalStation station = getStation();
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllPackets;
|
||||
import com.simibubi.create.AllPartialModels;
|
||||
import com.simibubi.create.compat.Mods;
|
||||
import com.simibubi.create.content.decoration.slidingDoor.DoorControl;
|
||||
import com.simibubi.create.content.trains.entity.Carriage;
|
||||
import com.simibubi.create.content.trains.entity.Train;
|
||||
|
@ -23,6 +24,7 @@ import com.simibubi.create.foundation.utility.CreateLang;
|
|||
|
||||
import dev.engine_room.flywheel.lib.model.baked.PartialModel;
|
||||
import net.createmod.catnip.gui.UIRenderHelper;
|
||||
import net.createmod.catnip.utility.AnimationTickHolder;
|
||||
import net.createmod.catnip.utility.Pair;
|
||||
import net.createmod.catnip.utility.animation.LerpedFloat;
|
||||
import net.createmod.catnip.utility.lang.Components;
|
||||
|
@ -44,6 +46,9 @@ public class StationScreen extends AbstractStationScreen {
|
|||
private int leavingAnimation;
|
||||
private LerpedFloat trainPosition;
|
||||
private DoorControl doorControl;
|
||||
|
||||
private ScrollInput colorTypeScroll;
|
||||
private int messedWithColors;
|
||||
|
||||
private boolean switchingToAssemblyMode;
|
||||
|
||||
|
@ -99,6 +104,20 @@ public class StationScreen extends AbstractStationScreen {
|
|||
dropScheduleButton.withCallback(() -> AllPackets.getChannel()
|
||||
.sendToServer(StationEditPacket.dropSchedule(blockEntity.getBlockPos())));
|
||||
addRenderableWidget(dropScheduleButton);
|
||||
|
||||
colorTypeScroll = new ScrollInput(x + 166, y + 17, 22, 14).titled(CreateLang.translateDirect("station.train_map_color"));
|
||||
colorTypeScroll.withRange(0, 16);
|
||||
colorTypeScroll.withStepFunction(ctx -> -colorTypeScroll.standardStep()
|
||||
.apply(ctx));
|
||||
colorTypeScroll.calling(s -> {
|
||||
Train train = displayedTrain.get();
|
||||
if (train != null) {
|
||||
train.mapColorIndex = s;
|
||||
messedWithColors = 10;
|
||||
}
|
||||
});
|
||||
colorTypeScroll.active = colorTypeScroll.visible = false;
|
||||
addRenderableWidget(colorTypeScroll);
|
||||
|
||||
onTextChanged = s -> trainNameBox.setX(nameBoxX(s, trainNameBox));
|
||||
trainNameBox = new EditBox(font, x + 23, y + 47, background.getWidth() - 75, 10, Components.immutableEmpty());
|
||||
|
@ -131,6 +150,12 @@ public class StationScreen extends AbstractStationScreen {
|
|||
.length());
|
||||
trainNameBox.setHighlightPos(trainNameBox.getCursorPosition());
|
||||
}
|
||||
|
||||
if (messedWithColors > 0) {
|
||||
messedWithColors--;
|
||||
if (messedWithColors == 0)
|
||||
syncTrainNameAndColor();
|
||||
}
|
||||
|
||||
super.tick();
|
||||
|
||||
|
@ -151,6 +176,8 @@ public class StationScreen extends AbstractStationScreen {
|
|||
leavingAnimation = 0;
|
||||
newTrainButton.active = blockEntity.edgePoint.isOrthogonal();
|
||||
newTrainButton.visible = true;
|
||||
colorTypeScroll.visible = false;
|
||||
colorTypeScroll.active = false;
|
||||
Train imminentTrain = getImminent();
|
||||
|
||||
if (imminentTrain != null) {
|
||||
|
@ -161,7 +188,9 @@ public class StationScreen extends AbstractStationScreen {
|
|||
disassembleTrainButton.visible = true;
|
||||
dropScheduleButton.active = blockEntity.trainHasSchedule;
|
||||
dropScheduleButton.visible = true;
|
||||
|
||||
colorTypeScroll.setState(imminentTrain.mapColorIndex);
|
||||
colorTypeScroll.visible = true;
|
||||
colorTypeScroll.active = true;
|
||||
trainNameBox.active = true;
|
||||
trainNameBox.setValue(imminentTrain.name.getString());
|
||||
trainNameBox.setX(nameBoxX(trainNameBox.getValue(), trainNameBox));
|
||||
|
@ -185,6 +214,8 @@ public class StationScreen extends AbstractStationScreen {
|
|||
targetPos -= trainIconWidth - 130;
|
||||
|
||||
if (leavingAnimation > 0) {
|
||||
colorTypeScroll.visible = false;
|
||||
colorTypeScroll.active = false;
|
||||
disassembleTrainButton.active = false;
|
||||
float f = 1 - (leavingAnimation / 80f);
|
||||
trainPosition.setValue(targetPos + f * f * f * (background.getWidth() - targetPos + 5));
|
||||
|
@ -301,6 +332,27 @@ public class StationScreen extends AbstractStationScreen {
|
|||
if (font.width(text) > trainNameBox.getWidth())
|
||||
graphics.drawString(font, "...", guiLeft + 26, guiTop + 47, 0xa6a6a6);
|
||||
}
|
||||
|
||||
if (!Mods.FTBCHUNKS.isLoaded())
|
||||
return;
|
||||
|
||||
AllGuiTextures sprite = AllGuiTextures.TRAINMAP_SPRITES;
|
||||
sprite.bind();
|
||||
int trainColorIndex = colorTypeScroll.getState();
|
||||
int colorRow = trainColorIndex / 4;
|
||||
int colorCol = trainColorIndex % 4;
|
||||
int rotation = (AnimationTickHolder.getTicks() / 5) % 8;
|
||||
|
||||
for (int slice = 0; slice < 3; slice++) {
|
||||
int row = slice == 0 ? 1 : slice == 2 ? 2 : 3;
|
||||
int col = rotation;
|
||||
int positionX = colorTypeScroll.getX() + 4;
|
||||
int positionY = colorTypeScroll.getY() - 1;
|
||||
int sheetX = col * 16 + colorCol * 128;
|
||||
int sheetY = row * 16 + colorRow * 64;
|
||||
|
||||
graphics.blit(sprite.location, positionX, positionY, sheetX, sheetY, 16, 16, sprite.getWidth(), sprite.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -335,19 +387,19 @@ public class StationScreen extends AbstractStationScreen {
|
|||
|
||||
if (hitEnter && trainNameBox.isFocused()) {
|
||||
trainNameBox.setFocused(false);
|
||||
syncTrainName();
|
||||
syncTrainNameAndColor();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
|
||||
}
|
||||
|
||||
private void syncTrainName() {
|
||||
private void syncTrainNameAndColor() {
|
||||
Train train = displayedTrain.get();
|
||||
if (train != null && !trainNameBox.getValue()
|
||||
.equals(train.name.getString()))
|
||||
AllPackets.getChannel()
|
||||
.sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId()));
|
||||
.sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId(), train.mapColorIndex));
|
||||
}
|
||||
|
||||
private void syncStationName() {
|
||||
|
@ -371,7 +423,8 @@ public class StationScreen extends AbstractStationScreen {
|
|||
return;
|
||||
if (!switchingToAssemblyMode)
|
||||
AllPackets.getChannel()
|
||||
.sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId()));
|
||||
.sendToServer(
|
||||
new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId(), train.mapColorIndex));
|
||||
else
|
||||
blockEntity.imminentTrain = null;
|
||||
}
|
||||
|
|
|
@ -21,17 +21,20 @@ public class TrainEditPacket extends SimplePacketBase {
|
|||
private String name;
|
||||
private UUID id;
|
||||
private ResourceLocation iconType;
|
||||
private int mapColor;
|
||||
|
||||
public TrainEditPacket(UUID id, String name, ResourceLocation iconType) {
|
||||
public TrainEditPacket(UUID id, String name, ResourceLocation iconType, int mapColor) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
this.iconType = iconType;
|
||||
this.mapColor = mapColor;
|
||||
}
|
||||
|
||||
public TrainEditPacket(FriendlyByteBuf buffer) {
|
||||
id = buffer.readUUID();
|
||||
name = buffer.readUtf(256);
|
||||
iconType = buffer.readResourceLocation();
|
||||
mapColor = buffer.readVarInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,6 +42,7 @@ public class TrainEditPacket extends SimplePacketBase {
|
|||
buffer.writeUUID(id);
|
||||
buffer.writeUtf(name);
|
||||
buffer.writeResourceLocation(iconType);
|
||||
buffer.writeVarInt(mapColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,8 +56,9 @@ public class TrainEditPacket extends SimplePacketBase {
|
|||
if (!name.isBlank())
|
||||
train.name = Components.literal(name);
|
||||
train.icon = TrainIconType.byId(iconType);
|
||||
train.mapColorIndex = mapColor;
|
||||
if (sender != null)
|
||||
AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainEditReturnPacket(id, name, iconType));
|
||||
AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainEditReturnPacket(id, name, iconType, mapColor));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -64,8 +69,8 @@ public class TrainEditPacket extends SimplePacketBase {
|
|||
super(buffer);
|
||||
}
|
||||
|
||||
public TrainEditReturnPacket(UUID id, String name, ResourceLocation iconType) {
|
||||
super(id, name, iconType);
|
||||
public TrainEditReturnPacket(UUID id, String name, ResourceLocation iconType, int mapColor) {
|
||||
super(id, name, iconType, mapColor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.simibubi.create.content.trains.track;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack.Pose;
|
||||
|
@ -10,6 +12,7 @@ import dev.engine_room.flywheel.lib.transform.TransformStack;
|
|||
import net.createmod.catnip.utility.Couple;
|
||||
import net.createmod.catnip.utility.Iterate;
|
||||
import net.createmod.catnip.utility.NBTHelper;
|
||||
import net.createmod.catnip.utility.Pair;
|
||||
import net.createmod.catnip.utility.VecHelper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
|
@ -108,7 +111,8 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
.map(v -> v.add(Vec3.atLowerCornerOf(localTo))),
|
||||
Couple.deserializeEach(compound.getList("Axes", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
|
||||
Couple.deserializeEach(compound.getList("Normals", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
|
||||
compound.getBoolean("Primary"), compound.getBoolean("Girder"), TrackMaterial.deserialize(compound.getString("Material")));
|
||||
compound.getBoolean("Primary"), compound.getBoolean("Girder"),
|
||||
TrackMaterial.deserialize(compound.getString("Material")));
|
||||
|
||||
if (compound.contains("Smoothing"))
|
||||
smoothing =
|
||||
|
@ -398,7 +402,8 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
}
|
||||
|
||||
public void spawnDestroyParticles(Level level) {
|
||||
BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, getMaterial().getBlock().defaultBlockState());
|
||||
BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, getMaterial().getBlock()
|
||||
.defaultBlockState());
|
||||
BlockParticleOption girderData =
|
||||
new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.METAL_GIRDER.getDefaultState());
|
||||
if (!(level instanceof ServerLevel slevel))
|
||||
|
@ -673,4 +678,104 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
return bakedGirders;
|
||||
}
|
||||
|
||||
public Map<Pair<Integer, Integer>, Double> rasterise() {
|
||||
Map<Pair<Integer, Integer>, Double> yLevels = new HashMap<>();
|
||||
BlockPos tePosition = bePositions.getFirst();
|
||||
Vec3 end1 = starts.getFirst()
|
||||
.subtract(Vec3.atLowerCornerOf(tePosition))
|
||||
.add(0, 3 / 16f, 0);
|
||||
Vec3 end2 = starts.getSecond()
|
||||
.subtract(Vec3.atLowerCornerOf(tePosition))
|
||||
.add(0, 3 / 16f, 0);
|
||||
Vec3 axis1 = axes.getFirst();
|
||||
Vec3 axis2 = axes.getSecond();
|
||||
|
||||
double handleLength = getHandleLength();
|
||||
Vec3 finish1 = axis1.scale(handleLength)
|
||||
.add(end1);
|
||||
Vec3 finish2 = axis2.scale(handleLength)
|
||||
.add(end2);
|
||||
|
||||
Vec3 faceNormal1 = normals.getFirst();
|
||||
Vec3 faceNormal2 = normals.getSecond();
|
||||
|
||||
int segCount = getSegmentCount();
|
||||
float[] lut = getStepLUT();
|
||||
Vec3[] samples = new Vec3[segCount];
|
||||
|
||||
for (int i = 0; i < segCount; i++) {
|
||||
float t = Mth.clamp((i + 0.5f) * lut[i] / segCount, 0, 1);
|
||||
Vec3 result = VecHelper.bezier(end1, end2, finish1, finish2, t);
|
||||
Vec3 derivative = VecHelper.bezierDerivative(end1, end2, finish1, finish2, t)
|
||||
.normalize();
|
||||
Vec3 faceNormal =
|
||||
faceNormal1.equals(faceNormal2) ? faceNormal1 : VecHelper.slerp(t, faceNormal1, faceNormal2);
|
||||
Vec3 normal = faceNormal.cross(derivative)
|
||||
.normalize();
|
||||
Vec3 below = result.add(faceNormal.scale(-.25f));
|
||||
Vec3 rail1 = below.add(normal.scale(.05f));
|
||||
Vec3 rail2 = below.subtract(normal.scale(.05f));
|
||||
Vec3 railMiddle = rail1.add(rail2)
|
||||
.scale(.5);
|
||||
samples[i] = railMiddle;
|
||||
}
|
||||
|
||||
Vec3 center = end1.add(end2)
|
||||
.scale(0.5);
|
||||
|
||||
Pair<Integer, Integer> prev = null;
|
||||
Pair<Integer, Integer> prev2 = null;
|
||||
Pair<Integer, Integer> prev3 = null;
|
||||
|
||||
for (int i = 0; i < segCount; i++) {
|
||||
Vec3 railMiddle = samples[i];
|
||||
BlockPos pos = BlockPos.containing(railMiddle);
|
||||
Pair<Integer, Integer> key = Pair.of(pos.getX(), pos.getZ());
|
||||
boolean alreadyPresent = yLevels.containsKey(key);
|
||||
if (alreadyPresent && yLevels.get(key) <= railMiddle.y)
|
||||
continue;
|
||||
yLevels.put(key, railMiddle.y);
|
||||
if (alreadyPresent)
|
||||
continue;
|
||||
|
||||
if (prev3 != null) { // Remove obsolete pixels
|
||||
boolean doubledViaPrev = isLineDoubled(prev2, prev, key);
|
||||
boolean doubledViaPrev2 = isLineDoubled(prev3, prev2, prev);
|
||||
boolean prevCloser = diff(prev, center) > diff(prev2, center);
|
||||
|
||||
if (doubledViaPrev2 && (!doubledViaPrev || !prevCloser)) {
|
||||
yLevels.remove(prev2);
|
||||
prev2 = prev;
|
||||
prev = key;
|
||||
continue;
|
||||
|
||||
} else if (doubledViaPrev && doubledViaPrev2 && prevCloser) {
|
||||
yLevels.remove(prev);
|
||||
prev = key;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
prev3 = prev2;
|
||||
prev2 = prev;
|
||||
prev = key;
|
||||
}
|
||||
|
||||
return yLevels;
|
||||
}
|
||||
|
||||
private double diff(Pair<Integer, Integer> pFrom, Vec3 to) {
|
||||
return to.distanceToSqr(pFrom.getFirst() + 0.5, to.y, pFrom.getSecond() + 0.5);
|
||||
}
|
||||
|
||||
private boolean isLineDoubled(Pair<Integer, Integer> pFrom, Pair<Integer, Integer> pVia,
|
||||
Pair<Integer, Integer> pTo) {
|
||||
int diff1x = pVia.getFirst() - pFrom.getFirst();
|
||||
int diff1z = pVia.getSecond() - pFrom.getSecond();
|
||||
int diff2x = pTo.getFirst() - pVia.getFirst();
|
||||
int diff2z = pTo.getSecond() - pVia.getSecond();
|
||||
return Math.abs(diff1x) + Math.abs(diff1z) == 1 && Math.abs(diff2x) + Math.abs(diff2z) == 1 && diff1x != diff2x
|
||||
&& diff1z != diff2z;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour
|
|||
|
||||
import dev.engine_room.flywheel.lib.visualization.VisualizationHelper;
|
||||
import net.createmod.catnip.utility.Pair;
|
||||
import net.createmod.catnip.utility.VecHelper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
|
@ -363,54 +362,7 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
|||
}
|
||||
|
||||
public void manageFakeTracksAlong(BezierConnection bc, boolean remove) {
|
||||
Map<Pair<Integer, Integer>, Double> yLevels = new HashMap<>();
|
||||
BlockPos tePosition = bc.bePositions.getFirst();
|
||||
Vec3 end1 = bc.starts.getFirst()
|
||||
.subtract(Vec3.atLowerCornerOf(tePosition))
|
||||
.add(0, 3 / 16f, 0);
|
||||
Vec3 end2 = bc.starts.getSecond()
|
||||
.subtract(Vec3.atLowerCornerOf(tePosition))
|
||||
.add(0, 3 / 16f, 0);
|
||||
Vec3 axis1 = bc.axes.getFirst();
|
||||
Vec3 axis2 = bc.axes.getSecond();
|
||||
|
||||
double handleLength = bc.getHandleLength();
|
||||
|
||||
Vec3 finish1 = axis1.scale(handleLength)
|
||||
.add(end1);
|
||||
Vec3 finish2 = axis2.scale(handleLength)
|
||||
.add(end2);
|
||||
|
||||
Vec3 faceNormal1 = bc.normals.getFirst();
|
||||
Vec3 faceNormal2 = bc.normals.getSecond();
|
||||
|
||||
int segCount = bc.getSegmentCount();
|
||||
float[] lut = bc.getStepLUT();
|
||||
|
||||
for (int i = 0; i < segCount; i++) {
|
||||
float t = i == segCount ? 1 : i * lut[i] / segCount;
|
||||
t += 0.5f / segCount;
|
||||
|
||||
Vec3 result = VecHelper.bezier(end1, end2, finish1, finish2, t);
|
||||
Vec3 derivative = VecHelper.bezierDerivative(end1, end2, finish1, finish2, t)
|
||||
.normalize();
|
||||
Vec3 faceNormal =
|
||||
faceNormal1.equals(faceNormal2) ? faceNormal1 : VecHelper.slerp(t, faceNormal1, faceNormal2);
|
||||
Vec3 normal = faceNormal.cross(derivative)
|
||||
.normalize();
|
||||
Vec3 below = result.add(faceNormal.scale(-.25f));
|
||||
Vec3 rail1 = below.add(normal.scale(.05f));
|
||||
Vec3 rail2 = below.subtract(normal.scale(.05f));
|
||||
Vec3 railMiddle = rail1.add(rail2)
|
||||
.scale(.5);
|
||||
|
||||
for (Vec3 vec : new Vec3[] { railMiddle }) {
|
||||
BlockPos pos = BlockPos.containing(vec);
|
||||
Pair<Integer, Integer> key = Pair.of(pos.getX(), pos.getZ());
|
||||
if (!yLevels.containsKey(key) || yLevels.get(key) > vec.y)
|
||||
yLevels.put(key, vec.y);
|
||||
}
|
||||
}
|
||||
Map<Pair<Integer, Integer>, Double> yLevels = bc.rasterise();
|
||||
|
||||
for (Entry<Pair<Integer, Integer>, Double> entry : yLevels.entrySet()) {
|
||||
double yValue = entry.getValue();
|
||||
|
@ -419,7 +371,7 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
|||
.getFirst(), floor,
|
||||
entry.getKey()
|
||||
.getSecond());
|
||||
targetPos = targetPos.offset(tePosition)
|
||||
targetPos = targetPos.offset(bc.bePositions.getFirst())
|
||||
.above(1);
|
||||
|
||||
BlockState stateAtPos = level.getBlockState(targetPos);
|
||||
|
|
|
@ -80,6 +80,10 @@ public abstract class CapManipulationBehaviourBase<T, S extends CapManipulationB
|
|||
targetCapability = LazyOptional.empty();
|
||||
}
|
||||
|
||||
public void removeListener() {
|
||||
targetCapability.removeListener(new HashableNonNullConsumer<>(this::onHandlerInvalidated, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lazyTick() {
|
||||
super.lazyTick();
|
||||
|
|
|
@ -2,10 +2,13 @@ package com.simibubi.create.foundation.blockEntity.renderer;
|
|||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
import com.simibubi.create.foundation.ponder.PonderWorld;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.culling.Frustum;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
@ -28,7 +31,10 @@ public abstract class SafeBlockEntityRenderer<T extends BlockEntity> implements
|
|||
.getBlock() == Blocks.AIR;
|
||||
}
|
||||
|
||||
public boolean shouldCullItem(Vec3 itemPos) {
|
||||
public boolean shouldCullItem(Vec3 itemPos, Level level) {
|
||||
if (level instanceof PonderWorld)
|
||||
return false;
|
||||
|
||||
Frustum frustum = Minecraft.getInstance().levelRenderer.capturedFrustum != null ?
|
||||
Minecraft.getInstance().levelRenderer.capturedFrustum :
|
||||
Minecraft.getInstance().levelRenderer.cullingFrustum;
|
||||
|
|
|
@ -32,6 +32,12 @@ public enum CompatMetals {
|
|||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getName(Mods mod) {
|
||||
if (this == ALUMINUM && mod == IC2) // include in mods.builder if this happens again
|
||||
return "aluminium";
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* These mods must provide an ingot and nugget variant of the corresponding metal.
|
||||
|
|
|
@ -817,7 +817,8 @@ public class MillingRecipeGen extends ProcessingRecipeGen {
|
|||
create(Mods.BTN.recipeId(color + "_petal"), b -> b.duration(50)
|
||||
.require(AllTags.optionalTag(ForgeRegistries.ITEMS,
|
||||
new ResourceLocation(Mods.BTN.getId(), "petals/" + color)))
|
||||
.output(Mods.MC, color + "_dye"));
|
||||
.output(Mods.MC, color + "_dye")
|
||||
.whenModLoaded(Mods.BTN.getId()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -850,7 +851,7 @@ public class MillingRecipeGen extends ProcessingRecipeGen {
|
|||
public MillingRecipeGen(PackOutput output) {
|
||||
super(output);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected AllRecipeTypes getRecipeType() {
|
||||
return AllRecipeTypes.MILLING;
|
||||
|
|
|
@ -59,6 +59,8 @@ import net.minecraftforge.common.crafting.conditions.ICondition;
|
|||
import net.minecraftforge.common.crafting.conditions.ModLoadedCondition;
|
||||
import net.minecraftforge.common.crafting.conditions.NotCondition;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class StandardRecipeGen extends CreateRecipeProvider {
|
||||
|
||||
|
@ -1178,7 +1180,8 @@ public class StandardRecipeGen extends CreateRecipeProvider {
|
|||
.inBlastFurnace(),
|
||||
|
||||
UA_TREE_FERTILIZER = create(AllItems.TREE_FERTILIZER::get).returns(2)
|
||||
.whenModLoaded(Mods.UA.getId()).unlockedBy(() -> Items.BONE_MEAL)
|
||||
.unlockedBy(() -> Items.BONE_MEAL)
|
||||
.whenModLoaded(Mods.UA.getId())
|
||||
.viaShapeless(b -> b.requires(Ingredient.of(ItemTags.SMALL_FLOWERS), 2)
|
||||
.requires(AllItemTags.UA_CORAL.tag).requires(Items.BONE_MEAL))
|
||||
|
||||
|
@ -1224,8 +1227,8 @@ public class StandardRecipeGen extends CreateRecipeProvider {
|
|||
}
|
||||
|
||||
GeneratedRecipe blastModdedCrushedMetal(ItemEntry<? extends Item> ingredient, CompatMetals metal) {
|
||||
String metalName = metal.getName();
|
||||
for (Mods mod : metal.getMods()) {
|
||||
String metalName = metal.getName(mod);
|
||||
ResourceLocation ingot = mod.ingotOf(metalName);
|
||||
String modId = mod.getId();
|
||||
create(ingot).withSuffix("_compat_" + modId)
|
||||
|
@ -1375,7 +1378,12 @@ public class StandardRecipeGen extends CreateRecipeProvider {
|
|||
ShapelessRecipeBuilder b = builder.apply(ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, result.get(), amount));
|
||||
if (unlockedBy != null)
|
||||
b.unlockedBy("has_item", inventoryTrigger(unlockedBy.get()));
|
||||
b.save(consumer, createLocation("crafting"));
|
||||
|
||||
b.save(result -> {
|
||||
consumer.accept(
|
||||
!recipeConditions.isEmpty() ? new ConditionSupportingShapelessRecipeResult(result, recipeConditions)
|
||||
: result);
|
||||
}, createLocation("crafting"));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1478,10 +1486,10 @@ public class StandardRecipeGen extends CreateRecipeProvider {
|
|||
SimpleCookingRecipeBuilder b = builder.apply(SimpleCookingRecipeBuilder.generic(ingredient.get(),
|
||||
RecipeCategory.MISC, isOtherMod ? Items.DIRT : result.get(), exp,
|
||||
(int) (cookingTime * cookingTimeModifier), serializer));
|
||||
|
||||
|
||||
if (unlockedBy != null)
|
||||
b.unlockedBy("has_item", inventoryTrigger(unlockedBy.get()));
|
||||
|
||||
|
||||
b.save(result -> {
|
||||
consumer.accept(
|
||||
isOtherMod ? new ModdedCookingRecipeResult(result, compatDatagenOutput, recipeConditions)
|
||||
|
@ -1502,19 +1510,39 @@ public class StandardRecipeGen extends CreateRecipeProvider {
|
|||
super(p_i48262_1_);
|
||||
}
|
||||
|
||||
private static class ModdedCookingRecipeResult implements FinishedRecipe {
|
||||
private record ModdedCookingRecipeResult(FinishedRecipe wrapped, ResourceLocation outputOverride, List<ICondition> conditions) implements FinishedRecipe {
|
||||
@Override
|
||||
public ResourceLocation getId() {
|
||||
return wrapped.getId();
|
||||
}
|
||||
|
||||
private FinishedRecipe wrapped;
|
||||
private ResourceLocation outputOverride;
|
||||
private List<ICondition> conditions;
|
||||
@Override
|
||||
public RecipeSerializer<?> getType() {
|
||||
return wrapped.getType();
|
||||
}
|
||||
|
||||
public ModdedCookingRecipeResult(FinishedRecipe wrapped, ResourceLocation outputOverride,
|
||||
List<ICondition> conditions) {
|
||||
this.wrapped = wrapped;
|
||||
this.outputOverride = outputOverride;
|
||||
this.conditions = conditions;
|
||||
@Override
|
||||
public JsonObject serializeAdvancement() {
|
||||
return wrapped.serializeAdvancement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getAdvancementId() {
|
||||
return wrapped.getAdvancementId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeRecipeData(JsonObject object) {
|
||||
wrapped.serializeRecipeData(object);
|
||||
object.addProperty("result", outputOverride.toString());
|
||||
|
||||
JsonArray conds = new JsonArray();
|
||||
conditions.forEach(c -> conds.add(CraftingHelper.serialize(c)));
|
||||
object.add("conditions", conds);
|
||||
}
|
||||
}
|
||||
|
||||
private record ConditionSupportingShapelessRecipeResult(FinishedRecipe wrapped, List<ICondition> conditions) implements FinishedRecipe {
|
||||
@Override
|
||||
public ResourceLocation getId() {
|
||||
return wrapped.getId();
|
||||
|
@ -1536,15 +1564,12 @@ public class StandardRecipeGen extends CreateRecipeProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void serializeRecipeData(JsonObject object) {
|
||||
wrapped.serializeRecipeData(object);
|
||||
object.addProperty("result", outputOverride.toString());
|
||||
public void serializeRecipeData(@NotNull JsonObject pJson) {
|
||||
wrapped.serializeRecipeData(pJson);
|
||||
|
||||
JsonArray conds = new JsonArray();
|
||||
conditions.forEach(c -> conds.add(CraftingHelper.serialize(c)));
|
||||
object.add("conditions", conds);
|
||||
pJson.add("conditions", conds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -133,8 +133,8 @@ public class WashingRecipeGen extends ProcessingRecipeGen {
|
|||
}
|
||||
|
||||
public GeneratedRecipe moddedCrushedOre(ItemEntry<? extends Item> crushed, CompatMetals metal) {
|
||||
String metalName = metal.getName();
|
||||
for (Mods mod : metal.getMods()) {
|
||||
String metalName = metal.getName(mod);
|
||||
ResourceLocation nugget = mod.nuggetOf(metalName);
|
||||
create(mod.getId() + "/" + crushed.getId()
|
||||
.getPath(),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.simibubi.create.foundation.events;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.compat.trainmap.TrainMapSync;
|
||||
import com.simibubi.create.content.contraptions.ContraptionHandler;
|
||||
import com.simibubi.create.content.contraptions.actors.trainControls.ControlsServerHandler;
|
||||
import com.simibubi.create.content.contraptions.minecart.CouplingPhysics;
|
||||
|
@ -67,6 +68,7 @@ public class CommonEvents {
|
|||
Create.LAGGER.tick();
|
||||
ServerSpeedProvider.serverTick();
|
||||
Create.RAILWAYS.sync.serverTick();
|
||||
TrainMapSync.serverTick(event);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
|
|
@ -188,6 +188,21 @@ public enum AllGuiTextures implements ScreenElement, TextureSheetSegment {
|
|||
TRAIN_PROMPT_R("widgets", 11, 209, 3, 16),
|
||||
TRAIN_PROMPT("widgets", 0, 230, 256, 16),
|
||||
|
||||
// PlacementIndicator
|
||||
PLACEMENT_INDICATOR_SHEET("placement_indicator", 0, 0, 16, 256),
|
||||
|
||||
// Train Map
|
||||
TRAINMAP_SPRITES("trainmap_sprite_sheet", 0, 0, 512, 256),
|
||||
TRAINMAP_SIGNAL("widgets", 81, 156, 5, 10),
|
||||
TRAINMAP_STATION_ORTHO("widgets", 49, 156, 5, 5),
|
||||
TRAINMAP_STATION_DIAGO("widgets", 56, 156, 5, 5),
|
||||
TRAINMAP_STATION_ORTHO_HIGHLIGHT("widgets", 63, 156, 7, 7),
|
||||
TRAINMAP_STATION_DIAGO_HIGHLIGHT("widgets", 72, 156, 7, 7),
|
||||
|
||||
TRAINMAP_TOGGLE_PANEL("widgets", 166, 74, 33, 14),
|
||||
TRAINMAP_TOGGLE_ON("widgets", 166, 89, 12, 7),
|
||||
TRAINMAP_TOGGLE_OFF("widgets", 166, 97, 12, 7),
|
||||
|
||||
// ComputerCraft
|
||||
COMPUTER("computer", 200, 102);
|
||||
|
||||
|
|
|
@ -283,4 +283,16 @@ public class ItemHelper {
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static ItemStack limitCountToMaxStackSize(ItemStack stack, boolean simulate) {
|
||||
int count = stack.getCount();
|
||||
int max = stack.getMaxStackSize();
|
||||
if (count <= max)
|
||||
return ItemStack.EMPTY;
|
||||
ItemStack remainder = ItemHandlerHelper.copyStackWithSize(stack, count - max);
|
||||
if (!simulate)
|
||||
stack.setCount(max);
|
||||
return remainder;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import com.simibubi.create.foundation.mixin.accessor.UseOnContextAccessor;
|
|||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
@Mixin(BlockItem.class)
|
||||
|
@ -19,7 +18,7 @@ public class BlockItemMixin {
|
|||
@Inject(method = "place", at = @At("HEAD"), cancellable = true)
|
||||
private void create$fixDeployerPlacement(BlockPlaceContext pContext, CallbackInfoReturnable<InteractionResult> cir) {
|
||||
BlockState state = pContext.getLevel().getBlockState(((UseOnContextAccessor) pContext).create$getHitResult().getBlockPos());
|
||||
if (state != Blocks.AIR.defaultBlockState() && pContext.getPlayer() instanceof DeployerFakePlayer) {
|
||||
if (!state.canBeReplaced() && pContext.getPlayer() instanceof DeployerFakePlayer) {
|
||||
cir.setReturnValue(InteractionResult.PASS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package com.simibubi.create.foundation.mixin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
|
||||
import com.simibubi.create.compat.Mods;
|
||||
|
||||
public class CreateMixinPlugin implements IMixinConfigPlugin {
|
||||
|
||||
@Override
|
||||
public void onLoad(String mixinPackage) {}
|
||||
|
||||
@Override
|
||||
public String getRefMapperConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
|
||||
if (targetClassName.equals("journeymap/client/ui/fullscreen/Fullscreen") && !Mods.JOURNEYMAP.isLoaded())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {}
|
||||
|
||||
@Override
|
||||
public List<String> getMixins() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {}
|
||||
|
||||
@Override
|
||||
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.simibubi.create.foundation.mixin.compat;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
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.At.Shift;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.simibubi.create.compat.trainmap.JourneyTrainMap;
|
||||
|
||||
import journeymap.client.render.map.GridRenderer;
|
||||
import journeymap.client.ui.fullscreen.Fullscreen;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
|
||||
@Mixin(Fullscreen.class)
|
||||
public abstract class JourneyFullscreenMapMixin {
|
||||
|
||||
@Shadow
|
||||
private static GridRenderer gridRenderer;
|
||||
|
||||
@Shadow
|
||||
private Boolean isScrolling;
|
||||
|
||||
@Shadow
|
||||
public abstract Point2D.Double getMouseDrag();
|
||||
|
||||
@Inject(method = "Ljourneymap/client/ui/fullscreen/Fullscreen;render(Lnet/minecraft/client/gui/GuiGraphics;IIF)V", at = @At(target = "Ljourneymap/client/ui/fullscreen/Fullscreen;drawMap(Lnet/minecraft/client/gui/GuiGraphics;II)V", value = "INVOKE", shift = Shift.AFTER))
|
||||
public void create$journeyMapFullscreenRender(GuiGraphics graphics, int mouseX, int mouseY, float pt,
|
||||
CallbackInfo ci) {
|
||||
boolean dragging = isScrolling;
|
||||
Point2D.Double mouseDrag = getMouseDrag();
|
||||
double x = gridRenderer.getCenterBlockX() - (dragging ? mouseDrag.x : 0);
|
||||
double z = gridRenderer.getCenterBlockZ() - (dragging ? mouseDrag.y : 0);
|
||||
JourneyTrainMap.onRender(graphics, (Fullscreen) (Object) this, x, z, mouseX, mouseY, pt);
|
||||
}
|
||||
|
||||
}
|
|
@ -101,6 +101,19 @@ public class RenderTypes extends RenderStateShard {
|
|||
return ADDITIVE;
|
||||
}
|
||||
|
||||
public static BiFunction<ResourceLocation, Boolean, RenderType> TRAIN_MAP = Util.memoize(RenderTypes::getTrainMap);
|
||||
|
||||
private static RenderType getTrainMap(ResourceLocation locationIn, boolean linearFiltering) {
|
||||
RenderType.CompositeState rendertype$state = RenderType.CompositeState.builder()
|
||||
.setShaderState(RENDERTYPE_TEXT_SHADER)
|
||||
.setTextureState(new RenderStateShard.TextureStateShard(locationIn, linearFiltering, false))
|
||||
.setTransparencyState(NO_TRANSPARENCY)
|
||||
.setLightmapState(LIGHTMAP)
|
||||
.createCompositeState(false);
|
||||
return RenderType.create("create_train_map", DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP,
|
||||
VertexFormat.Mode.QUADS, 256, false, true, rendertype$state);
|
||||
}
|
||||
|
||||
public static RenderType fluid() {
|
||||
return FLUID;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue