From 990d80412e64f6ae56fac897fea6fa3f65c91b10 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Sat, 19 Sep 2020 15:19:22 +0200 Subject: [PATCH] Logistics' final stretch, Part I - Brass tunnels once again have the ability to synchronize inputs among a chain - Mechanical arms now have a range limitation - Mechanical arms now wait with initialization until their area is fully loaded - Chutes no longer ignore the direction of an attached fans air flow - Chutes now render particles indicating their movement direction - Chutes can now pull items up from belts or off the ground - Fixed item model of shadow casing - Fixed invisible quads under funnels when no casing is applied to the belt - Belt mounted funnels can now be perpendicular to the belt theyre on - Funnels can now transpose items like a hopper when facing down --- src/generated/resources/.cache/cache | 20 +-- .../resources/assets/create/lang/en_us.json | 5 + .../assets/create/lang/unfinished/de_de.json | 7 +- .../assets/create/lang/unfinished/fr_fr.json | 7 +- .../assets/create/lang/unfinished/it_it.json | 7 +- .../assets/create/lang/unfinished/ja_jp.json | 7 +- .../assets/create/lang/unfinished/ko_kr.json | 7 +- .../assets/create/lang/unfinished/nl_nl.json | 7 +- .../assets/create/lang/unfinished/pt_br.json | 7 +- .../assets/create/lang/unfinished/ru_ru.json | 7 +- .../assets/create/lang/unfinished/zh_cn.json | 7 +- .../com/simibubi/create/AllParticleTypes.java | 2 + src/main/java/com/simibubi/create/Create.java | 8 +- .../crafter/MechanicalCrafterTileEntity.java | 2 +- .../deployer/DeployerItemHandler.java | 3 +- .../components/fan/AirCurrent.java | 107 ++++++----- .../fluids/FluidPipeAttachmentBehaviour.java | 6 +- .../TransparentStraightPipeRenderer.java | 2 +- .../particle/AirFlowParticle.java | 3 +- .../contraptions/particle/AirParticle.java | 104 +++++++++++ .../particle/AirParticleData.java | 73 ++++++++ .../contraptions/particle/CubeParticle.java | 4 +- .../contraptions/particle/HeaterParticle.java | 4 +- .../relays/belt/BeltTileEntity.java | 8 +- .../BeltFunnelInteractionHandler.java | 24 +-- .../BeltTunnelInteractionHandler.java | 3 +- .../block/belts/tunnel/BeltTunnelBlock.java | 4 + .../belts/tunnel/BeltTunnelTileEntity.java | 3 +- .../belts/tunnel/BrassTunnelItemHandler.java | 2 +- .../belts/tunnel/BrassTunnelTileEntity.java | 60 ++++++- .../logistics/block/chute/ChuteBlock.java | 9 +- .../logistics/block/chute/ChuteRenderer.java | 3 +- .../block/chute/ChuteTileEntity.java | 167 +++++++++++++++++- .../logistics/block/depot/DepotRenderer.java | 17 +- .../block/depot/DepotTileEntity.java | 11 +- .../block/funnel/BeltFunnelBlock.java | 13 +- .../block/funnel/FunnelTileEntity.java | 123 +++++++++---- .../ArmInteractionPointHandler.java | 29 +++ .../block/mechanicalArm/ArmTileEntity.java | 28 ++- .../redstone/RedstoneLinkTileEntity.java | 2 +- .../create/foundation/config/CLogistics.java | 16 +- .../create/foundation/gui/AllIcons.java | 1 + .../create/foundation/item/ItemHelper.java | 4 +- .../tileEntity/SmartTileEntity.java | 12 +- .../tileEntity/TileEntityBehaviour.java | 18 +- .../filtering/FilteringCountUpdatePacket.java | 3 +- .../filtering/FilteringRenderer.java | 2 +- .../inventory/InvManipulationBehaviour.java | 34 +++- .../behaviour/linked/LinkRenderer.java | 8 +- .../scrollvalue/ScrollValueHandler.java | 4 +- .../scrollvalue/ScrollValueRenderer.java | 5 +- .../scrollvalue/ScrollValueUpdatePacket.java | 3 +- .../foundation/utility/BlockHelper.java | 35 ++-- .../assets/create/lang/default/messages.json | 7 +- .../block/belt_funnel/block_extended.json | 18 +- .../block/belt_funnel/block_retracted.json | 20 ++- .../assets/create/particles/air.json | 12 ++ .../textures/block/shadow_steel_casing.png | Bin 263 -> 405 bytes .../assets/create/textures/gui/icons.png | Bin 4411 -> 4434 bytes 59 files changed, 864 insertions(+), 250 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/particle/AirParticle.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/particle/AirParticleData.java create mode 100644 src/main/resources/assets/create/particles/air.json diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 33942da90..870f56f0e 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -350,16 +350,16 @@ a3a11524cd3515fc01d905767b4b7ea782adaf03 assets/create/blockstates/yellow_seat.j 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json c87674f2935327f78657f1bb44b3b10b6697a548 assets/create/lang/en_ud.json -0e38385f3de32bfc0f5d3d90dfa635469e953e43 assets/create/lang/en_us.json -cb59266eb110493f41cd8754915e2c2626063742 assets/create/lang/unfinished/de_de.json -9f1f8ebf3683613729f0c4d62d12d3146cfdb634 assets/create/lang/unfinished/fr_fr.json -a6d24acb90e85ed13a5bd36a4e95750319a01de5 assets/create/lang/unfinished/it_it.json -5dbd2b38becc4e985cc926bab5c58e8c7dfaf7e7 assets/create/lang/unfinished/ja_jp.json -4065e282b5860497090e86b3bdf2773f9888f502 assets/create/lang/unfinished/ko_kr.json -e1baa1589c53467ca2f610c3f0cc51c861afdcff assets/create/lang/unfinished/nl_nl.json -8590ef541ece9eae76135b3e93c53798b3d37aac assets/create/lang/unfinished/pt_br.json -7b67a7b85631c83f6803eb717bced55d0efb76b7 assets/create/lang/unfinished/ru_ru.json -29a47e6bc1f85467af17f97d30e2e0100bea99ea assets/create/lang/unfinished/zh_cn.json +62a4c9e5454fd6e899495c95d6fddd020d472bc7 assets/create/lang/en_us.json +42081320880e3248cc1e7e667d38bb3be682790a assets/create/lang/unfinished/de_de.json +8fc3d8467436b5dd9221b0ed72b1a64bf83d0767 assets/create/lang/unfinished/fr_fr.json +a5125e0ca8bb93c7c4f11d49a80a155a7ea14b16 assets/create/lang/unfinished/it_it.json +b173b6500f8a675e266864310ab8e205721dbe12 assets/create/lang/unfinished/ja_jp.json +1af8e96a3129f8aac458b75eff69378a0cc9dd7d assets/create/lang/unfinished/ko_kr.json +343a4455ca0f29b2ae6ac439030c0dfde0e4c59b assets/create/lang/unfinished/nl_nl.json +d7bd8d85e3b8def1b4fe72da0a43845d1bb61c1c assets/create/lang/unfinished/pt_br.json +6e7fdb53ae3121e5575021bb224d1bfbe257c38b assets/create/lang/unfinished/ru_ru.json +1a3e1309d92024445dae821d25168dab74ff5cdd assets/create/lang/unfinished/zh_cn.json 846200eb548d3bfa2e77b41039de159b4b6cfb45 assets/create/models/block/acacia_window.json 1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets/create/models/block/acacia_window_pane_noside.json 1763ea2c9b981d187f5031ba608f3d5d3be3986a assets/create/models/block/acacia_window_pane_noside_alt.json diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 51f581b80..9475d69b2 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -836,6 +836,10 @@ "create.tooltip.generationSpeed": "Generates at %1$s %2$s", "create.tooltip.analogStrength": "Analog Strength: %1$s/15", + "create.mechanical_arm.extract_from": "Take items from %1$s", + "create.mechanical_arm.deposit_to": "Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "%1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "Round Robin", @@ -848,6 +852,7 @@ "create.tunnel.selection_mode.forced_round_robin": "Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "Prefer Nearest", "create.tunnel.selection_mode.randomize": "Randomize", + "create.tunnel.selection_mode.synchronize": "Synchronize Inputs", "create.gui.config.overlay1": "Hi :)", "create.gui.config.overlay2": "This is a sample overlay", diff --git a/src/generated/resources/assets/create/lang/unfinished/de_de.json b/src/generated/resources/assets/create/lang/unfinished/de_de.json index c58938a1d..2f46228b6 100644 --- a/src/generated/resources/assets/create/lang/unfinished/de_de.json +++ b/src/generated/resources/assets/create/lang/unfinished/de_de.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 800", + "_": "Missing Localizations: 804", "_": "->------------------------] Game Elements [------------------------<-", @@ -837,6 +837,10 @@ "create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s", "create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15", + "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", + "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", @@ -849,6 +853,7 @@ "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", + "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", diff --git a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json index 2ac436d6a..820163344 100644 --- a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json +++ b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 424", + "_": "Missing Localizations: 428", "_": "->------------------------] Game Elements [------------------------<-", @@ -837,6 +837,10 @@ "create.tooltip.generationSpeed": "Génère à %1$s %2$s", "create.tooltip.analogStrength": "Force analogique: %1$s/15", + "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", + "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", @@ -849,6 +853,7 @@ "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", + "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", diff --git a/src/generated/resources/assets/create/lang/unfinished/it_it.json b/src/generated/resources/assets/create/lang/unfinished/it_it.json index 28ef50685..299ac1c3a 100644 --- a/src/generated/resources/assets/create/lang/unfinished/it_it.json +++ b/src/generated/resources/assets/create/lang/unfinished/it_it.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 408", + "_": "Missing Localizations: 412", "_": "->------------------------] Game Elements [------------------------<-", @@ -837,6 +837,10 @@ "create.tooltip.generationSpeed": "Genera %1$s %2$s", "create.tooltip.analogStrength": "Forza Analogica: %1$s/15", + "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", + "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", @@ -849,6 +853,7 @@ "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", + "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", diff --git a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json index 8ffdeb2e8..4c339d77d 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json +++ b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 403", + "_": "Missing Localizations: 407", "_": "->------------------------] Game Elements [------------------------<-", @@ -837,6 +837,10 @@ "create.tooltip.generationSpeed": "%1$s %2$sを生成", "create.tooltip.analogStrength": "アナログ強度: %1$s/15", + "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", + "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", @@ -849,6 +853,7 @@ "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", + "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", diff --git a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json index 6f6e67b5c..fc1468e89 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json +++ b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 408", + "_": "Missing Localizations: 412", "_": "->------------------------] Game Elements [------------------------<-", @@ -837,6 +837,10 @@ "create.tooltip.generationSpeed": "%1$s %2$s만큼 발전함", "create.tooltip.analogStrength": "레드스톤 출력: %1$s/15", + "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", + "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", @@ -849,6 +853,7 @@ "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", + "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", diff --git a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json index 3689e2c23..a120cfccd 100644 --- a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json +++ b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 738", + "_": "Missing Localizations: 742", "_": "->------------------------] Game Elements [------------------------<-", @@ -837,6 +837,10 @@ "create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s", "create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15", + "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", + "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", @@ -849,6 +853,7 @@ "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", + "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_br.json b/src/generated/resources/assets/create/lang/unfinished/pt_br.json index 38dab76bd..f1753a13b 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pt_br.json +++ b/src/generated/resources/assets/create/lang/unfinished/pt_br.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 807", + "_": "Missing Localizations: 811", "_": "->------------------------] Game Elements [------------------------<-", @@ -837,6 +837,10 @@ "create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s", "create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15", + "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", + "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", @@ -849,6 +853,7 @@ "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", + "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", diff --git a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json index 21717a198..4ea84c952 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json +++ b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 801", + "_": "Missing Localizations: 805", "_": "->------------------------] Game Elements [------------------------<-", @@ -837,6 +837,10 @@ "create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s", "create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15", + "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", + "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", @@ -849,6 +853,7 @@ "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", + "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json index db7543fac..de1d2d829 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 88", + "_": "Missing Localizations: 92", "_": "->------------------------] Game Elements [------------------------<-", @@ -837,6 +837,10 @@ "create.tooltip.generationSpeed": "产生 %1$s %2$s", "create.tooltip.analogStrength": "调节强度: %1$s/15", + "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", + "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", + "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", + "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", @@ -849,6 +853,7 @@ "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", + "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", diff --git a/src/main/java/com/simibubi/create/AllParticleTypes.java b/src/main/java/com/simibubi/create/AllParticleTypes.java index 387933851..d583ef7aa 100644 --- a/src/main/java/com/simibubi/create/AllParticleTypes.java +++ b/src/main/java/com/simibubi/create/AllParticleTypes.java @@ -3,6 +3,7 @@ package com.simibubi.create; import java.util.function.Supplier; import com.simibubi.create.content.contraptions.particle.AirFlowParticleData; +import com.simibubi.create.content.contraptions.particle.AirParticleData; import com.simibubi.create.content.contraptions.particle.CubeParticle; import com.simibubi.create.content.contraptions.particle.CubeParticleData; import com.simibubi.create.content.contraptions.particle.HeaterParticleData; @@ -26,6 +27,7 @@ public enum AllParticleTypes { ROTATION_INDICATOR(RotationIndicatorParticleData::new), AIR_FLOW(AirFlowParticleData::new), + AIR(AirParticleData::new), HEATER_PARTICLE(HeaterParticleData::new), CUBE(CubeParticleData::dummy, () -> CubeParticle.Factory::new) diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 413289fc7..ff091b66a 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -1,7 +1,7 @@ package com.simibubi.create; -import com.simibubi.create.foundation.command.ChunkUtil; -import net.minecraftforge.common.MinecraftForge; +import java.util.Random; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -15,6 +15,7 @@ import com.simibubi.create.content.palettes.PalettesItemGroup; import com.simibubi.create.content.schematics.ServerSchematicLoader; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.AllTriggers; +import com.simibubi.create.foundation.command.ChunkUtil; import com.simibubi.create.foundation.command.ServerLagger; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.data.CreateRegistrate; @@ -34,6 +35,7 @@ import net.minecraft.particles.ParticleType; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.DistExecutor; @@ -62,6 +64,7 @@ public class Create { public static TorquePropagator torquePropagator; public static ServerLagger lagger; public static ChunkUtil chunkUtil; + public static Random random; private static final NonNullLazyValue registrate = CreateRegistrate.lazy(ID); @@ -87,6 +90,7 @@ public class Create { modEventBus.addListener(EventPriority.LOWEST, this::gatherData); AllConfigs.register(); + random = new Random(); DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> CreateClient.addClientListeners(modEventBus)); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java index 845289274..5a779c40b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java @@ -111,7 +111,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity { public void blockChanged() { removeBehaviour(InvManipulationBehaviour.TYPE); inserting = new InvManipulationBehaviour(this, this::getTargetFace); - putBehaviour(inserting); + attachBehaviourLate(inserting); } public BlockFace getTargetFace(World world, BlockPos pos, BlockState state) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerItemHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerItemHandler.java index b5dcee399..0e7ba0183 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerItemHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerItemHandler.java @@ -2,7 +2,6 @@ package com.simibubi.create.content.contraptions.components.deployer; import java.util.Iterator; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import net.minecraft.item.ItemStack; @@ -132,7 +131,7 @@ public class DeployerItemHandler implements IItemHandlerModifiable { @Override public boolean isItemValid(int slot, ItemStack stack) { - FilteringBehaviour filteringBehaviour = TileEntityBehaviour.get(te, FilteringBehaviour.TYPE); + FilteringBehaviour filteringBehaviour = te.getBehaviour(FilteringBehaviour.TYPE); return filteringBehaviour == null || filteringBehaviour.test(stack); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java index 124409bb7..f77d9c5a1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java @@ -158,60 +158,18 @@ public class AirCurrent { bounds = new AxisAlignedBB(0, 0, 0, 0, 0, 0); return; } - - World world = source.getWorld(); - BlockPos start = source.getPos(); + direction = source.getBlockState() .get(BlockStateProperties.FACING); pushing = source.getAirFlowDirection() == direction; - Vec3d directionVec = new Vec3d(direction.getDirectionVec()); - Vec3d planeVec = VecHelper.axisAlingedPlaneOf(directionVec); - - // 4 Rays test for holes in the shapes blocking the flow - float offsetDistance = .25f; - Vec3d[] offsets = new Vec3d[] { planeVec.mul(offsetDistance, offsetDistance, offsetDistance), - planeVec.mul(-offsetDistance, -offsetDistance, offsetDistance), - planeVec.mul(offsetDistance, -offsetDistance, -offsetDistance), - planeVec.mul(-offsetDistance, offsetDistance, -offsetDistance), }; - maxDistance = source.getMaxDistance(); - float limitedDistance = 0; - // Determine the distance of the air flow - Outer: for (int i = 1; i < maxDistance; i++) { - BlockPos currentPos = start.offset(direction, i); - if (!world.isBlockPresent(currentPos)) - break; - BlockState state = world.getBlockState(currentPos); - if (shouldAlwaysPass(state)) - continue; - VoxelShape voxelshape = state.getCollisionShape(world, currentPos, ISelectionContext.dummy()); - if (voxelshape.isEmpty()) - continue; - if (voxelshape == VoxelShapes.fullCube()) { - maxDistance = i - 1; - break; - } - - for (Vec3d offset : offsets) { - Vec3d rayStart = VecHelper.getCenterOf(currentPos) - .subtract(directionVec.scale(.5f + 1 / 32f)) - .add(offset); - Vec3d rayEnd = rayStart.add(directionVec.scale(1 + 1 / 32f)); - BlockRayTraceResult blockraytraceresult = - world.rayTraceBlocks(rayStart, rayEnd, currentPos, voxelshape, state); - if (blockraytraceresult == null) - continue Outer; - - double distance = i - 1 + blockraytraceresult.getHitVec() - .distanceTo(rayStart); - if (limitedDistance < distance) - limitedDistance = (float) distance; - } - - maxDistance = limitedDistance; - break; - } + World world = source.getWorld(); + BlockPos start = source.getPos(); + float max = this.maxDistance; + Direction facing = direction; + Vec3d directionVec = new Vec3d(facing.getDirectionVec()); + maxDistance = getFlowLimit(world, start, max, facing); // Determine segments with transported fluids/gases AirCurrentSegment currentSegment = new AirCurrentSegment(); @@ -257,6 +215,57 @@ public class AirCurrent { findAffectedHandlers(); } + public static float getFlowLimit(World world, BlockPos start, float max, Direction facing) { + Vec3d directionVec = new Vec3d(facing.getDirectionVec()); + Vec3d planeVec = VecHelper.axisAlingedPlaneOf(directionVec); + + // 4 Rays test for holes in the shapes blocking the flow + float offsetDistance = .25f; + Vec3d[] offsets = new Vec3d[] { planeVec.mul(offsetDistance, offsetDistance, offsetDistance), + planeVec.mul(-offsetDistance, -offsetDistance, offsetDistance), + planeVec.mul(offsetDistance, -offsetDistance, -offsetDistance), + planeVec.mul(-offsetDistance, offsetDistance, -offsetDistance), }; + + float limitedDistance = 0; + + // Determine the distance of the air flow + Outer: for (int i = 1; i <= max; i++) { + BlockPos currentPos = start.offset(facing, i); + if (!world.isBlockPresent(currentPos)) + break; + BlockState state = world.getBlockState(currentPos); + if (shouldAlwaysPass(state)) + continue; + VoxelShape voxelshape = state.getCollisionShape(world, currentPos, ISelectionContext.dummy()); + if (voxelshape.isEmpty()) + continue; + if (voxelshape == VoxelShapes.fullCube()) { + max = i - 1; + break; + } + + for (Vec3d offset : offsets) { + Vec3d rayStart = VecHelper.getCenterOf(currentPos) + .subtract(directionVec.scale(.5f + 1 / 32f)) + .add(offset); + Vec3d rayEnd = rayStart.add(directionVec.scale(1 + 1 / 32f)); + BlockRayTraceResult blockraytraceresult = + world.rayTraceBlocks(rayStart, rayEnd, currentPos, voxelshape, state); + if (blockraytraceresult == null) + continue Outer; + + double distance = i - 1 + blockraytraceresult.getHitVec() + .distanceTo(rayStart); + if (limitedDistance < distance) + limitedDistance = (float) distance; + } + + max = limitedDistance; + break; + } + return max; + } + public void findEntities() { caughtEntities.clear(); caughtEntities = source.getWorld() diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeAttachmentBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeAttachmentBehaviour.java index 71afd7cfb..0edd0cfd0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeAttachmentBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeAttachmentBehaviour.java @@ -16,10 +16,10 @@ public class FluidPipeAttachmentBehaviour extends TileEntityBehaviour { public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) { if (!isPipeConnectedTowards(state, direction)) return AttachmentTypes.NONE; - + BlockPos offsetPos = pos.offset(direction); BlockState facingState = world.getBlockState(offsetPos); - + if (facingState.getBlock() instanceof PumpBlock && facingState.get(PumpBlock.FACING) .getAxis() == direction.getAxis()) return AttachmentTypes.NONE; @@ -31,7 +31,7 @@ public class FluidPipeAttachmentBehaviour extends TileEntityBehaviour { } public boolean isPipeConnectedTowards(BlockState state, Direction direction) { - FluidPipeBehaviour fluidPipeBehaviour = TileEntityBehaviour.get(tileEntity, FluidPipeBehaviour.TYPE); + FluidPipeBehaviour fluidPipeBehaviour = tileEntity.getBehaviour(FluidPipeBehaviour.TYPE); if (fluidPipeBehaviour == null) return false; return fluidPipeBehaviour.isConnectedTo(state, direction); diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java index 47f692529..c5d446bb6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java @@ -23,7 +23,7 @@ public class TransparentStraightPipeRenderer extends SafeTileEntityRenderer= this.maxAge) { + this.setExpired(); + return; + } + + float progress = (float) Math.pow(((float) age) / maxAge, drag); + float angle = (progress * 2 * 360 + twirlAngleOffset) % 360; + Vec3d twirl = VecHelper.rotate(new Vec3d(0, twirlRadius, 0), angle, twirlAxis); + + float x = (float) (MathHelper.lerp(progress, originX, targetX) + twirl.x); + float y = (float) (MathHelper.lerp(progress, originY, targetY) + twirl.y); + float z = (float) (MathHelper.lerp(progress, originZ, targetZ) + twirl.z); + + motionX = x - posX; + motionY = y - posY; + motionZ = z - posZ; + + selectSpriteWithAge(field_217584_C); + this.move(this.motionX, this.motionY, this.motionZ); + } + + public int getBrightnessForRender(float partialTick) { + BlockPos blockpos = new BlockPos(this.posX, this.posY, this.posZ); + return this.world.isBlockPresent(blockpos) ? WorldRenderer.getLightmapCoordinates(world, blockpos) : 0; + } + + private void selectSprite(int index) { + setSprite(field_217584_C.get(index, 8)); + } + + public static class Factory implements IParticleFactory { + private final IAnimatedSprite spriteSet; + + public Factory(IAnimatedSprite animatedSprite) { + this.spriteSet = animatedSprite; + } + + public Particle makeParticle(AirParticleData data, World worldIn, double x, double y, double z, double xSpeed, + double ySpeed, double zSpeed) { + return new AirParticle(worldIn, data, x, y, z, xSpeed, ySpeed, zSpeed, this.spriteSet); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/AirParticleData.java b/src/main/java/com/simibubi/create/content/contraptions/particle/AirParticleData.java new file mode 100644 index 000000000..3f40c9576 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/particle/AirParticleData.java @@ -0,0 +1,73 @@ +package com.simibubi.create.content.contraptions.particle; + +import java.util.Locale; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.simibubi.create.AllParticleTypes; + +import net.minecraft.client.particle.ParticleManager.IParticleMetaFactory; +import net.minecraft.network.PacketBuffer; +import net.minecraft.particles.IParticleData; +import net.minecraft.particles.ParticleType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class AirParticleData implements IParticleData, ICustomParticle { + + public static final IParticleData.IDeserializer DESERIALIZER = + new IParticleData.IDeserializer() { + public AirParticleData deserialize(ParticleType particleTypeIn, StringReader reader) + throws CommandSyntaxException { + reader.expect(' '); + float drag = reader.readFloat(); + reader.expect(' '); + float speed = reader.readFloat(); + return new AirParticleData(drag, speed); + } + + public AirParticleData read(ParticleType particleTypeIn, PacketBuffer buffer) { + return new AirParticleData(buffer.readFloat(), buffer.readFloat()); + } + }; + + float drag; + float speed; + + public AirParticleData(float drag, float speed) { + this.drag = drag; + this.speed = speed; + } + + public AirParticleData() { + this(0, 0); + } + + @Override + public ParticleType getType() { + return AllParticleTypes.AIR.get(); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeFloat(drag); + buffer.writeFloat(speed); + } + + @Override + public String getParameters() { + return String.format(Locale.ROOT, "%s %f %f", AllParticleTypes.AIR.parameter(), drag, speed); + } + + @Override + public IDeserializer getDeserializer() { + return DESERIALIZER; + } + + @Override + @OnlyIn(Dist.CLIENT) + public IParticleMetaFactory getFactory() { + return AirParticle.Factory::new; + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticle.java b/src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticle.java index a9df78e38..298bce251 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticle.java +++ b/src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticle.java @@ -1,8 +1,11 @@ package com.simibubi.create.content.contraptions.particle; +import org.lwjgl.opengl.GL11; + import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.IVertexBuilder; + import net.minecraft.client.particle.IParticleFactory; import net.minecraft.client.particle.IParticleRenderType; import net.minecraft.client.particle.Particle; @@ -15,7 +18,6 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -import org.lwjgl.opengl.GL11; public class CubeParticle extends Particle { diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticle.java b/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticle.java index 1543ab12d..713314f8c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticle.java +++ b/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticle.java @@ -1,5 +1,7 @@ package com.simibubi.create.content.contraptions.particle; +import javax.annotation.ParametersAreNonnullByDefault; + import mcp.MethodsReturnNonnullByDefault; import net.minecraft.client.particle.IAnimatedSprite; import net.minecraft.client.particle.IParticleFactory; @@ -9,8 +11,6 @@ import net.minecraft.client.particle.SimpleAnimatedParticle; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; -import javax.annotation.ParametersAreNonnullByDefault; - @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault public class HeaterParticle extends SimpleAnimatedParticle { diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java index 4229d67b7..2fb39ce91 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java @@ -360,9 +360,11 @@ public class BeltTileEntity extends KineticTileEntity { private void applyToAllItems(float maxDistanceFromCenter, Function processFunction) { BeltTileEntity controller = getControllerTE(); - if (controller != null) - controller.getInventory() - .applyToEachWithin(index + .5f, maxDistanceFromCenter, processFunction); + if (controller == null) + return; + BeltInventory inventory = controller.getInventory(); + if (inventory != null) + inventory.applyToEachWithin(index + .5f, maxDistanceFromCenter, processFunction); } private Vec3d getWorldPositionOf(TransportedItemStack transported) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java index 5957bd788..ad2d4e10f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java @@ -3,13 +3,13 @@ package com.simibubi.create.content.contraptions.relays.belt.transport; import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; @@ -31,36 +31,38 @@ public class BeltFunnelInteractionHandler { BlockState funnelState = world.getBlockState(funnelPos); if (!(funnelState.getBlock() instanceof BeltFunnelBlock)) continue; - if (funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING) != beltInventory.belt.getMovementFacing() - .getOpposite()) + Direction funnelFacing = funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING); + Direction movementFacing = beltInventory.belt.getMovementFacing(); + boolean blocking = funnelFacing == movementFacing.getOpposite(); + if (funnelFacing == movementFacing) continue; currentItem.beltPosition = segment + .5f; if (world.isRemote) - return true; + return blocking; if (funnelState.get(BeltFunnelBlock.PUSHING)) - return true; + return blocking; if (funnelState.has(BeltFunnelBlock.POWERED) && funnelState.get(BeltFunnelBlock.POWERED)) - return true; + return blocking; TileEntity te = world.getTileEntity(funnelPos); if (!(te instanceof FunnelTileEntity)) return true; FunnelTileEntity funnelTE = (FunnelTileEntity) te; - InvManipulationBehaviour inserting = TileEntityBehaviour.get(funnelTE, InvManipulationBehaviour.TYPE); - FilteringBehaviour filtering = TileEntityBehaviour.get(funnelTE, FilteringBehaviour.TYPE); + InvManipulationBehaviour inserting = funnelTE.getBehaviour(InvManipulationBehaviour.TYPE); + FilteringBehaviour filtering = funnelTE.getBehaviour(FilteringBehaviour.TYPE); if (inserting == null) - return true; + return blocking; if (filtering != null && !filtering.test(currentItem.stack)) - return true; + return blocking; ItemStack before = currentItem.stack.copy(); ItemStack remainder = inserting.insert(before); if (before.equals(remainder, false)) - return true; + return blocking; funnelTE.flap(true); currentItem.stack = remainder; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltTunnelInteractionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltTunnelInteractionHandler.java index b916628dc..0ad9792fd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltTunnelInteractionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltTunnelInteractionHandler.java @@ -37,8 +37,7 @@ public class BeltTunnelInteractionHandler { if (nextTunnel instanceof BrassTunnelTileEntity) { BrassTunnelTileEntity brassTunnel = (BrassTunnelTileEntity) nextTunnel; if (brassTunnel.hasDistributionBehaviour()) { - if (!brassTunnel.getStackToDistribute() - .isEmpty()) + if (!brassTunnel.canTakeItems()) return true; if (onServer) { brassTunnel.setStackToDistribute(current.stack); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java index 35b8f287d..ce91f29b0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java @@ -168,10 +168,14 @@ public class BeltTunnelBlock extends Block implements ITE, Direction fw = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis); BlockState blockState1 = reader.getBlockState(pos.offset(fw)); BlockState blockState2 = reader.getBlockState(pos.offset(fw.getOpposite())); + boolean funnel1 = blockState1.getBlock() instanceof BeltFunnelBlock + && blockState1.get(BeltFunnelBlock.SHAPE) == BeltFunnelBlock.Shape.EXTENDED && blockState1.get(BeltFunnelBlock.HORIZONTAL_FACING) == fw.getOpposite(); boolean funnel2 = blockState2.getBlock() instanceof BeltFunnelBlock + && blockState2.get(BeltFunnelBlock.SHAPE) == BeltFunnelBlock.Shape.EXTENDED && blockState2.get(BeltFunnelBlock.HORIZONTAL_FACING) == fw; + boolean valid1 = blockState1.getBlock() instanceof BeltTunnelBlock || funnel1; boolean valid2 = blockState2.getBlock() instanceof BeltTunnelBlock || funnel2; boolean canHaveWindow = valid1 && valid2 && !(funnel1 && funnel2); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java index d48faab5c..768a34ad5 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java @@ -130,7 +130,8 @@ public class BeltTunnelTileEntity extends SmartTileEntity { BlockState funnelState = world.getBlockState(getPos().offset(direction)); if (funnelState.getBlock() instanceof BeltFunnelBlock) - if (funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING) == direction.getOpposite()) + if (funnelState.get(BeltFunnelBlock.SHAPE) == BeltFunnelBlock.Shape.EXTENDED + && funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING) == direction.getOpposite()) continue; flaps.put(direction, new InterpolatedChasingValue().start(.25f) diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelItemHandler.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelItemHandler.java index b103dd5ae..317457f24 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelItemHandler.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelItemHandler.java @@ -31,7 +31,7 @@ public class BrassTunnelItemHandler implements IItemHandler { return beltCapability.orElse(null).insertItem(slot, stack, simulate); } - if (!te.stackToDistribute.isEmpty()) + if (!te.canTakeItems()) return stack; if (!simulate) te.setStackToDistribute(stack); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java index e3a5c0fb4..f2d2687d5 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java @@ -1,8 +1,10 @@ package com.simibubi.create.content.logistics.block.belts.tunnel; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Random; +import java.util.Set; import javax.annotation.Nullable; @@ -58,6 +60,9 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { int distributionDistanceRight; int previousOutputIndex; + private boolean syncedOutputActive; + private Set syncSet; + protected ScrollOptionBehaviour selectionMode; private LazyOptional beltCapability; private LazyOptional tunnelCapability; @@ -65,10 +70,12 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { public BrassTunnelTileEntity(TileEntityType type) { super(type); distributionTargets = new ArrayList<>(); + syncSet = new HashSet<>(); stackToDistribute = ItemStack.EMPTY; beltCapability = LazyOptional.empty(); tunnelCapability = LazyOptional.of(() -> new BrassTunnelItemHandler(this)); previousOutputIndex = 0; + syncedOutputActive = false; } @Override @@ -100,7 +107,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { distributionProgress--; if (beltBelow == null || beltBelow.getSpeed() == 0) return; - if (stackToDistribute.isEmpty()) + if (stackToDistribute.isEmpty() && !syncedOutputActive) return; if (world.isRemote) return; @@ -109,7 +116,28 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { distributionTargets.clear(); distributionDistanceLeft = 0; distributionDistanceRight = 0; - for (Pair pair : gatherValidOutputs()) { + + syncSet.clear(); + List> validOutputs = gatherValidOutputs(); + if (selectionMode.get() == SelectionMode.SYNCHRONIZE) { + boolean allEmpty = true; + boolean allFull = true; + for (BrassTunnelTileEntity te : syncSet) { + boolean hasStack = !te.stackToDistribute.isEmpty(); + allEmpty &= !hasStack; + allFull &= hasStack; + } + final boolean notifySyncedOut = !allEmpty; + if (allFull || allEmpty) + syncSet.forEach(te -> te.syncedOutputActive = notifySyncedOut); + } + + if (validOutputs == null) + return; + if (stackToDistribute.isEmpty()) + return; + + for (Pair pair : validOutputs) { BrassTunnelTileEntity tunnel = pair.getKey(); Direction output = pair.getValue(); if (insertIntoTunnel(tunnel, output, stackToDistribute, true) == null) @@ -125,8 +153,10 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { if (distributionTargets.isEmpty()) return; - distributionProgress = 10; - sendData(); + if (selectionMode.get() != SelectionMode.SYNCHRONIZE || syncedOutputActive) { + distributionProgress = 10; + sendData(); + } return; } @@ -162,7 +192,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { if (mode == SelectionMode.RANDOMIZE) indexStart = rand.nextInt(amountTargets); - if (mode == SelectionMode.PREFER_NEAREST) + if (mode == SelectionMode.PREFER_NEAREST || mode == SelectionMode.SYNCHRONIZE) indexStart = 0; ItemStack toDistribute = null; @@ -290,7 +320,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { public void initialize() { if (filtering == null) { filtering = createSidedFilter(); - putBehaviour(filtering); + attachBehaviourLate(filtering); } super.initialize(); } @@ -322,22 +352,29 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { private List> gatherValidOutputs() { List> validOutputs = new ArrayList<>(); + boolean synchronize = selectionMode.get() == SelectionMode.SYNCHRONIZE; addValidOutputsOf(this, validOutputs); + for (boolean left : Iterate.trueAndFalse) { BrassTunnelTileEntity adjacent = this; while (adjacent != null) { if (!world.isAreaLoaded(adjacent.getPos(), 1)) return null; adjacent = adjacent.getAdjacent(left); - if (adjacent != null) - addValidOutputsOf(adjacent, validOutputs); + if (adjacent == null) + continue; + addValidOutputsOf(adjacent, validOutputs); } } + + if (!syncedOutputActive && synchronize) + return null; return validOutputs; } private void addValidOutputsOf(BrassTunnelTileEntity tunnelTE, List> validOutputs) { + syncSet.add(tunnelTE); BeltTileEntity below = BeltHelper.getSegmentTE(world, tunnelTE.pos.down()); if (below == null) return; @@ -400,6 +437,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { @Override public void write(CompoundNBT compound, boolean clientPacket) { + compound.putBoolean("SyncedOutput", syncedOutputActive); compound.putBoolean("ConnectedLeft", connectedLeft); compound.putBoolean("ConnectedRight", connectedRight); @@ -424,6 +462,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { boolean wasConnectedLeft = connectedLeft; boolean wasConnectedRight = connectedRight; + syncedOutputActive = compound.getBoolean("SyncedOutput"); connectedLeft = compound.getBoolean("ConnectedLeft"); connectedRight = compound.getBoolean("ConnectedRight"); stackToDistribute = ItemStack.read(compound.getCompound("StackToDistribute")); @@ -549,6 +588,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { FORCED_ROUND_ROBIN(AllIcons.I_TUNNEL_FORCED_ROUND_ROBIN), PREFER_NEAREST(AllIcons.I_TUNNEL_PREFER_NEAREST), RANDOMIZE(AllIcons.I_TUNNEL_RANDOMIZE), + SYNCHRONIZE(AllIcons.I_TUNNEL_SYNCHRONIZE), ; @@ -571,4 +611,8 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { } } + public boolean canTakeItems() { + return stackToDistribute.isEmpty() && !syncedOutputActive; + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteBlock.java index 9c6d7e4a6..187916f85 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteBlock.java @@ -147,6 +147,13 @@ public class ChuteBlock extends Block implements IWrenchable, ITE { BlockState blockState = te.getBlockState(); if (blockState.get(ChuteBlock.FACING) != Direction.DOWN) return; - if (blockState.get(ChuteBlock.SHAPE) != Shape.WINDOW) + if (blockState.get(ChuteBlock.SHAPE) != Shape.WINDOW + && (te.bottomPullDistance == 0 || te.itemPosition.get(partialTicks) > .5f)) return; ItemRenderer itemRenderer = Minecraft.getInstance() diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java index 067d5c4b3..e7f2987fb 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java @@ -7,18 +7,25 @@ import javax.annotation.Nullable; import com.google.common.base.Predicates; import com.simibubi.create.AllBlocks; +import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.components.fan.AirCurrent; import com.simibubi.create.content.contraptions.components.fan.EncasedFanBlock; import com.simibubi.create.content.contraptions.components.fan.EncasedFanTileEntity; import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.contraptions.particle.AirParticleData; import com.simibubi.create.content.logistics.block.chute.ChuteBlock.Shape; import com.simibubi.create.content.logistics.block.funnel.BrassFunnelBlock; import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; +import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.gui.widgets.InterpolatedValue; import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.VecHelper; @@ -33,6 +40,7 @@ import net.minecraft.particles.ParticleTypes; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -54,6 +62,13 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor LazyOptional lazyHandler; boolean canPickUpItems; + float bottomPullDistance; + int airCurrentUpdateCooldown; + int entitySearchCooldown; + boolean updateAirFlow; + TransportedItemStackHandlerBehaviour beltBelow; + float beltBelowOffset; + LazyOptional capAbove; LazyOptional capBelow; @@ -66,6 +81,8 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor canPickUpItems = false; capAbove = LazyOptional.empty(); capBelow = LazyOptional.empty(); + bottomPullDistance = 0; + updateAirFlow = true; } @Override @@ -94,14 +111,25 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor @Override public void initialize() { super.initialize(); + onAdded(); + } + + @Override + public AxisAlignedBB getRenderBoundingBox() { + return new AxisAlignedBB(pos).expand(0, -3, 0); } @Override public void tick() { super.tick(); + canPickUpItems = canDirectlyInsert(); float itemMotion = getItemMotion(); + if (itemMotion != 0 && world.isRemote) + spawnParticles(itemMotion); + if (itemMotion > 0) + tickAirStreamFromBelow(itemMotion); if (item.isEmpty()) { if (itemMotion < 0) @@ -138,6 +166,127 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor itemPosition.set(nextOffset); } + private void tickAirStreamFromBelow(float itemSpeed) { + if (world.isRemote) + return; + + if (airCurrentUpdateCooldown-- <= 0) { + airCurrentUpdateCooldown = AllConfigs.SERVER.kinetics.fanBlockCheckRate.get(); + updateAirFlow = true; + } + + if (bottomPullDistance > 0 && getItem().isEmpty() && entitySearchCooldown-- <= 0) { + entitySearchCooldown = 5; + Vec3d center = VecHelper.getCenterOf(pos); + AxisAlignedBB searchArea = + new AxisAlignedBB(center.add(0, -bottomPullDistance - 0.5, 0), center.add(0, -0.5, 0)).grow(.45f); + for (ItemEntity itemEntity : world.getEntitiesWithinAABB(ItemEntity.class, searchArea)) { + setItem(itemEntity.getItem() + .copy(), + (float) (itemEntity.getBoundingBox() + .getCenter().y - pos.getY())); + itemEntity.remove(); + break; + } + } + + if (getItem().isEmpty() && beltBelow != null) { + beltBelow.handleCenteredProcessingOnAllItems(.5f, ts -> { + if (getItem().isEmpty()) { + setItem(ts.stack.copy(), -beltBelowOffset); + return TransportedResult.removeItem(); + } + return TransportedResult.doNothing(); + }); + } + + if (!updateAirFlow) + return; + + float speed = pull - push; + float flowLimit = 0; + updateAirFlow = false; + beltBelow = null; + + float maxPullDistance; + if (speed >= 128) + maxPullDistance = 3; + else if (speed >= 64) + maxPullDistance = 2; + else if (speed >= 32) + maxPullDistance = 1; + else + maxPullDistance = MathHelper.lerp(speed / 32, 0, 1); + + if (AllBlocks.CHUTE.has(world.getBlockState(pos.down()))) + maxPullDistance = 0; + flowLimit = maxPullDistance; + if (flowLimit > 0) + flowLimit = AirCurrent.getFlowLimit(world, pos, maxPullDistance, Direction.DOWN); + + for (int i = 1; i <= flowLimit + 1; i++) { + TransportedItemStackHandlerBehaviour behaviour = + TileEntityBehaviour.get(world, pos.down(i), TransportedItemStackHandlerBehaviour.TYPE); + if (behaviour == null) + continue; + beltBelow = behaviour; + beltBelowOffset = i - 1; + break; + } + + if (bottomPullDistance == flowLimit) + return; + + this.bottomPullDistance = flowLimit; + sendData(); + } + + public void blockBelowChanged() { + updateAirFlow = true; + } + + private void spawnParticles(float itemMotion) { + BlockState blockState = getBlockState(); + boolean up = itemMotion > 0; + float absMotion = up ? itemMotion : -itemMotion; + if (blockState == null || !(blockState.getBlock() instanceof ChuteBlock)) + return; + if (push == 0 && pull == 0) + return; + + if (up + && (blockState.get(ChuteBlock.FACING) == Direction.DOWN + || blockState.get(ChuteBlock.SHAPE) == Shape.INTERSECTION) + && BlockHelper.noCollisionInSpace(world, pos.up())) + spawnAirFlow(1, 2, absMotion, .5f); + + if (blockState.get(ChuteBlock.FACING) != Direction.DOWN) + return; + + if (blockState.get(ChuteBlock.SHAPE) == Shape.WINDOW) + spawnAirFlow(up ? 0 : 1, up ? 1 : 0, absMotion, 1); + + if (!up && BlockHelper.noCollisionInSpace(world, pos.down())) + spawnAirFlow(0, -1, absMotion, .5f); + + if (up && bottomPullDistance > 0) { + spawnAirFlow(-bottomPullDistance, 0, absMotion, 2); + spawnAirFlow(-bottomPullDistance, 0, absMotion, 2); + } + } + + private void spawnAirFlow(float verticalStart, float verticalEnd, float motion, float drag) { + AirParticleData airParticleData = new AirParticleData(drag, motion); + Vec3d origin = new Vec3d(pos); + float xOff = Create.random.nextFloat() * .5f + .25f; + float zOff = Create.random.nextFloat() * .5f + .25f; + Vec3d v = origin.add(xOff, verticalStart, zOff); + Vec3d d = origin.add(xOff, verticalEnd, zOff) + .subtract(v); + if (Create.random.nextFloat() < 2 * motion) + world.addOptionalParticle(airParticleData, v.x, v.y, v.z, d.x, d.y, d.z); + } + private void handleInputFromAbove() { if (!capAbove.isPresent()) capAbove = grabCapability(Direction.UP); @@ -200,7 +349,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor capBelow = grabCapability(Direction.DOWN); if (capBelow.isPresent()) { ItemStack remainder = ItemHandlerHelper.insertItemStacked(capBelow.orElse(null), item, simulate); - if (!simulate) + if (!simulate) setItem(ItemStack.EMPTY); return remainder.isEmpty(); } @@ -260,7 +409,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor capAbove = grabCapability(Direction.UP); if (capAbove.isPresent()) { ItemStack remainder = ItemHandlerHelper.insertItemStacked(capAbove.orElse(null), item, simulate); - if (!simulate) + if (!simulate) setItem(ItemStack.EMPTY); return remainder.isEmpty(); } @@ -314,6 +463,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor compound.putFloat("ItemPosition", itemPosition.value); compound.putFloat("Pull", pull); compound.putFloat("Push", push); + compound.putFloat("BottomAirFlowDistance", bottomPullDistance); super.write(compound, clientPacket); } @@ -324,6 +474,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor itemPosition.lastValue = itemPosition.value = compound.getFloat("ItemPosition"); pull = compound.getFloat("Pull"); push = compound.getFloat("Push"); + bottomPullDistance = compound.getFloat("BottomAirFlowDistance"); super.read(compound, clientPacket); if (hasWorld() && world.isRemote && !previousItem.equals(item, false) && !item.isEmpty()) { @@ -339,11 +490,11 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor public float getItemMotion() { // Chutes per second final float fanSpeedModifier = 1 / 64f; - final float maxUpwardItemSpeed = 20f; + final float maxItemSpeed = 20f; final float gravity = 4f; - float upwardMotion = (push + pull) * fanSpeedModifier; - return (upwardMotion == 0 ? -gravity : MathHelper.clamp(upwardMotion, 0, maxUpwardItemSpeed)) / 20f; + float motion = (push + pull) * fanSpeedModifier; + return (MathHelper.clamp(motion, -maxItemSpeed, maxItemSpeed) + (motion <= 0 ? -gravity : 0)) / 20f; } public void onRemoved(BlockState chuteState) { @@ -374,6 +525,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor if (pull == totalPull) return; pull = totalPull; + updateAirFlow = true; sendData(); ChuteTileEntity targetChute = getTargetChute(getBlockState()); if (targetChute != null) @@ -384,6 +536,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor float totalPush = calculatePush(branchCount); if (push == totalPush) return; + updateAirFlow = true; push = totalPush; sendData(); propagatePush(); @@ -401,7 +554,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor TileEntity te = world.getTileEntity(pos.up()); if (te instanceof EncasedFanTileEntity && !te.isRemoved()) { EncasedFanTileEntity fan = (EncasedFanTileEntity) te; - return Math.abs(fan.getSpeed()); + return fan.getSpeed(); } } @@ -421,7 +574,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor TileEntity te = world.getTileEntity(pos.down()); if (te instanceof EncasedFanTileEntity && !te.isRemoved()) { EncasedFanTileEntity fan = (EncasedFanTileEntity) te; - return Math.abs(fan.getSpeed()); + return fan.getSpeed(); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java index 98c8626f8..63f2755a2 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java @@ -95,13 +95,10 @@ public class DepotRenderer extends SafeTileEntityRenderer { boolean renderUpright = BeltHelper.isItemUpright(itemStack); boolean blockItem = itemRenderer.getItemModelWithOverrides(itemStack, null, null) .isGui3d(); - + ms.push(); msr.rotateY(angle); - if (!blockItem && !renderUpright) { - ms.translate(0, -.09375, 0); - msr.rotateX(90); - } + if (renderUpright) { Entity renderViewEntity = Minecraft.getInstance().renderViewEntity; if (renderViewEntity != null) { @@ -111,14 +108,18 @@ public class DepotRenderer extends SafeTileEntityRenderer { float yRot = (float) MathHelper.atan2(diff.z, -diff.x); ms.multiply(Vector3f.POSITIVE_Y.getRadialQuaternion((float) (yRot - Math.PI / 2))); } - ms.translate(0, 3 / 32d, 1/16f); + ms.translate(0, 3 / 32d, 1 / 16f); } - + for (int i = 0; i <= count; i++) { ms.push(); if (blockItem) ms.translate(r.nextFloat() * .0625f * i, 0, r.nextFloat() * .0625f * i); ms.scale(.5f, .5f, .5f); + if (!blockItem && !renderUpright) { + ms.translate(0, -3 / 16f, 0); + msr.rotateX(90); + } itemRenderer.renderItem(itemStack, TransformType.FIXED, light, overlay, ms, buffer); ms.pop(); @@ -129,7 +130,7 @@ public class DepotRenderer extends SafeTileEntityRenderer { } else ms.translate(0, 0, -1 / 16f); } - + ms.pop(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java index 900f4d45d..019ada874 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java @@ -33,6 +33,7 @@ public class DepotTileEntity extends SmartTileEntity { DepotItemHandler itemHandler; LazyOptional lazyItemHandler; + private TransportedItemStackHandlerBehaviour transportedHandler; public DepotTileEntity(TileEntityType tileEntityTypeIn) { super(tileEntityTypeIn); @@ -75,9 +76,8 @@ public class DepotTileEntity extends SmartTileEntity { boolean wasLocked = heldItem.locked; ItemStack previousItem = heldItem.stack; - TransportedItemStackHandlerBehaviour handler = getBehaviour(TransportedItemStackHandlerBehaviour.TYPE); - ProcessingResult result = wasLocked ? processingBehaviour.handleHeldItem(heldItem, handler) - : processingBehaviour.handleReceivedItem(heldItem, handler); + ProcessingResult result = wasLocked ? processingBehaviour.handleHeldItem(heldItem, transportedHandler) + : processingBehaviour.handleReceivedItem(heldItem, transportedHandler); if (result == ProcessingResult.REMOVE) { heldItem = null; sendData(); @@ -116,8 +116,9 @@ public class DepotTileEntity extends SmartTileEntity { @Override public void addBehaviours(List behaviours) { behaviours.add(new DirectBeltInputBehaviour(this).setInsertionHandler(this::tryInsertingFromSide)); - behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) - .withStackPlacement(this::getWorldPositionOf)); + transportedHandler = new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) + .withStackPlacement(this::getWorldPositionOf); + behaviours.add(transportedHandler); } public ItemStack getHeldItemStack() { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java index c0b721908..570eef9bf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java @@ -101,16 +101,19 @@ public abstract class BeltFunnelBlock extends HorizontalInteractionFunnelBlock { return false; if (!BeltBlock.canTransport(stateBelow)) return false; - if (stateBelow.get(BeltBlock.HORIZONTAL_FACING) - .getAxis() != state.get(HORIZONTAL_FACING) - .getAxis()) - return false; return true; } public static BlockState updateShape(BlockState state, IBlockReader world, BlockPos pos) { state = state.with(SHAPE, Shape.RETRACTED); - BlockState neighbour = world.getBlockState(pos.offset(state.get(HORIZONTAL_FACING))); + Direction horizontalFacing = state.get(HORIZONTAL_FACING); + + BlockState below = world.getBlockState(pos.down()); + if (below.getBlock() instanceof BeltBlock && below.get(BeltBlock.HORIZONTAL_FACING) + .getAxis() != horizontalFacing.getAxis()) + return state; + + BlockState neighbour = world.getBlockState(pos.offset(horizontalFacing)); if (canConnectTo(state, neighbour)) return state.with(SHAPE, Shape.EXTENDED); return state; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java index 69f9e19c5..c606f8bf4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java @@ -1,10 +1,13 @@ package com.simibubi.create.content.logistics.block.funnel; import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape; +import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; @@ -26,16 +29,19 @@ public class FunnelTileEntity extends SmartTileEntity { private FilteringBehaviour filtering; private InvManipulationBehaviour invManipulation; + private InvManipulationBehaviour autoExtractor; + private int extractionCooldown; int sendFlap; InterpolatedChasingValue flap; static enum Mode { - INVALID, PAUSED, COLLECT, BELT + INVALID, PAUSED, COLLECT, PUSHING_TO_BELT, TAKING_FROM_BELT, HOPPER } public FunnelTileEntity(TileEntityType tileEntityTypeIn) { super(tileEntityTypeIn); + extractionCooldown = 0; flap = new InterpolatedChasingValue().start(.25f) .target(0) .withSpeed(.05f); @@ -47,8 +53,12 @@ public class FunnelTileEntity extends SmartTileEntity { return Mode.INVALID; if (state.has(BlockStateProperties.POWERED) && state.get(BlockStateProperties.POWERED)) return Mode.PAUSED; - if (state.getBlock() instanceof BeltFunnelBlock) - return Mode.BELT; + if (FunnelBlock.getFunnelFacing(state) == Direction.UP && autoExtractor.hasInventory()) + return Mode.HOPPER; + if (state.getBlock() instanceof BeltFunnelBlock) { + boolean pushing = state.get(BeltFunnelBlock.PUSHING); + return pushing ? Mode.PUSHING_TO_BELT : Mode.TAKING_FROM_BELT; + } return Mode.COLLECT; } @@ -57,45 +67,87 @@ public class FunnelTileEntity extends SmartTileEntity { super.tick(); flap.tick(); Mode mode = determineCurrentMode(); - if (mode == Mode.BELT) - tickAsBeltFunnel(); - if (world.isRemote) - return; - } - - public void tickAsBeltFunnel() { - BlockState blockState = getBlockState(); - Direction facing = blockState.get(BeltFunnelBlock.HORIZONTAL_FACING); if (world.isRemote) return; - Boolean pushing = blockState.get(BeltFunnelBlock.PUSHING); - if (!pushing) { - // Belts handle insertion from their side - if (AllBlocks.BELT.has(world.getBlockState(pos.down()))) - return; - TransportedItemStackHandlerBehaviour handler = - TileEntityBehaviour.get(world, pos.down(), TransportedItemStackHandlerBehaviour.TYPE); - if (handler == null) - return; - handler.handleCenteredProcessingOnAllItems(1 / 32f, this::collectFromHandler); + // Redstone resets the extraction cooldown + if (mode == Mode.PAUSED) + extractionCooldown = 0; + if (mode == Mode.TAKING_FROM_BELT) + tickAsPullingBeltFunnel(); + + if (extractionCooldown > 0) { + extractionCooldown--; return; } + if (mode == Mode.PUSHING_TO_BELT) + activateExtractingBeltFunnel(); + if (mode == Mode.HOPPER) + activateHopper(); + } + + private void activateHopper() { + if (!invManipulation.hasInventory()) + return; + int amountToExtract = autoExtractor.getAmountFromFilter(); + if (!filtering.isActive()) + amountToExtract = 1; + + Predicate filter = s -> !filtering.isActive() || filtering.test(s); + Function amountThreshold = s -> s.getMaxStackSize() - invManipulation.simulate() + .insert(s) + .getCount(); + + if (amountToExtract != -1 && !invManipulation.simulate() + .insert(autoExtractor.simulate() + .extract(amountToExtract, filter)) + .isEmpty()) + return; + + ItemStack stack = autoExtractor.extract(amountToExtract, filter, amountThreshold); + if (stack.isEmpty()) + return; + invManipulation.insert(stack); + startCooldown(); + } + + private void tickAsPullingBeltFunnel() { + // Belts handle insertion from their side + if (AllBlocks.BELT.has(world.getBlockState(pos.down()))) + return; + TransportedItemStackHandlerBehaviour handler = + TileEntityBehaviour.get(world, pos.down(), TransportedItemStackHandlerBehaviour.TYPE); + if (handler == null) + return; + handler.handleCenteredProcessingOnAllItems(1 / 32f, this::collectFromHandler); + } + + private void activateExtractingBeltFunnel() { + BlockState blockState = getBlockState(); + Direction facing = blockState.get(BeltFunnelBlock.HORIZONTAL_FACING); DirectBeltInputBehaviour inputBehaviour = TileEntityBehaviour.get(world, pos.down(), DirectBeltInputBehaviour.TYPE); + if (inputBehaviour == null) return; if (!inputBehaviour.canInsertFromSide(facing)) return; - ItemStack stack = invManipulation.extract(invManipulation.getAmountFromFilter(), - s -> inputBehaviour.handleInsertion(s, facing, true) - .isEmpty()); + int amountToExtract = invManipulation.getAmountFromFilter(); + if (!filtering.isActive()) + amountToExtract = 1; + ItemStack stack = invManipulation.extract(amountToExtract, s -> inputBehaviour.handleInsertion(s, facing, true) + .isEmpty()); if (stack.isEmpty()) return; flap(false); inputBehaviour.handleInsertion(stack, facing, false); + startCooldown(); + } + + private int startCooldown() { + return extractionCooldown = AllConfigs.SERVER.logistics.defaultExtractionTimer.get(); } private TransportedResult collectFromHandler(TransportedItemStack stack) { @@ -120,18 +172,27 @@ public class FunnelTileEntity extends SmartTileEntity { public void addBehaviours(List behaviours) { invManipulation = new InvManipulationBehaviour(this, InterfaceProvider.oppositeOfBlockFacing()); behaviours.add(invManipulation); + autoExtractor = InvManipulationBehaviour.forExtraction(this, InterfaceProvider.towardBlockFacing()); + behaviours.add(autoExtractor); - filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning()).showCountWhen(() -> { - BlockState blockState = getBlockState(); - return blockState.getBlock() instanceof HorizontalInteractionFunnelBlock - && blockState.get(HorizontalInteractionFunnelBlock.PUSHING); - }); + filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning()); + filtering.showCountWhen(this::supportsAmountOnFilter); filtering.onlyActiveWhen(this::supportsFiltering); behaviours.add(filtering); + behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput) .setInsertionHandler(this::handleDirectBeltInput)); } + private boolean supportsAmountOnFilter() { + BlockState blockState = getBlockState(); + boolean pushingToBelt = blockState.getBlock() instanceof HorizontalInteractionFunnelBlock + && blockState.get(HorizontalInteractionFunnelBlock.PUSHING); + boolean hopper = FunnelBlock.getFunnelFacing(blockState) == Direction.UP && invManipulation.hasInventory() + && autoExtractor.hasInventory(); + return pushingToBelt || hopper; + } + private boolean supportsDirectBeltInput(Direction side) { BlockState blockState = getBlockState(); if (blockState == null) @@ -171,6 +232,7 @@ public class FunnelTileEntity extends SmartTileEntity { @Override protected void write(CompoundNBT compound, boolean clientPacket) { super.write(compound, clientPacket); + compound.putInt("TransferCooldown", extractionCooldown); if (clientPacket && sendFlap != 0) { compound.putInt("Flap", sendFlap); sendFlap = 0; @@ -180,6 +242,7 @@ public class FunnelTileEntity extends SmartTileEntity { @Override protected void read(CompoundNBT compound, boolean clientPacket) { super.read(compound, clientPacket); + extractionCooldown = compound.getInt("TransferCooldown"); if (clientPacket && compound.contains("Flap")) { int direction = compound.getInt("Flap"); flap.set(direction); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java index 7a5a181cc..573bc1c28 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java @@ -10,6 +10,7 @@ import com.simibubi.create.AllItems; import com.simibubi.create.CreateClient; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode; import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.Lang; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; @@ -21,6 +22,9 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.event.entity.player.PlayerInteractEvent; @@ -55,6 +59,17 @@ public class ArmInteractionPointHandler { } selected.cycleMode(); + PlayerEntity player = event.getPlayer(); + if (player != null) { + String key = selected.mode == Mode.DEPOSIT ? "mechanical_arm.deposit_to" : "mechanical_arm.extract_from"; + TextFormatting colour = selected.mode == Mode.DEPOSIT ? TextFormatting.GOLD : TextFormatting.AQUA; + String translatedBlock = new TranslationTextComponent(selected.state.getBlock() + .getTranslationKey()).getFormattedText(); + player.sendStatusMessage( + new StringTextComponent(colour + Lang.translate(key, TextFormatting.WHITE + translatedBlock + colour)), + true); + } + event.setCanceled(true); event.setCancellationResult(ActionResultType.SUCCESS); } @@ -75,6 +90,20 @@ public class ArmInteractionPointHandler { public static void flushSettings(BlockPos pos) { if (currentItem == null) return; + + int removed = 0; + for (Iterator iterator = currentSelection.iterator(); iterator.hasNext();) { + ArmInteractionPoint point = iterator.next(); + if (point.pos.withinDistance(pos, ArmTileEntity.getRange())) + continue; + iterator.remove(); + removed++; + } + + if (removed > 0) + Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent( + TextFormatting.RED + Lang.translate("mechanical_arm.points_outside_range", removed)), true); + AllPackets.channel.sendToServer(new ArmPlacementPacket(currentSelection, pos)); currentSelection.clear(); currentItem = null; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java index c7e17c488..93d21dea1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java @@ -9,6 +9,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Jukebox; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode; import com.simibubi.create.foundation.advancement.AllTriggers; +import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.widgets.InterpolatedAngle; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; @@ -328,6 +329,8 @@ public class ArmTileEntity extends KineticTileEntity { protected void initInteractionPoints() { if (!updateInteractionPoints || interactionPointTag == null) return; + if (!world.isAreaLoaded(pos, getRange() + 1)) + return; inputs.clear(); outputs.clear(); for (INBT inbt : interactionPointTag) { @@ -348,16 +351,21 @@ public class ArmTileEntity extends KineticTileEntity { public void write(CompoundNBT compound, boolean clientPacket) { super.write(compound, clientPacket); - ListNBT pointsNBT = new ListNBT(); - inputs.stream() - .map(ArmInteractionPoint::serialize) - .forEach(pointsNBT::add); - outputs.stream() - .map(ArmInteractionPoint::serialize) - .forEach(pointsNBT::add); + if (updateInteractionPoints) { + compound.put("InteractionPoints", interactionPointTag); + + } else { + ListNBT pointsNBT = new ListNBT(); + inputs.stream() + .map(ArmInteractionPoint::serialize) + .forEach(pointsNBT::add); + outputs.stream() + .map(ArmInteractionPoint::serialize) + .forEach(pointsNBT::add); + compound.put("InteractionPoints", pointsNBT); + } NBTHelper.writeEnum(compound, "Phase", phase); - compound.put("InteractionPoints", pointsNBT); compound.put("HeldItem", heldItem.serializeNBT()); compound.putInt("TargetPointIndex", chasedPointIndex); compound.putFloat("MovementProgress", chasedPointProgress); @@ -395,6 +403,10 @@ public class ArmTileEntity extends KineticTileEntity { } } + public static int getRange() { + return AllConfigs.SERVER.logistics.mechanicalArmRange.get(); + } + private class SelectionModeValueBox extends CenteredSideValueBoxTransform { public SelectionModeValueBox() { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java index 65205b6b6..f6e4e9d6b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java @@ -93,7 +93,7 @@ public class RedstoneLinkTileEntity extends SmartTileEntity { removeBehaviour(LinkBehaviour.TYPE); createLink(); link.copyItemsFrom(prevlink); - putBehaviour(link); + attachBehaviourLate(link); } if (transmitter) diff --git a/src/main/java/com/simibubi/create/foundation/config/CLogistics.java b/src/main/java/com/simibubi/create/foundation/config/CLogistics.java index 90b7dd853..a784769cc 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CLogistics.java +++ b/src/main/java/com/simibubi/create/foundation/config/CLogistics.java @@ -2,21 +2,23 @@ package com.simibubi.create.foundation.config; public class CLogistics extends ConfigBase { - public ConfigInt extractorDelay = i(20, 10, "extractorDelay", Comments.extractorDelay); - public ConfigInt extractorInventoryScanDelay = i(40, 10, "extractorInventoryScanDelay", Comments.extractorInventoryScanDelay); - public ConfigInt extractorAmount = i(16, 1, 64, "extractorAmount", Comments.extractorAmount); + public ConfigInt defaultExtractionLimit = i(64, 1, 64, "defaultExtractionLimit", Comments.defaultExtractionLimit); + public ConfigInt defaultExtractionTimer = i(8, 1, "defaultExtractionTimer", Comments.defaultExtractionTimer); + public ConfigInt mechanicalArmRange = i(5, 1, "mechanicalArmRange", Comments.mechanicalArmRange); public ConfigInt linkRange = i(128, 1, "linkRange", Comments.linkRange); - + @Override public String getName() { return "logistics"; } private static class Comments { - static String extractorDelay = "The amount of game ticks an Extractor waits after pulling an item successfully."; - static String extractorInventoryScanDelay = "The amount of game ticks an Extractor waits before checking again if the attached inventory contains items to extract."; - static String extractorAmount = "The amount of items an extractor pulls at a time without an applied filter."; + static String defaultExtractionLimit = + "The maximum amount of items a funnel pulls at a time without an applied filter."; + static String defaultExtractionTimer = + "The amount of ticks a funnel waits between item transferrals, when it is not re-activated by redstone."; static String linkRange = "Maximum possible range in blocks of redstone link connections."; + static String mechanicalArmRange = "Maximum distance in blocks a Mechanical Arm can reach across."; } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java index c697cc6c9..af547236b 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java @@ -83,6 +83,7 @@ public class AllIcons { I_TUNNEL_FORCED_ROUND_ROBIN = next(), I_TUNNEL_PREFER_NEAREST = next(), I_TUNNEL_RANDOMIZE = next(), + I_TUNNEL_SYNCHRONIZE = next(), I_TOOL_MOVE_XZ = newRow(), I_TOOL_MOVE_Y = next(), diff --git a/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java b/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java index c6f9e4816..da3a40a23 100644 --- a/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java +++ b/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java @@ -134,7 +134,7 @@ public class ItemHelper { } public static ItemStack extract(IItemHandler inv, Predicate test, boolean simulate) { - return extract(inv, test, ExtractionCountMode.UPTO, AllConfigs.SERVER.logistics.extractorAmount.get(), + return extract(inv, test, ExtractionCountMode.UPTO, AllConfigs.SERVER.logistics.defaultExtractionLimit.get(), simulate); } @@ -207,7 +207,7 @@ public class ItemHelper { public static ItemStack extract(IItemHandler inv, Predicate test, Function amountFunction, boolean simulate) { ItemStack extracting = ItemStack.EMPTY; - int maxExtractionCount = AllConfigs.SERVER.logistics.extractorAmount.get(); + int maxExtractionCount = AllConfigs.SERVER.logistics.defaultExtractionLimit.get(); for (int slot = 0; slot < inv.getSlots(); slot++) { if (extracting.isEmpty()) { diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java b/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java index 25c74b7d7..bb1a42cdc 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java @@ -78,7 +78,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka public final void readClientUpdate(CompoundNBT tag) { read(tag, true); } - + @Override public final void read(CompoundNBT tag) { read(tag, false); @@ -99,7 +99,6 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka .forEach(tb -> tb.read(compound, clientPacket)); } - /** * Hook only these in future subclasses of STE */ @@ -126,13 +125,10 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka protected void forEachBehaviour(Consumer action) { behaviours.values() - .forEach(tb -> { - if (!tb.isPaused()) - action.accept(tb); - }); + .forEach(action); } - protected void putBehaviour(TileEntityBehaviour behaviour) { + protected void attachBehaviourLate(TileEntityBehaviour behaviour) { behaviours.put(behaviour.getType(), behaviour); behaviour.initialize(); } @@ -144,7 +140,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka } @SuppressWarnings("unchecked") - protected T getBehaviour(BehaviourType type) { + public T getBehaviour(BehaviourType type) { if (behaviours.containsKey(type)) return (T) behaviours.get(type); return null; diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java index dd89490aa..af79b9005 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java @@ -13,13 +13,11 @@ import net.minecraft.world.World; public abstract class TileEntityBehaviour { public SmartTileEntity tileEntity; - private boolean paused; private int lazyTickRate; private int lazyTickCounter; public TileEntityBehaviour(SmartTileEntity te) { tileEntity = te; - paused = false; setLazyTickRate(10); } @@ -34,13 +32,13 @@ public abstract class TileEntityBehaviour { lazyTickCounter = lazyTickRate; lazyTick(); } - + } public void read(CompoundNBT nbt, boolean clientPacket) { } - + public void write(CompoundNBT nbt, boolean clientPacket) { } @@ -55,14 +53,10 @@ public abstract class TileEntityBehaviour { public void remove() { - } - - public void destroy() { - } - public boolean isPaused() { - return paused; + public void destroy() { + } public void setLazyTickRate(int slowTickRate) { @@ -74,10 +68,6 @@ public abstract class TileEntityBehaviour { } - public void setPaused(boolean paused) { - this.paused = paused; - } - public BlockPos getPos() { return tileEntity.getPos(); } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringCountUpdatePacket.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringCountUpdatePacket.java index e5be66eaf..d6548d1e8 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringCountUpdatePacket.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringCountUpdatePacket.java @@ -2,7 +2,6 @@ package com.simibubi.create.foundation.tileEntity.behaviour.filtering; import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import net.minecraft.network.PacketBuffer; import net.minecraft.util.math.BlockPos; @@ -32,7 +31,7 @@ public class FilteringCountUpdatePacket extends TileEntityConfigurationPacket TYPE = new BehaviourType<>(); - private InterfaceProvider target; - private LazyOptional targetCapability; - private boolean simulateNext; + // Extra types available for multibehaviour + public static BehaviourType + TYPE = new BehaviourType<>(), EXTRACT = new BehaviourType<>(), INSERT = new BehaviourType<>(); + + protected InterfaceProvider target; + protected LazyOptional targetCapability; + protected boolean simulateNext; + + private BehaviourType behaviourType; + + public static InvManipulationBehaviour forExtraction(SmartTileEntity te, InterfaceProvider target) { + return new InvManipulationBehaviour(EXTRACT, te, target); + } + + public static InvManipulationBehaviour forInsertion(SmartTileEntity te, InterfaceProvider target) { + return new InvManipulationBehaviour(INSERT, te, target); + } + public InvManipulationBehaviour(SmartTileEntity te, InterfaceProvider target) { + this(TYPE, te, target); + } + + private InvManipulationBehaviour(BehaviourType type, SmartTileEntity te, + InterfaceProvider target) { super(te); + behaviourType = type; setLazyTickRate(40); this.target = target; this.targetCapability = LazyOptional.empty(); @@ -94,7 +114,7 @@ public class InvManipulationBehaviour extends TileEntityBehaviour { protected Predicate getFilterTest(Predicate customFilter) { Predicate test = customFilter; - FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE); + FilteringBehaviour filter = tileEntity.getBehaviour(FilteringBehaviour.TYPE); if (filter != null) test = customFilter.and(filter::test); return test; @@ -119,7 +139,7 @@ public class InvManipulationBehaviour extends TileEntityBehaviour { public int getAmountFromFilter() { int amount = -1; - FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE); + FilteringBehaviour filter = tileEntity.getBehaviour(FilteringBehaviour.TYPE); if (filter != null && !filter.anyAmount()) amount = filter.getAmount(); return amount; @@ -146,7 +166,7 @@ public class InvManipulationBehaviour extends TileEntityBehaviour { @Override public BehaviourType getType() { - return TYPE; + return behaviourType; } @FunctionalInterface diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/linked/LinkRenderer.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/linked/LinkRenderer.java index 64e5d6862..97ed69ce6 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/linked/LinkRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/linked/LinkRenderer.java @@ -57,12 +57,12 @@ public class LinkRenderer { } } - public static void renderOnTileEntity(SmartTileEntity tileEntityIn, float partialTicks, MatrixStack ms, + public static void renderOnTileEntity(SmartTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { - if (tileEntityIn == null || tileEntityIn.isRemoved()) + if (te == null || te.isRemoved()) return; - LinkBehaviour behaviour = TileEntityBehaviour.get(tileEntityIn, LinkBehaviour.TYPE); + LinkBehaviour behaviour = te.getBehaviour(LinkBehaviour.TYPE); if (behaviour == null) return; @@ -71,7 +71,7 @@ public class LinkRenderer { ItemStack stack = first ? behaviour.frequencyFirst.getStack() : behaviour.frequencyLast.getStack(); ms.push(); - transform.transform(tileEntityIn.getBlockState(), ms); + transform.transform(te.getBlockState(), ms); ValueBoxRenderer.renderItemIntoValueBox(stack, ms, buffer, light, overlay); ms.pop(); } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueHandler.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueHandler.java index 4e0b46635..c614f07c6 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueHandler.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueHandler.java @@ -45,8 +45,8 @@ public class ScrollValueHandler { if (scrolling instanceof BulkScrollValueBehaviour && AllKeys.ctrlDown()) { BulkScrollValueBehaviour bulkScrolling = (BulkScrollValueBehaviour) scrolling; - for (SmartTileEntity smartTileEntity : bulkScrolling.getBulk()) { - ScrollValueBehaviour other = TileEntityBehaviour.get(smartTileEntity, ScrollValueBehaviour.TYPE); + for (SmartTileEntity te : bulkScrolling.getBulk()) { + ScrollValueBehaviour other = te.getBehaviour(ScrollValueBehaviour.TYPE); if (other != null) applyTo(delta, other); } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueRenderer.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueRenderer.java index cac65c2ce..6171633ab 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueRenderer.java @@ -35,15 +35,14 @@ public class ScrollValueRenderer { ScrollValueBehaviour behaviour = TileEntityBehaviour.get(world, pos, ScrollValueBehaviour.TYPE); if (behaviour == null) return; - if (behaviour.needsWrench - && !AllItems.WRENCH.isIn(Minecraft.getInstance().player.getHeldItemMainhand())) + if (behaviour.needsWrench && !AllItems.WRENCH.isIn(Minecraft.getInstance().player.getHeldItemMainhand())) return; boolean highlight = behaviour.testHit(target.getHitVec()); if (behaviour instanceof BulkScrollValueBehaviour && AllKeys.ctrlDown()) { BulkScrollValueBehaviour bulkScrolling = (BulkScrollValueBehaviour) behaviour; for (SmartTileEntity smartTileEntity : bulkScrolling.getBulk()) { - ScrollValueBehaviour other = TileEntityBehaviour.get(smartTileEntity, ScrollValueBehaviour.TYPE); + ScrollValueBehaviour other = smartTileEntity.getBehaviour(ScrollValueBehaviour.TYPE); if (other != null) addBox(world, smartTileEntity.getPos(), face, other, highlight); } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueUpdatePacket.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueUpdatePacket.java index 88f7433d9..3e4d0d90a 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueUpdatePacket.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueUpdatePacket.java @@ -2,7 +2,6 @@ package com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue; import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import net.minecraft.network.PacketBuffer; import net.minecraft.util.math.BlockPos; @@ -32,7 +31,7 @@ public class ScrollValueUpdatePacket extends TileEntityConfigurationPacket<{ADoI2^ zR5(wSl3z>1Fcif*SJI}-bZZ%7Fnm(*)$jjx1R1i4u3eM#kDlbzE{YG^AzW_mJ-_y* z&E)anS*BTZnQDD>9VIRNzd0L+6iU>)6mu=5*e!Wd&- zmd89Vxb+tNQ#k-E!GQz}JPJyccH zG&QvJ^$bl-%&o0#-dr14K#yAqBmGj6{f(P$j{H2qY8(q(CT-S+m}H`;W8sI%lu_?el%>oV`1a4;=sf z>fzS_pz&J8owexz0N>4Az4YTv3}Rst+L&|qF!_T$WnZB2+>KYSw(Ph4FFD-`6&4ZlN(g>c>^GKW01&r42(C*{O^!py8ETSV z2rntECWto#ohXfEU;b-%GFw=<%wJmM)0M9nIc(>ge?eW9&Ko zex27zx5Y5(THCfLkP7}@G6JW-7wKQ3U)YI8gv~!>u(K=vI`5lkLE>!tkXZ6@LXK1z zHtF#P{tWHW*vYW8gD3LK(&}z&&CON+x2FiqhLYo>5h{gCyQ?HRi507!XXj7JVd0_i3VkyziL;Uh0|zq%02huG&o;2!zexKWt`V zdzTXe)(U%skkucOnmysM1_Nc=O)a;$%tAi7)W;!0=wCGPX&k3FNIcPDU1ZcFCu4AK zn(}Wx9{Cl+9W=H)Xb?Bi-b*O)!M{y#H8D32iIaFH7Ca|@nmZip&juf~xIHuiTuKB`86eC_9c z8!0XFbtj2p@OBD^O&f7bN>OrmHD`n%Dbf?;mAED4(=p) z4M7CxH3{@5&(nsF zyXWCJdZ~261*Znw(eMDwr%FA5Hgjw!M>&zc-#S@!-Z$AY!yIQp2q$ktKnX})kto5{ zsxsWyP!Q|Deyw6}Zk??5o%VArzs)5e0k#uMI0BjysAFU7&(98T4f@>!=v#QucILc; z%vSv0(=-{?apSJ7SlJ71A#D?p&F?2OxG7No!`@w^O z{P<RZ7gx?h%bz)#KJ#{m&u5{0 zxqysfYiTuC^2y7!!e=mI?aE`Ky8p=j!CALi>^jL_Cw1Josw2!If6y&NAnpyY^2%}O zk})#6Sw)q2=d=gUgG?pVxmhLbO)FJm>Z03u{b01$r+*iNPS~Fb(d&H?+tS&Jn+W%{ zegkl`qTpsF?!aH%4_s{R`ij9er@q~b-z0$%Y7_Z_!i5rIEM!BW!HnLJ^>=hCu7i@S4g<%OPTm|a7oS>5xdNYQ!_%A2n)jE(Ju<1OymBF-$eO3e^~E8(N|wNQ}^y?2<`i2e{gc4MHMG z0L^Yq_m?cHAG6kH#->ma2&hV+IAkdzZt#UcJXGT*@}Z14Fip?B{9*S6m}~EemmE>EfQ$(j5ujM zB>H-Ss20KM3~yXDbalf^OJm%H1E=Veq$=FXrhXewDuq3yE_RHM9KWC5xPjP6Z!hIw zvL1~O{}MI{vacl_l@}fYs}zN2&k&JzBJ!diX|lerdz70Z2V0w_|eR~Xm5g7W;k?xMD*O~TiNAYAZG>5(ZrZv9OUet|h!HAbUj^Vvt-P9*dP!C1B7OZi zt(K-Os?tUmUy9|yW!>;v=SGVKG-c60@I|0Zzd1-E95~dqF};M7t$90cE1#}xhpazW z*x>s2ON;|^#`M=-SUtBs|C$T%AxiSF5!j;AriuO>IR;#cjhqC6kQ+HN_ho4IC{V9M zkBeNie5DCS#r}-P?fS}}Sm|!h9xt`SKV(0Fik%&|CRWhmU9^Yxx}B<{?JAjD8U{cz z@w58Wv27V|?L-`_Y{TIqUa8yn6IOjcJ^7VC`)5~Ms!vTIY9o{LZ4xT-n9aK(ljRqV z5fWA;G8c?tbW17Z}4by7xJKiHx6Pb>$`kl@- z-IoocFBu>%ucK6ouMG#k<>a2t?IKkR#0gH)#jMu0sTLEOqT@ly2t8ld?HxyU3v_K~ z&sV=}NxW+BF10W=@XQc|w$bfKc=)|EIi_oi@+>A`E(AKqe=|g~EXU|2#%7L>CT@a9 z_|w~Om$2)rOWU3Zt9k6N-nx9A3i4@tucKmeX$!*y83M=C%avB5BK|p?KGUYO92Zhn zN|cn#QDn_m9`Z$A5q^;uh}367=_v5#QYmm!1Gnk4$~{bE&F;HDAil0AX%FP1QIu@x zncRx#_$vpUGOFE$(LKRd@qwVLs|2R*5}d&cF>L7eki!jF!c%a*KpC1iju*UcPlaX+ zg)G96+4+6pX%b`f!zIjhz4R<+A#;88>hZB(Z>&Y`AKu*AlJ^I6)G69G74Iwe9q%SA z-^8t|zrwT{C@l`^I${GUN*v25d6b4=%iekbQoh`W{uJT?=!4aDA`BH#vr;O7U2uP4 zLtS$S2~MzzxB8r9GNv7?7dsgRaewFIl-qxBz~W2Wax_8P&Axuvn<@4&+gFpcqj=f~ zrkcW|KgH^F=+ON2O8T@BA36+FtQ792knfwiM^MqXlPu_FBg_8V%E{@KhM=lOk9;pB z!46jmLeZck?C56uZT)n##K%mthJr_1l$pDK+$2&XkA^sO$+LNuSLv#XRI9uElbn;O z8Lxx&sVnSzu?pB>e9+@19QBzguZ&zYR=>66b(oOQ50A6(ygzmV80mwMAuKg?%= zrwovWe6#GGmKC5106^!XRp=#|AEWM52i9I2w--pdlQe<80S1U5YE59gotIdZ^G2N=)>QzwkW{aRg3fIAEwQb zH)P|rETv6HYGSPFm1Zr!p$@IA9w}cy9*$?7eps0eAKbnbCfqieUbcurZk!k_)5IUp zsQh*SZeqMQywbJuKdlvR^m;s=vG+O_KIacoQ(GC%Lv;PV#i#6? zexbxlw-c)MD{Vh-rA|Q=Jj#j7MK*WB4n`wyXNWvA@uxbBWp6EvB?l%N}a%mb+@bsiHY5(aZ9mNVUW%JowKl)9h_zipkIceyF}QJQvV*wa>#H_m)`B&Jq;SUT2_xah`2GK^73YUj_z zck0xA48+mKXy36MQ;P$FBrefqq^0GQJX_6L@{(ofkFE1I?CA*=g2(;XH{MWcvnOx( zXTFKEzyC50KUkjj#hEic+=ld|H!{Vwj#6l?Y>g}Fe3epm2d#o?IKYD?_l<}#^?@-< zm?_~<#;(74`rGC!P`tI>`j~sYyi-VtQr>4we~?||w3!&G!#Ot|qu7MpSB0e_GRrUP z1X~zOS9`z@4Anx&#!M$H26y1J??vA+j>0a_1<DGx#xCci@-6ewBYp*jdfL-&!ZdatF^qbPaZ9ds(+C zDQeE+kqXdBOvm@ut(1DX+AoFY6=mUDKn7s&{C>&?T63vK(_`rYt<>$Kvlqy z@npbmDZGpEPdvd?ZK{XE_iIbj4Y8i_w;r06 zrx7Oq)L7PV!@3Eguh_%g-1FRniA?&bewf&ZUa<)^8`agEQVEkR`gSG?9(l`l<}I_r z;dl>Y!%{ZP)PF)(lhPiCpGH_o1qsG?|#>*x5MY1fhvz}wTj-4SxAecKmSeh O)ywXe>VLZP%l`s+YxLOw delta 4171 zcmXw6dsNct)~2znPLpXSRHRNbrCn4qQ@o@$XEdkrLS|`7O69G*p%sb>{%odMrJzij zqG>v1X(mdFNF^65k?~3?ib#rycT6GyQAEEw=X}o}d+ojUTJL_Iz4zK{y}ds+|M=Ib zo%JA)LH)W?qWKUAWccos$IoZ6VV{Ow3-4aq3Eci;PtWVt?fR81c~wp~ZB*jJ+&2|(0*m*cat0}pm0tN*a8-htpAt<{wU zz7$~zkSzqlvR}?qPHzHcbK8!8IX)e6Ux4fQwQ;5r(_#ni@Xxt5p!Qry~{s6 zO$!-0yAvv#!92FVn1m7+)+*d=Yyx-@k&gnG2Bz+VZ$eIlw$-b~NrcZ&hz{gyLu|qO z&=!B{1=)H0Led)0&r93uLSAOKnTs|&sJ-piljOy@aG&hjFgjbRb_lGz1P zbwrBvoK4gI)eBS6A&MT7?w<%nZc+w5oY=5jKz?#f1LPE$FUs78eW)~R+e$jX|G*y< zT2U%=on+UUpK?xO#7a_od~Bm!Cb)HS9JG239Iaj7iinHJ)cKfywV}h z`ysTsu>MY`80msiMiHBhtUq?Lmfb^?%HMps<8k#vB-4FC@M8YKv7pe37UDIS{Mw~A-t2cWxcDH(A#=AF?vi?lU6j=hFo^ly< zytr>$!jGg+2RVA6Be&t1mWh*4P|p)NB@IB@zS%koN(Ya2jS)~jQ6a#mwQdwn-k@7G z*UeO!uZU16wcQ7h83dl`VhH&g9IBIp(n1KZjN;vZb#dt2+*G3P_iHnC2_ViY33xf~ z;-+?zy*&oE5HnMpEx(YTrL2GWiSIB!Vzm&<9SJ zA`8)=beo>qUn8Qi1ncZ0{{!wye1!P${B`iX*DK&c5@-><^$sgDRBOojGJ) zwK7fOtoC{z3gB#xfY4IRYF1Zx0KKNJKoiFdw2+l)9HY{wVoc>r@bu6f=30v5@Hi6_ zBZ9ieF6$d^j7TuypP*|CN>}y=&oZ z3c#{eeEFkmNtgTg$lB?<<(36}__Yrs8t`H$k|fIZXMTC`+W-{9KK6qVA7`XYOb z-W}7Cqt9!OgKE!aWBMner0P3_5M!sxJl(RAga*B8srPB)(f-^U%HjJoh;7N;Z+TH0j4PjP*tqMC|KtgwQJ+vB$pU+yfS16V%pZCkQo-k>? zdtkD=w8d2c&82$_=5wgcuoR}1bzw@PBiY*EuP<+?DMQG>7YfrU+tE}V9LQv%P7OFXHU zypKL%EIFhO!Z;OBJ}zPZ>f}xSUS<*=LS3b&-4ui$4Y}nU2zzCcF11!Cbq+eQ*_Dwg zSG<`WQPq3Qt_7om`041CXN}jk^>$>L$4~ydVE8Q9Jv%Gq9AFLFno-*N=qP5yes#y7 zF34O!?vH(#k!Hj@b#{>ziDq)s_Cfp1c(N6Hi=imt-}?!$+m#0FqA(yVf z`!;fU3PSE3)Gk7o`X9?D>*%7Js;xg{&``0iOEhSv))3ND2+e$&TMGw?b_0)D`8d)~ z2_PX+;sQ8K5oaGDO$8Ma5L2VRa9-#y4w!o1b77E{p_Fo1aSWT$Sl)HL7kWrEsDkr$ zBWN@RtLOL+N0+kNG5p1n!+$5my$yZ}+dBq1t(w}EeXyAtI6DY+567%4&w*~rJz`H_ zPLo1bjv^7mO){}@IoEA@>*)LCwK=m1eb-^2bKuRcYN;|g2Ouqlb|@pKkVD({~@ zX-`X34GSY&8^5+Rv#MxmeI_Y(MFiw#&HADrh;rDOVe5zS3 zx=|(yJQcr~hb^6r4|J;p^Z1DX9ff8LZI>&ub*TinhXehrE`Xj8tH>iuOvV z2hnb#dS!a^Gc3bgYikTGXWNe8ITO$maj5cW?I=7mO_5G1ZwE@?plyOc4AYG&NR48G z|H?n$2a$*=J|qj0MJZ#y_FSk}C_|i+f28nzg!0x6qEj92!lb7$qej)Q7%KebmqVyz zRBdbQ@v|dBY6K^D`1^8dlOI_RF*!^E?Z#E*(Z~IzGQu7Rs*Bo5UlFclz?YcTqUyQ! z-Wc})9v@IrEp5zlD%{C$f3dYm==`|1V9~*5vh($3XMj%5dD|6$lWSb_lrEX1UyUvN z&iMZRVw1Nz*2(wrNJMXJBbf7*Von&Yw6z{(U2mg;dpkQUtXD3*3k(iPM^66lR6?QU7$7aW~>Sbb9`2#6kCZpbIsSDyu3!qw~EH$mrnKb~vgsa?b&@ z@j;`-dcTR!r@=K}#}!%s+kf20;dWEzJW4L$fIj(?OM8Kfq=IK2sk~QQe2ecPO&WKi z;*5$#&@~^o0iV``x$Jdw+^wLm*x0*hC`vJ6TuatstyaJwO^c>U>ZxlL0BD1#g+@$< zRRFm>ixDXD$Nj$-%atDAwxIuayYy_se4d4>*jPKKR-C^N&wMf3a5mdM($??EKcVg5 zp13kcSeZ0t#Ybd?C{2md+C|cimsV-@M+qjdp)PLUdP=zIR6M~l(P!e_X)v|8DRjxv><87-0VQA(vgE$yC5|ZGy^Z;BLod?m z@RqBUK9wenC%!-(W3hFMKOQ-QV%=f1detZZI!ocmlcj(}+y&1Z2>ftRz%EuD{~oKd zpj<0;8j36HD(wCek`}32Gufl#Z17S}z z2d9dJgaZGS{nG571oNWGteN(!wA7)VtP3!|5}XTi9MXoEEdXfaCm`@&_s0DH0R?FUfLdBf$CI6h-6ny2@Z+(LNe zCf#Cu;03t9YA4z|IcV;W@W8SCO~{7A<&5Ox&%H~rlgzoI?zV2h`$JTGRi5f(GUc2@ zUrl=3fed-l=oPrms3kwWaT5@NU=~|m(kV+PifR$!VytPbsYLAd+;h=fj~*9%acskp z`{T9C1rmbFHeTj@5}!O*cD+x%ThSp7fgRalc|P{L0r9I3zg-ASj_@Y7I?5Mkd+TfC z+eL~Ni?SP{@fwn-{Skz`5G^oMs2r;dEBd zazOdpm~wvZ#=v3Sdcqbgp+Gb6-3_)I4Ei){g=w0@hqX)-C-dpiC`XXTJWDLXRIk!`ajdNo=`Z%wG3gb92fLqxa%Amrwek zW$V?~_0#{Q@YQBk83H=tko;;vNe-#0)gxVcGn%2SY5{>pgSo=Vfegf9i}}UIj_x)u z*BjLXr1~JAJ6oR6C4JdhTG!g57ZN+9K}!L!<@p4i zV?ujUcL%Bm0=X(qiT+n7!Q^ZFKO85g0OzHshw-|KlAV$vp@T7i4!vM2Pqc4v7SLxm o