From 6b0af48e99c2811f990362ad0033e078584f1287 Mon Sep 17 00:00:00 2001 From: DaComputerNerd Date: Fri, 10 Feb 2023 10:32:15 -0500 Subject: [PATCH 01/22] Add track merge event Can't test it due to java shenanigans, but I think this will work. It's worth noting that this will only be specific to merging as long as transferAll is. If anything else ends up using transferAll, all that needs to happen is adding an intermediate method that posts the event instead of transferAll doing it, then calls transferAll --- .../api/event/TrackGraphMergeEvent.java | 22 +++++++++++++++++++ .../content/logistics/trains/TrackGraph.java | 3 +++ 2 files changed, 25 insertions(+) create mode 100644 src/main/java/com/simibubi/create/api/event/TrackGraphMergeEvent.java diff --git a/src/main/java/com/simibubi/create/api/event/TrackGraphMergeEvent.java b/src/main/java/com/simibubi/create/api/event/TrackGraphMergeEvent.java new file mode 100644 index 000000000..af58070d2 --- /dev/null +++ b/src/main/java/com/simibubi/create/api/event/TrackGraphMergeEvent.java @@ -0,0 +1,22 @@ +package com.simibubi.create.api.event; + +import com.simibubi.create.content.logistics.trains.TrackGraph; + +import net.minecraftforge.eventbus.api.Event; + +public class TrackGraphMergeEvent extends Event{ + private TrackGraph mergedInto, mergedFrom; + + public TrackGraphMergeEvent(TrackGraph from, TrackGraph into) { + mergedInto = into; + mergedFrom = from; + } + + public TrackGraph getGraphMergedInto() { + return mergedInto; + } + + public TrackGraph getGraphMergedFrom() { + return mergedFrom; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java index 897713e94..cda0e5f2f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java @@ -19,6 +19,7 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; import com.simibubi.create.Create; +import com.simibubi.create.api.event.TrackGraphMergeEvent; import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; import com.simibubi.create.content.logistics.trains.entity.Train; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; @@ -41,6 +42,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.MinecraftForge; public class TrackGraph { @@ -247,6 +249,7 @@ public class TrackGraph { } public void transferAll(TrackGraph toOther) { + MinecraftForge.EVENT_BUS.post(new TrackGraphMergeEvent(this, toOther)); nodes.forEach((loc, node) -> { if (toOther.addNodeIfAbsent(node)) Create.RAILWAYS.sync.nodeAdded(toOther, node); From cc09f4c6343196c20765d3fa5f4a12c46f4d63ce Mon Sep 17 00:00:00 2001 From: cakeGit <65340665+cakeGit@users.noreply.github.com> Date: Tue, 28 Mar 2023 21:51:16 +0100 Subject: [PATCH 02/22] =?UTF-8?q?Fix=20=F0=9F=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fluids/actors/SpoutRenderer.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutRenderer.java index cc6443589..933ebdc1e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutRenderer.java @@ -38,14 +38,24 @@ public class SpoutRenderer extends SafeTileEntityRenderer { .getValue(partialTicks); if (!fluidStack.isEmpty() && level != 0) { + boolean top = fluidStack.getFluid() + .getAttributes() + .isLighterThanAir(); + level = Math.max(level, 0.175f); float min = 2.5f / 16f; float max = min + (11 / 16f); float yOffset = (11 / 16f) * level; + ms.pushPose(); - ms.translate(0, yOffset, 0); - FluidRenderer.renderFluidBox(fluidStack, min, min - yOffset, min, max, min, max, buffer, ms, light, - false); + if (!top) ms.translate(0, yOffset, 0); + else ms.translate(0, max - min, 0); + + FluidRenderer.renderFluidBox(fluidStack, + min, min - yOffset, min, + max, min, max, + buffer, ms, light, false); + ms.popPose(); } From 596c9839d2b7d383107555611ec6b2b411581a2f Mon Sep 17 00:00:00 2001 From: NerdsOfAFeather Date: Sun, 23 Apr 2023 17:55:01 -0400 Subject: [PATCH 03/22] Open Ended Pipes now correctly handle Builder's Tea --- .../contraptions/fluids/OpenEndedPipe.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java index bc4059b73..d200f0c75 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java @@ -25,6 +25,7 @@ import net.minecraft.tags.BlockTags; import net.minecraft.tags.FluidTags; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; @@ -39,6 +40,7 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.phys.AABB; +import net.minecraftforge.common.ForgeConfig; import net.minecraftforge.common.Tags; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidStack; @@ -54,6 +56,7 @@ public class OpenEndedPipe extends FlowSource { registerEffectHandler(new MilkEffectHandler()); registerEffectHandler(new WaterEffectHandler()); registerEffectHandler(new LavaEffectHandler()); + registerEffectHandler(new TeaEffectHandler()); } private Level world; @@ -443,4 +446,23 @@ public class OpenEndedPipe extends FlowSource { } } + public static class TeaEffectHandler implements IEffectHandler { + @Override + public boolean canApplyEffects(OpenEndedPipe pipe, FluidStack fluid) { + return fluid.getFluid().isSame(AllFluids.TEA.get()); + } + + @Override + public void applyEffects(OpenEndedPipe pipe, FluidStack fluid) { + Level world = pipe.getWorld(); + if (world.getGameTime() % 5 != 0) + return; + List entities = world + .getEntitiesOfClass(LivingEntity.class, pipe.getAOE(), LivingEntity::isAffectedByPotions); + for (LivingEntity entity : entities) { + entity.addEffect(new MobEffectInstance(MobEffects.DIG_SPEED, 21, 0, false, false, false)); + } + } + } + } From 0347038c9adf7b40d8a1b8418a5ee53a2f1ece06 Mon Sep 17 00:00:00 2001 From: Walle123 Date: Mon, 1 May 2023 11:32:29 +0200 Subject: [PATCH 04/22] brass tunnel distribution speed config added --- .../belts/tunnel/BrassTunnelTileEntity.java | 18 +++++++++--------- .../create/foundation/config/CLogistics.java | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) 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 c45ceff6b..e8b1ba8ed 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 @@ -66,7 +66,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity implements IHave ItemStack stackToDistribute; Direction stackEnteredFrom; - + float distributionProgress; int distributionDistanceLeft; int distributionDistanceRight; @@ -174,7 +174,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity implements IHave return; if (selectionMode.get() != SelectionMode.SYNCHRONIZE || syncedOutputActive) { - distributionProgress = 10; + distributionProgress = AllConfigs.SERVER.logistics.brassTunnelTimer.get(); sendData(); } return; @@ -528,7 +528,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity implements IHave continue; if (!tunnelTE.sides.contains(direction)) continue; - + BlockPos offset = tunnelTE.worldPosition.below() .relative(direction); @@ -579,11 +579,11 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity implements IHave compound.putBoolean("SyncedOutput", syncedOutputActive); compound.putBoolean("ConnectedLeft", connectedLeft); compound.putBoolean("ConnectedRight", connectedRight); - + compound.put("StackToDistribute", stackToDistribute.serializeNBT()); if (stackEnteredFrom != null) NBTHelper.writeEnum(compound, "StackEnteredFrom", stackEnteredFrom); - + compound.putFloat("DistributionProgress", distributionProgress); compound.putInt("PreviousIndex", previousOutputIndex); compound.putInt("DistanceLeft", distributionDistanceLeft); @@ -611,7 +611,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity implements IHave syncedOutputActive = compound.getBoolean("SyncedOutput"); connectedLeft = compound.getBoolean("ConnectedLeft"); connectedRight = compound.getBoolean("ConnectedRight"); - + stackToDistribute = ItemStack.of(compound.getCompound("StackToDistribute")); stackEnteredFrom = compound.contains("StackEnteredFrom") ? NBTHelper.readEnum(compound, "StackEnteredFrom", Direction.class) @@ -719,7 +719,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity implements IHave super.invalidate(); tunnelCapability.invalidate(); } - + @Override public void destroy() { super.destroy(); @@ -782,7 +782,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity implements IHave List allStacks = grabAllStacksOfGroup(true); if (allStacks.isEmpty()) return false; - + tooltip.add(componentSpacing.plainCopy() .append(Lang.translateDirect("tooltip.brass_tunnel.contains")) .withStyle(ChatFormatting.WHITE)); @@ -795,7 +795,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity implements IHave tooltip.add(componentSpacing.plainCopy() .append(Lang.translateDirect("tooltip.brass_tunnel.retrieve")) .withStyle(ChatFormatting.DARK_GRAY)); - + return true; } 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 cde5fe2d3..822f23230 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CLogistics.java +++ b/src/main/java/com/simibubi/create/foundation/config/CLogistics.java @@ -10,7 +10,7 @@ public class CLogistics extends ConfigBase { public final ConfigInt linkRange = i(256, 1, "linkRange", Comments.linkRange); public final ConfigInt displayLinkRange = i(64, 1, "displayLinkRange", Comments.displayLinkRange); public final ConfigInt vaultCapacity = i(20, 1, "vaultCapacity", Comments.vaultCapacity); - + public final ConfigInt brassTunnelTimer = i(1,10,10, "brassTunnelTimer",Comments.brassTunnelTimer); @Override public String getName() { return "logistics"; @@ -28,6 +28,7 @@ public class CLogistics extends ConfigBase { "The amount of ticks a portable storage interface waits for transfers until letting contraptions move along."; static String mechanicalArmRange = "Maximum distance in blocks a Mechanical Arm can reach across."; static String vaultCapacity = "The total amount of stacks a vault can hold per block in size."; + static String brassTunnelTimer = "The amount of ticks a brass tunnel waits between distributions"; } } From b8779299cd8ca01797ca20cdbc996ee036196691 Mon Sep 17 00:00:00 2001 From: Walle123 Date: Mon, 1 May 2023 11:57:13 +0200 Subject: [PATCH 05/22] brass tunnel distribution speed config added --- .../logistics/block/belts/tunnel/BrassTunnelTileEntity.java | 2 ++ .../java/com/simibubi/create/foundation/config/CLogistics.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) 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 e8b1ba8ed..7f889e767 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 @@ -11,6 +11,8 @@ import java.util.Set; import javax.annotation.Nullable; +import com.simibubi.create.foundation.config.AllConfigs; + import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllBlocks; 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 822f23230..b850a88a7 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CLogistics.java +++ b/src/main/java/com/simibubi/create/foundation/config/CLogistics.java @@ -10,7 +10,7 @@ public class CLogistics extends ConfigBase { public final ConfigInt linkRange = i(256, 1, "linkRange", Comments.linkRange); public final ConfigInt displayLinkRange = i(64, 1, "displayLinkRange", Comments.displayLinkRange); public final ConfigInt vaultCapacity = i(20, 1, "vaultCapacity", Comments.vaultCapacity); - public final ConfigInt brassTunnelTimer = i(1,10,10, "brassTunnelTimer",Comments.brassTunnelTimer); + public final ConfigInt brassTunnelTimer = i(10,1,10, "brassTunnelTimer",Comments.brassTunnelTimer); @Override public String getName() { return "logistics"; From e5c6ca157c4acd11ad4f4a516fc456e8a54b3511 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue, 9 May 2023 18:23:47 +0200 Subject: [PATCH 06/22] Squashed commit of the following: commit 053dd09df6c426ab5e570f42a1edb5df3d0fbd01 Merge: 6d1e1c71d ecc645eba Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue May 9 18:22:42 2023 +0200 Merge branch '1.18/api' of https://github.com/Layers-of-Railways/Create into pr/4692 commit ecc645eba7bfd5f86b9bfb16ee1236a5d6432d3d Author: Rabbitminers Date: Tue May 9 11:24:11 2023 +0100 Implemented support for creating and removing individual blockstate models commit 6d1e1c71de7ce20f6fd9fc8ed4ed9bdd1072829a Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue May 9 12:16:54 2023 +0200 Less error logging when migrating old worlds commit 205e47352ec46f8e300167db69023c7938a52b58 Author: techno-sam Date: Mon May 8 21:02:19 2023 -0700 Fix up ItemOutline commit 6cf204f6afd12671060d198d5a09efe9cd04c7b5 Merge: fe049bc77 2e3c906ce Author: techno-sam Date: Mon May 8 20:28:56 2023 -0700 Merge remote-tracking branch 'upstream/mc1.18/dev' into 1.18/api # Conflicts: # src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java commit fe049bc771cc3a4dd91f5c91f098aa7448af6c8d Author: techno-sam Date: Mon May 8 20:26:16 2023 -0700 Revert "Revert "Rewrite outline buffering"" This reverts commit 726bfaf0 commit 435b4c1c16153e30740d6878cf1f676b7a442c19 Author: techno-sam Date: Mon May 8 20:20:23 2023 -0700 Clean up last bits of upside down rendering commit 662da6bab1f6ad96a4fa05c9ff8538080ac69ac2 Merge: 122fe77af d83285e8a Author: techno-sam Date: Mon May 8 20:16:32 2023 -0700 Merge remote-tracking branch 'origin/1.18/api' into 1.18/api # Conflicts: # src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java commit 122fe77afa2df18dde7afe0bc6aee536f33b18bd Author: techno-sam Date: Mon May 8 20:15:46 2023 -0700 Fix up upside down rendering commit d83285e8a4da5fcb6900c032e6bd8cd59f81bde8 Merge: 00e953a58 cdb0ad210 Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Sun May 7 07:02:18 2023 -0700 Merge pull request #3 from Layers-of-Railways/1.18/bogey-api Cleanup cycle groups and unused imports commit cdb0ad210b7c984b9fcfbecae8a2a0ebf052eb9d Author: Rabbitminers Date: Sun May 7 10:15:47 2023 +0100 Fixed merge artifact commit 457d5f33ed05075dbd0ffc38c17d3135b494dc26 Merge: 4e4e227a3 00e953a58 Author: Rabbitminers Date: Sun May 7 10:14:07 2023 +0100 Merge remote-tracking branch 'origin/1.18/api' into 1.18/api commit 00e953a585bd8e146b6304a19cebd174404ab1c3 Merge: 1e4d5504e a7a25896c Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Sun May 7 10:13:49 2023 +0100 Merge pull request #2 from Rabbitminers/mc1.18/dev Added Return Values and Small Cleanup commit a7a25896c1a5a0a353400ed329a46a461347553e Merge: 7622128be 1e4d5504e Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Sun May 7 10:13:40 2023 +0100 Merge branch '1.18/api' into mc1.18/dev commit 4e4e227a351cb7f70aa4476bebfad1c0e963b561 Author: Rabbitminers Date: Sun May 7 10:10:30 2023 +0100 Cleanup to cycle groups commit aa94fc97d154dcdcaaaa5b4d5e8311af9470d38a Author: Rabbitminers Date: Sun May 7 09:50:50 2023 +0100 Removed unused import of Railways commit 7622128bec17931ea4029792d62c645d0f354e5f Merge: 81eeadb85 d52065808 Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Sun May 7 09:11:59 2023 +0100 Merge branch 'Layers-of-Railways:mc1.18/dev' into mc1.18/dev commit 1e4d5504ee4fe32d655e08acbeb6c492b5e8bb0b Author: techno-sam Date: Sat May 6 18:03:39 2023 -0700 Don't revert non-buggy changes commit b306cf212471f2842311af071dc6b595cbf79216 Author: techno-sam Date: Sat May 6 18:00:59 2023 -0700 Take materials into consideration when trains pathfind commit fca02ae4bfade6f839533c11785cc3e56332f463 Author: techno-sam Date: Sat May 6 10:25:51 2023 -0700 Add materials to track graph commit 726bfaf0b5226a657b45ce4bd1aa365d891a27a4 Author: techno-sam Date: Fri May 5 21:16:49 2023 -0700 Revert "Rewrite outline buffering" This reverts commit d4106d545b0381c3bec304e727a136ea105a8468. commit 171897bed25ed8f7ad3999c8527bb649bb932c81 Author: techno-sam Date: Fri May 5 20:55:25 2023 -0700 Fix up style cycling commit cbd0cf20da482851f98f5312cbc40770a6c14f16 Author: techno-sam Date: Fri May 5 07:32:06 2023 -0700 clean up nether portal carriage handling commit d556f0887632664126a2e10cbb1c8fc6d37e2582 Author: techno-sam Date: Fri May 5 07:06:02 2023 -0700 upside down bogeys work in nether portals fixed coupling anchor offsets commit da26c0ccbf26b892013f6e365556eea6952009f2 Author: techno-sam Date: Thu May 4 09:32:53 2023 -0700 working on upside down bogeys in nether portals commit 81eeadb8532599d482f2259e58cedeaa602e8628 Author: Rabbitminers Date: Mon May 1 16:15:28 2023 +0100 Small cleanup commit c7e9df973cf3d0dab15992d06e6a51985d305ba8 Author: Rabbitminers Date: Mon May 1 16:13:51 2023 +0100 Fixed issue raised in #1 commit 2f285b6eb7341879899895b1c5bbadd0137abb83 Author: techno-sam Date: Mon May 1 08:13:27 2023 -0700 add data gen commit 206de013111a879de133f62846e4f10d7228ea0a Merge: e91753a33 6564f4fa7 Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Mon May 1 06:49:21 2023 -0700 Merge pull request #1 from Rabbitminers/mc1.18/dev Bogey API commit 6564f4fa730f71920552fd2ad6f2c8255df69995 Merge: e5d759582 e91753a33 Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Mon May 1 10:40:32 2023 +0100 Merge branch '1.18/api' into mc1.18/dev commit e5d759582279b3a761c7011174ec77119f4f4f93 Author: Rabbitminers Date: Mon May 1 10:09:03 2023 +0100 Connected Custom Bogey Particle Types To CarriageParticles commit e91753a33cde6dbe0caaface45a7f377d75acbed Author: techno-sam Date: Sun Apr 30 19:51:26 2023 -0700 Fix up some problems commit 9815f1490f9d540986f85f49f297e2f014c312c4 Author: Rabbitminers Date: Sun Apr 30 21:12:43 2023 +0100 Implemented default data when shifting styles commit da30e78815afd7906ea82a9fba293f202c036fa8 Author: Rabbitminers Date: Sun Apr 30 21:12:14 2023 +0100 Added Particles To Bogey Style (And Respective Builder) commit 08c000b8ba302a1c14f7479e70445e2c6d360bc3 Author: Rabbitminers Date: Sun Apr 30 21:01:19 2023 +0100 Added Backup Rendering If A Size Is Not Present commit 2b76e8d7b3b8d88355868ea31d4b6e3df11a7169 Author: Rabbitminers Date: Sun Apr 30 21:00:40 2023 +0100 Added Common Renderer To Remove Function commit 411ec36f573a570284b2bda566d8a006550983e8 Author: Rabbitminers Date: Sun Apr 30 20:59:50 2023 +0100 Added Display Name To Standard Bogey Style commit 112306d5d49db10176d091f1f2ece893afb274dd Author: Rabbitminers Date: Sun Apr 30 20:59:30 2023 +0100 Displayed new style name when changing betweeen them commit 5634670b2750a2df5dfee6de3f93bc895391300d Author: Rabbitminers Date: Sun Apr 30 20:06:00 2023 +0100 General Cleanup commit 0f7a8b7b24ef25c4266fc88f82995b609087904e Author: Rabbitminers Date: Sun Apr 30 20:05:50 2023 +0100 Implemented Changes To Remaining Classes commit 8aedc00f963413ac0a02335bc9f914d45a82b4de Author: Rabbitminers Date: Sun Apr 30 20:02:06 2023 +0100 Removed Bogey Style Handling From Registrate commit edf8079abf9750dc9f3ccf1aedf58fef80428385 Author: Rabbitminers Date: Sun Apr 30 20:01:40 2023 +0100 Removed Unused Registry Handling commit 6a185c4e727ecf55183cb885b109c0f5c5319854 Author: Rabbitminers Date: Sun Apr 30 20:01:16 2023 +0100 Refactored Bogey Sizes commit e10d07ddc3b70cfa6f4a210aa9a9e6bcc6200b7f Author: Rabbitminers Date: Sun Apr 30 20:01:00 2023 +0100 Overhauled Bogey Style commit 74d98a2ad538e2b9d35fdfd2270a14597d29f957 Merge: e629d02f5 4ebcf8201 Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Sun Apr 23 07:16:33 2023 -0700 Merge branch 'Creators-of-Create:mc1.18/dev' into 1.18/api commit e629d02f505c7de2d786a126fe49168351f17124 Author: techno-sam Date: Sun Apr 9 07:18:22 2023 -0700 Track API Clean up code a bit commit d9ce6ce995128e64d079145b96273235c4fec783 Author: techno-sam Date: Sun Apr 9 07:14:46 2023 -0700 Track API? Fix placement commit 7fbf08ba54ce3397045a8acdd6b7be813009ee7b Author: techno-sam Date: Sat Apr 8 11:11:24 2023 -0700 Track API? Fix up some placement issues commit 35644f143426bc2cae1a63c4f09d7145a4e18983 Author: techno-sam Date: Sat Apr 8 08:11:13 2023 -0700 Track API maybe? Datagen Seems to be working commit f7c56b867a6afe52fa742f4d4c310db9788cc2ef Author: techno-sam Date: Thu Apr 6 21:24:31 2023 -0700 Track API maybe? Fix build - broken generic Not yet tested, but it is progress commit 2a59fd7e8ab91a6004abe4b92152a2a936a22c1b Author: techno-sam Date: Thu Apr 6 21:13:54 2023 -0700 Track API maybe? Not yet tested, but it is progress commit 5ba30d6a85dd2cfa49434cb55a25b258b02a9665 Merge: e4e5ac1c4 c2977bbff Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Thu Apr 6 17:10:39 2023 -0700 Merge branch 'Creators-of-Create:mc1.18/dev' into 1.18/api commit d52065808c5d250e6aec35878a5349be563c1d24 Merge: e4e5ac1c4 c2977bbff Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Thu Apr 6 17:10:26 2023 -0700 Merge branch 'Creators-of-Create:mc1.18/dev' into mc1.18/dev commit 53240bd42f08d839b233a3b75cb59aabb4648fb9 Author: Rabbitminers Date: Mon Apr 3 21:42:29 2023 +0100 Corrected Bogey InteractionResult To Pass commit 69326e361ab7d982a577f1e864c772967ad9c134 Author: Rabbitminers Date: Mon Apr 3 21:30:28 2023 +0100 Fixed Default Values When Used Styles Are Removed commit 4f176979de161c35d6c7b07744bf0b982490f49f Author: Rabbitminers Date: Mon Apr 3 19:33:17 2023 +0100 Fixed Carriage Sounds (Again) commit 1e80af3303e5bf9f9179857944cc233b4be7ebaf Author: Rabbitminers Date: Mon Apr 3 19:27:58 2023 +0100 Refactored Bogey Sizes To Seperate Class commit 129be61fee13e15e17c2e2a4ee0b08c9bc004846 Author: Rabbitminers Date: Mon Apr 3 17:20:17 2023 +0100 Fixed Bogey Sound Loading commit 2543185a55a60197494850582ca45d729e463f40 Author: Rabbitminers Date: Mon Apr 3 09:45:23 2023 +0100 Added Bogey Sound Customisation commit 1ad5ae95143f5240fcb83448a99a3924e6d96ce8 Author: Rabbitminers Date: Mon Apr 3 00:44:53 2023 +0100 Added Size Transforms If Size Is Not Available For New Style commit 96566b161441928f2b419340796a27631e1aeb91 Author: Rabbitminers Date: Sun Apr 2 23:02:02 2023 +0100 Moved Bogey Style Inside Of Bogey Data And Implemented Bogey Data Communication commit eedd98473807f1261c7d5edaf0a222c081b57e69 Author: Rabbitminers Date: Sun Apr 2 16:53:55 2023 +0100 Fixed Large Bogey Size commit 68ca0974c6867e61980990a345634963079faf10 Author: Rabbitminers Date: Sun Apr 2 16:47:58 2023 +0100 Implemented Style Cycling & Default Values commit a55ba4267a5fd01ec77e9d826a01f0157c3a1271 Author: Rabbitminers Date: Sun Apr 2 16:46:15 2023 +0100 Implemented renderer instance creator commit 43523302c22d5da374d71c69499269eb8c98dadf Author: Rabbitminers Date: Sun Apr 2 16:45:33 2023 +0100 Removed Unused Standard Bogey Instance commit 773e084422d5cba7e0c599c4e9e9199252e843a3 Merge: 0c0b5a1ed d1e1f7ec5 Author: Rabbitminers Date: Sat Apr 1 18:50:15 2023 +0100 Merge remote-tracking branch 'origin/mc1.18/dev' into mc1.18/dev # Conflicts: # src/main/java/com/simibubi/create/AllBogeyStyles.java # src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java # src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java # src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java # src/main/java/com/simibubi/create/content/logistics/trains/entity/StandardBogeyInstance.java # src/main/java/com/simibubi/create/foundation/data/BogeyStyleBuilder.java commit 0c0b5a1ed65c5f425265b340772b1177a309c46d Author: Rabbitminers Date: Sat Apr 1 18:39:58 2023 +0100 Linked Style Registry To Bogey Blocks commit 71f839ee51c4d609a19fe57632fb2e8fb0d2e5b7 Author: Rabbitminers Date: Sat Apr 1 18:39:03 2023 +0100 Replaced size boolean with direct use of size enum commit 50ff0817045029c721a0a5e38956b3ecd228e52f Author: Rabbitminers Date: Thu Mar 30 18:47:13 2023 +0100 Added Resource Location To NBT helper methods commit d1e1f7ec5abeb825a3170a8f6972ffae43d58381 Author: Rabbitminers Date: Thu Mar 30 18:47:13 2023 +0100 Re-worked BogeyStyles commit da593fccb1cb95232290289775affd097153e30d Author: Rabbitminers Date: Thu Mar 30 18:46:02 2023 +0100 Refactored IBogeyBlock to AbstractBogeyBlock and extracted relevant StandardBogeyBlock implementations commit 17432c911342b1d4937a8d2d22d50a58296639e6 Author: Rabbitminers Date: Sat Mar 25 10:20:50 2023 +0000 Fixed Incorrect Registry Loading commit c7d899369a4ad1a9962ed18c2ab02f58c985f5ae Author: Rabbitminers Date: Fri Mar 24 23:44:03 2023 +0000 Registered Registers commit 6d862290d71b24b1d841444fa21dcb44ecc0d6c7 Author: Rabbitminers Date: Fri Mar 24 23:43:23 2023 +0000 Added BogeyStyleBuilder To Registrate commit 3dfb9e3b3b4b7cec3833b65838ce9523b0cf7666 Author: Rabbitminers Date: Fri Mar 24 23:43:08 2023 +0000 Implemented AllBogeyStyles commit c9e71b462d00e138778f3064bfcc3549a6f28f22 Author: Rabbitminers Date: Fri Mar 24 23:42:56 2023 +0000 Created BogeyStyleBuilder commit a90977d6429657ade13c889d90ec8cd733f176e9 Author: Rabbitminers Date: Fri Mar 24 23:42:25 2023 +0000 Created AllRegistries and BogeyStyle Registry commit 154d455f3fbdef3000ad3e35e88b0909b66c69f8 Author: Rabbitminers Date: Fri Mar 24 23:41:56 2023 +0000 Added BogeyStyle Wrapper commit dfb7640bfc9850604c4ce05ff56338a4e2bbe2fa Author: Rabbitminers Date: Thu Mar 23 18:50:41 2023 +0000 Removed left over logging statement commit 9920536cc319897a89dc1fc974c67cd0975fbcfd Author: Rabbitminers Date: Thu Mar 23 18:50:18 2023 +0000 Implemented Secondary Shaft To Large Renderer commit 6cd40cc6f982226f2bbb9e04e3b8241f9cc36cb5 Author: Rabbitminers Date: Thu Mar 23 18:49:56 2023 +0000 Prevented Overwrite When Using Two BlockStates Of The Same Type With Different Properties commit 06fb901144de8d8df5b907e6261c76a018468f7d Author: Rabbitminers Date: Thu Mar 23 18:39:11 2023 +0000 Implemented Common Rendering For StandardBogeyRenderer commit 435b0f826663284f6544c034217516e36a0687d8 Author: Rabbitminers Date: Thu Mar 23 18:38:40 2023 +0000 Added Common Renderer commit 96a0623dab84d7062a0871ddacabf4342e568867 Author: Rabbitminers Date: Thu Mar 23 18:38:29 2023 +0000 Implemented BlockState Models For Rendering commit 469d9d592b9aa925b26b1206a4ad03d73d422a92 Author: Rabbitminers Date: Thu Mar 23 17:42:28 2023 +0000 Added Standard Bogey Instance (Might be redundant) commit 2661d260d8c21e57df751b17812d89919713120f Author: Rabbitminers Date: Thu Mar 23 17:42:06 2023 +0000 Refactored Changes To Existing Methods commit 9ded16fbabb38e3415cc7b5452cbaea1bef98f61 Author: Rabbitminers Date: Thu Mar 23 17:41:15 2023 +0000 Integrated BogeyRenderer To BogeyInstance (Also Corrected Rendering In Contraption) commit 4a82fcbca1002267fc70998e7ac9c22cd92de52e Author: Rabbitminers Date: Thu Mar 23 17:40:13 2023 +0000 Implemented Changes To StandardBogeyBlock commit 7238fb93f3d0fed43b091f44fd30814e505c544c Author: Rabbitminers Date: Thu Mar 23 17:39:51 2023 +0000 Added Renderer To IBogeyBlock commit ded4c1f613cb33ae29b6bf631eb49abd2ec037f4 Merge: 91727cc84 3c02fe6ec Author: Rabbitminers Date: Wed Mar 22 17:03:37 2023 +0000 Merge remote-tracking branch 'origin/mc1.18/dev' into mc1.18/dev commit 91727cc84a12b2fd27b1ce6e0d67bd182e34880b Author: Rabbitminers Date: Wed Mar 22 17:03:28 2023 +0000 Implemented Model Data Initializer to StandardBogeyRenderer commit 6d98a1f46942d319729c2d61451da462f4188167 Author: Rabbitminers Date: Wed Mar 22 17:03:00 2023 +0000 Added Contraption Model Instance Initializer commit 3c02fe6ecc0c20f1c8ba6bd2ffd2334c2d9d9d73 Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Tue Mar 21 22:45:34 2023 +0000 Added missing render type check commit 6672c49649026e6a6f9a71d9a0bc9411016bcfce Author: Rabbitminers Date: Tue Mar 21 22:37:36 2023 +0000 Re-created standard bogey with test api commit a8a9491fa07777218c7de3fe780ae17e05d5ac03 Author: Rabbitminers Date: Tue Mar 21 22:34:54 2023 +0000 Implemented Proof Of Concept Generic Bogey Renderer commit e4e5ac1c40cadb708429018dc17439eca87ee74e Author: SpottyTheTurtle <69260662+SpottyTheTurtle@users.noreply.github.com> Date: Sat Mar 11 21:34:59 2023 +0000 init --- .gitignore | 3 +- build.gradle | 4 + src/generated/resources/.cache/cache | 4 +- .../resources/assets/create/lang/en_us.json | 6 + .../create/tags/blocks/girdable_tracks.json | 6 + .../data/create/tags/blocks/tracks.json | 6 + .../java/com/simibubi/create/AllBlocks.java | 15 +- .../com/simibubi/create/AllBogeyStyles.java | 122 ++++++ .../java/com/simibubi/create/AllTags.java | 6 + .../com/simibubi/create/AllTileEntities.java | 13 +- src/main/java/com/simibubi/create/Create.java | 4 + .../actors/DrillMovementBehaviour.java | 4 +- .../press/MechanicalPressTileEntity.java | 4 +- .../BlockMovementChecks.java | 4 +- .../structureMovement/Contraption.java | 6 +- .../curiosities/girder/GirderBlock.java | 3 +- .../tools/BlueprintOverlayRenderer.java | 3 +- .../logistics/trains/AbstractBogeyBlock.java | 361 ++++++++++++++++++ .../logistics/trains/BezierConnection.java | 44 ++- .../logistics/trains/BogeyRenderer.java | 309 +++++++++++++++ .../content/logistics/trains/BogeySizes.java | 70 ++++ .../trains/BogeyTileEntityRenderer.java | 12 +- .../trains/GlobalRailwayManager.java | 8 +- .../content/logistics/trains/IBogeyBlock.java | 91 ----- .../content/logistics/trains/ITrackBlock.java | 29 +- .../trains/StandardBogeyRenderer.java | 137 +++++++ .../content/logistics/trains/TrackEdge.java | 12 +- .../content/logistics/trains/TrackGraph.java | 7 +- .../logistics/trains/TrackGraphSync.java | 6 +- .../trains/TrackGraphSyncPacket.java | 15 +- .../trains/TrackGraphVisualizer.java | 25 +- .../logistics/trains/TrackMaterial.java | 144 +++++++ .../trains/TrackMaterialFactory.java | 133 +++++++ .../logistics/trains/TrackNodeLocation.java | 30 +- .../logistics/trains/TrackPropagator.java | 4 +- .../trains/entity/BackupBogeyRenderer.java | 22 ++ .../trains/entity/BogeyInstance.java | 233 ++--------- .../logistics/trains/entity/BogeyStyle.java | 114 ++++++ .../logistics/trains/entity/Carriage.java | 34 +- .../trains/entity/CarriageBogey.java | 83 +++- .../trains/entity/CarriageContraption.java | 12 +- .../CarriageContraptionEntityRenderer.java | 12 +- .../entity/CarriageContraptionInstance.java | 10 +- .../entity/CarriageCouplingRenderer.java | 2 +- .../trains/entity/CarriageParticles.java | 3 +- .../trains/entity/CarriageSounds.java | 21 +- .../logistics/trains/entity/Navigation.java | 23 +- .../logistics/trains/entity/Train.java | 37 +- .../logistics/trains/entity/TrainPacket.java | 15 +- .../trains/entity/TrainRelocator.java | 11 +- .../trains/entity/TravellingPoint.java | 25 +- .../edgePoint/station/StationTileEntity.java | 89 +++-- .../trains/track/AbstractBogeyTileEntity.java | 119 ++++++ .../trains/track/CurvedTrackInteraction.java | 4 +- .../track/PlaceExtendedCurvePacket.java | 6 +- .../trains/track/StandardBogeyBlock.java | 198 +--------- .../trains/track/StandardBogeyTileEntity.java | 31 +- .../logistics/trains/track/TrackBlock.java | 54 ++- .../trains/track/TrackBlockItem.java | 5 +- .../trains/track/TrackBlockOutline.java | 6 +- .../logistics/trains/track/TrackInstance.java | 11 +- .../trains/track/TrackPlacement.java | 56 ++- .../logistics/trains/track/TrackRenderer.java | 10 +- .../trains/track/TrackTileEntity.java | 6 +- .../simibubi/create/events/CommonEvents.java | 8 +- .../foundation/command/AllCommands.java | 1 + .../foundation/command/DebugValueCommand.java | 41 ++ .../create/foundation/config/CClient.java | 2 + .../foundation/data/BuilderTransformers.java | 5 +- .../foundation/data/CreateRegistrate.java | 2 + .../ponder/content/PonderIndex.java | 16 +- .../AnimateTileEntityInstruction.java | 4 +- .../create/foundation/utility/Iterate.java | 9 + .../create/foundation/utility/NBTHelper.java | 9 + .../utility/outliner/ItemOutline.java | 51 +++ .../foundation/utility/outliner/Outliner.java | 8 + .../assets/create/lang/default/interface.json | 10 +- 77 files changed, 2357 insertions(+), 711 deletions(-) create mode 100644 src/generated/resources/data/create/tags/blocks/girdable_tracks.json create mode 100644 src/generated/resources/data/create/tags/blocks/tracks.json create mode 100644 src/main/java/com/simibubi/create/AllBogeyStyles.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/BogeyRenderer.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java delete mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/entity/BackupBogeyRenderer.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyTileEntity.java create mode 100644 src/main/java/com/simibubi/create/foundation/command/DebugValueCommand.java create mode 100644 src/main/java/com/simibubi/create/foundation/utility/outliner/ItemOutline.java diff --git a/.gitignore b/.gitignore index 4afb35865..b9a3321f8 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ local.properties # PDT-specific .buildpath -.DS_Store \ No newline at end of file +.DS_Store +/libs/ diff --git a/build.gradle b/build.gradle index d8e3a2d87..47e73e743 100644 --- a/build.gradle +++ b/build.gradle @@ -135,6 +135,9 @@ repositories { includeGroup "maven.modrinth" } } + flatDir { + dirs 'libs' + } } dependencies { @@ -169,6 +172,7 @@ dependencies { // runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.5-1.6.115") // runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252") // runtimeOnly fg.deobf("maven.modrinth:rubidium:0.5.3") + // implementation fg.deobf("com.railwayteam.railways:railways-1.18.2-1.1.1:all") { transitive = false } // https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497 // Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index d50c09db9..9ee732055 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -559,7 +559,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json f85edc574ee6de0de7693ffb031266643db6724a assets/create/lang/en_ud.json -eb624aafc91b284143c3a0cc7d9bbb8de66e8950 assets/create/lang/en_us.json +c0b485449804a49390ef01491350a2878b2b57bd assets/create/lang/en_us.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json @@ -5611,6 +5611,7 @@ ac265a674626e0e832330086fd18fe0be37fc327 data/create/recipes/weathered_copper_ti 2a2700b43614f86d3294726595cb28ed7dca4387 data/create/tags/blocks/brittle.json d99d5c67bdffff60789a19bd51a5c5267c75e0a4 data/create/tags/blocks/casing.json 2b4c93e5a752ebf54217594766f30d8d60cb4343 data/create/tags/blocks/fan_transparent.json +ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/girdable_tracks.json ee6d2b53d81f2bed492662b6c06f46c4f2b9ef9b data/create/tags/blocks/movable_empty_collider.json 6e5d3b2123fbb00e7f439c091623619502551bca data/create/tags/blocks/non_movable.json 10781e8cfcbb3486327aace3aa00e437fb44b331 data/create/tags/blocks/ore_override_stone.json @@ -5618,6 +5619,7 @@ ee6d2b53d81f2bed492662b6c06f46c4f2b9ef9b data/create/tags/blocks/movable_empty_c 23eb7cf8abff36f85320c35c69b98fdb775c8ec9 data/create/tags/blocks/safe_nbt.json 6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json d063e12c9ef75f39518c6d129ea35d833464d547 data/create/tags/blocks/toolboxes.json +ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/tracks.json 9460e92c8e483446318b849abe7e6f52dcd4a269 data/create/tags/blocks/tree_attachments.json 50936b211d94167a35ec78c89954082a336b6269 data/create/tags/blocks/valve_handles.json eac71740fb12bdb38b5dfaa2268613d7ba82b809 data/create/tags/blocks/windmill_sails.json diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 2603c07fc..dcee7c629 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1754,6 +1754,12 @@ "enchantment.create.capacity.desc": "Increases Backtank air capacity.", "enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.", + "create.bogey.style.updated_style": "Updated style", + "create.bogey.style.updated_style_and_size": "Updated style and size", + "create.bogey.style.no_other_sizes": "No other sizes", + "create.bogey.style.invalid": "Unnamed style", + "create.bogey.style.standard": "Standard", + "_": "->------------------------] Subtitles [------------------------<-", diff --git a/src/generated/resources/data/create/tags/blocks/girdable_tracks.json b/src/generated/resources/data/create/tags/blocks/girdable_tracks.json new file mode 100644 index 000000000..ef33e72ef --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/girdable_tracks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:track" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/tracks.json b/src/generated/resources/data/create/tags/blocks/tracks.json new file mode 100644 index 000000000..ef33e72ef --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/tracks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:track" + ] +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 255f0037e..ee2e4fd13 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -207,6 +207,9 @@ import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock; import com.simibubi.create.content.logistics.block.vault.ItemVaultCTBehaviour; import com.simibubi.create.content.logistics.block.vault.ItemVaultItem; import com.simibubi.create.content.logistics.item.LecternControllerBlock; +import com.simibubi.create.content.logistics.trains.BogeyRenderer; +import com.simibubi.create.content.logistics.trains.BogeySizes; +import com.simibubi.create.content.logistics.trains.TrackMaterial; import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayBlock; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem; @@ -667,7 +670,7 @@ public class AllBlocks { .onRegister(movementBehaviour(new BlazeBurnerMovementBehaviour())) .onRegister(interactionBehaviour(new BlazeBurnerInteractionBehaviour())) .item(BlazeBurnerBlockItem::withBlaze) - .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze")) + .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze")) .build() .register(); @@ -926,7 +929,7 @@ public class AllBlocks { .onRegister(assignDataBehaviour(new BoilerDisplaySource(), "boiler_status")) .addLayer(() -> RenderType::cutoutMipped) .item(FluidTankItem::new) - .model(AssetLookup.customBlockItemModel("_", "block_single_window")) + .model(AssetLookup.customBlockItemModel("_", "block_single_window")) .build() .register(); @@ -1500,7 +1503,7 @@ public class AllBlocks { .transform(customItemModel()) .register(); - public static final BlockEntry TRACK = REGISTRATE.block("track", TrackBlock::new) + public static final BlockEntry TRACK = REGISTRATE.block("track", TrackMaterial.ANDESITE::createBlock) .initialProperties(Material.STONE) .properties(p -> p.color(MaterialColor.METAL) .strength(0.8F) @@ -1510,6 +1513,8 @@ public class AllBlocks { .transform(pickaxeOnly()) .blockstate(new TrackBlockStateGenerator()::generate) .tag(AllBlockTags.RELOCATION_NOT_SUPPORTED.tag) + .tag(AllBlockTags.TRACKS.tag) + .tag(AllBlockTags.GIRDABLE_TRACKS.tag) .lang("Train Track") .item(TrackBlockItem::new) .model((c, p) -> p.generated(c, Create.asResource("item/" + c.getName()))) @@ -1578,13 +1583,13 @@ public class AllBlocks { .register(); public static final BlockEntry SMALL_BOGEY = - REGISTRATE.block("small_bogey", p -> new StandardBogeyBlock(p, false)) + REGISTRATE.block("small_bogey", p -> new StandardBogeyBlock(p, BogeySizes.SMALL)) .properties(p -> p.color(MaterialColor.PODZOL)) .transform(BuilderTransformers.bogey()) .register(); public static final BlockEntry LARGE_BOGEY = - REGISTRATE.block("large_bogey", p -> new StandardBogeyBlock(p, true)) + REGISTRATE.block("large_bogey", p -> new StandardBogeyBlock(p, BogeySizes.LARGE)) .properties(p -> p.color(MaterialColor.PODZOL)) .transform(BuilderTransformers.bogey()) .register(); diff --git a/src/main/java/com/simibubi/create/AllBogeyStyles.java b/src/main/java/com/simibubi/create/AllBogeyStyles.java new file mode 100644 index 000000000..dde09ec26 --- /dev/null +++ b/src/main/java/com/simibubi/create/AllBogeyStyles.java @@ -0,0 +1,122 @@ +package com.simibubi.create; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableMap; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; +import com.simibubi.create.content.logistics.trains.BogeyRenderer; +import com.simibubi.create.content.logistics.trains.BogeyRenderer.CommonRenderer; +import com.simibubi.create.content.logistics.trains.BogeySizes; +import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.CommonStandardBogeyRenderer; +import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.LargeStandardBogeyRenderer; +import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.SmallStandardBogeyRenderer; +import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; +import com.simibubi.create.foundation.utility.Components; +import com.simibubi.create.foundation.utility.Lang; +import com.tterrag.registrate.util.entry.BlockEntry; + +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +public class AllBogeyStyles { + public static final Map BOGEY_STYLES = new HashMap<>(); + public static final Map> CYCLE_GROUPS = new HashMap<>(); + private static final Map EMPTY_GROUP = ImmutableMap.of(); + + public static Map getCycleGroup(ResourceLocation cycleGroup) { + return CYCLE_GROUPS.getOrDefault(cycleGroup, EMPTY_GROUP); + } + + public static final String STANDARD_CYCLE_GROUP = "standard"; + + public static final BogeyStyle STANDARD = + create("standard", STANDARD_CYCLE_GROUP).commonRenderer(CommonStandardBogeyRenderer::new) + .displayName(Components.translatable("create.bogey.style.standard")) + .size(BogeySizes.SMALL, SmallStandardBogeyRenderer::new, AllBlocks.SMALL_BOGEY) + .size(BogeySizes.LARGE, LargeStandardBogeyRenderer::new, AllBlocks.LARGE_BOGEY) + .build(); + + private static BogeyStyleBuilder create(String name, String cycleGroup) { + return create(Create.asResource(name), Create.asResource(cycleGroup)); + } + + public static BogeyStyleBuilder create(ResourceLocation name, ResourceLocation cycleGroup) { + return new BogeyStyleBuilder(name, cycleGroup); + } + + public static void register() {} + + public static class BogeyStyleBuilder { + protected final Map sizes = new HashMap<>(); + protected final ResourceLocation name; + protected final ResourceLocation cycleGroup; + + protected Component displayName = Lang.translateDirect("bogey.style.invalid"); + protected ResourceLocation soundType = AllSoundEvents.TRAIN2.getId(); + protected CompoundTag defaultData = new CompoundTag(); + protected ParticleOptions contactParticle = ParticleTypes.CRIT; + protected ParticleOptions smokeParticle = ParticleTypes.POOF; + protected Optional> commonRenderer = Optional.empty(); + + public BogeyStyleBuilder(ResourceLocation name, ResourceLocation cycleGroup) { + this.name = name; + this.cycleGroup = cycleGroup; + } + + public BogeyStyleBuilder displayName(Component displayName) { + this.displayName = displayName; + return this; + } + + public BogeyStyleBuilder soundType(ResourceLocation soundType) { + this.soundType = soundType; + return this; + } + + public BogeyStyleBuilder defaultData(CompoundTag defaultData) { + this.defaultData = defaultData; + return this; + } + + public BogeyStyleBuilder size(BogeySizes.BogeySize size, Supplier renderer, + BlockEntry> blockEntry) { + this.size(size, renderer, blockEntry.getId()); + return this; + } + + public BogeyStyleBuilder size(BogeySizes.BogeySize size, Supplier renderer, + ResourceLocation location) { + this.sizes.put(size, new BogeyStyle.SizeData(location, renderer, renderer.get())); + return this; + } + + public BogeyStyleBuilder contactParticle(ParticleOptions contactParticle) { + this.contactParticle = contactParticle; + return this; + } + + public BogeyStyleBuilder smokeParticle(ParticleOptions smokeParticle) { + this.smokeParticle = smokeParticle; + return this; + } + + public BogeyStyleBuilder commonRenderer(Supplier commonRenderer) { + this.commonRenderer = Optional.of(commonRenderer); + return this; + } + + public BogeyStyle build() { + BogeyStyle entry = + new BogeyStyle(name, cycleGroup, displayName, soundType, contactParticle, smokeParticle, defaultData, sizes, commonRenderer); + BOGEY_STYLES.put(name, entry); + CYCLE_GROUPS.computeIfAbsent(cycleGroup, l -> new HashMap<>()).put(name, entry); + return entry; + } + } +} diff --git a/src/main/java/com/simibubi/create/AllTags.java b/src/main/java/com/simibubi/create/AllTags.java index 725836177..027ca062d 100644 --- a/src/main/java/com/simibubi/create/AllTags.java +++ b/src/main/java/com/simibubi/create/AllTags.java @@ -107,6 +107,8 @@ public class AllTags { SAFE_NBT, SEATS, TOOLBOXES, + TRACKS, + GIRDABLE_TRACKS, TREE_ATTACHMENTS, VALVE_HANDLES, WINDMILL_SAILS, @@ -155,6 +157,10 @@ public class AllTags { .is(tag); } + public boolean matches(ItemStack stack) { + return stack != null && stack.getItem() instanceof BlockItem blockItem && matches(blockItem.getBlock()); + } + public boolean matches(BlockState state) { return state.is(tag); } diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 6f74119bb..a6f0f7456 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -182,6 +182,7 @@ import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity; import com.simibubi.create.content.logistics.item.LecternControllerRenderer; import com.simibubi.create.content.logistics.item.LecternControllerTileEntity; import com.simibubi.create.content.logistics.trains.BogeyTileEntityRenderer; +import com.simibubi.create.content.logistics.trains.TrackMaterial; import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayRenderer; import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserverRenderer; @@ -191,7 +192,9 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.signal. import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationRenderer; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; import com.simibubi.create.content.logistics.trains.track.FakeTrackTileEntity; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; +import com.simibubi.create.content.logistics.trains.track.TrackBlock; import com.simibubi.create.content.logistics.trains.track.TrackInstance; import com.simibubi.create.content.logistics.trains.track.TrackRenderer; import com.simibubi.create.content.logistics.trains.track.TrackTileEntity; @@ -202,6 +205,8 @@ import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.tterrag.registrate.util.entry.BlockEntityEntry; +import com.tterrag.registrate.util.nullness.NonNullSupplier; + public class AllTileEntities { // Schematics @@ -656,7 +661,7 @@ public class AllTileEntities { .validBlocks(AllBlocks.ANALOG_LEVER) .renderer(() -> AnalogLeverRenderer::new) .register(); - + public static final BlockEntityEntry PLACARD = REGISTRATE .tileEntity("placard", PlacardTileEntity::new) .validBlocks(AllBlocks.PLACARD) @@ -781,9 +786,9 @@ public class AllTileEntities { .tileEntity("track", TrackTileEntity::new) .instance(() -> TrackInstance::new) .renderer(() -> TrackRenderer::new) - .validBlocks(AllBlocks.TRACK) + .validBlocks((NonNullSupplier[]) TrackMaterial.allBlocks().toArray(new NonNullSupplier[0])) .register(); - + public static final BlockEntityEntry FAKE_TRACK = REGISTRATE .tileEntity("fake_track", FakeTrackTileEntity::new) .validBlocks(AllBlocks.FAKE_TRACK) @@ -800,7 +805,7 @@ public class AllTileEntities { .renderer(() -> StationRenderer::new) .validBlocks(AllBlocks.TRACK_STATION) .register(); - + public static final BlockEntityEntry SLIDING_DOOR = REGISTRATE .tileEntity("sliding_door", SlidingDoorTileEntity::new) .renderer(() -> SlidingDoorRenderer::new) diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 420c74a30..df9200de7 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -2,6 +2,8 @@ package com.simibubi.create; import java.util.Random; +import com.simibubi.create.content.logistics.trains.BogeySizes; + import org.slf4j.Logger; import com.google.gson.Gson; @@ -121,6 +123,8 @@ public class Create { AllFeatures.register(modEventBus); AllPlacementModifiers.register(modEventBus); BuiltinRegistration.register(modEventBus); + BogeySizes.init(); + AllBogeyStyles.register(); AllConfigs.register(modLoadingContext); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java index 89ebb9582..d0a7a7cb6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java @@ -4,7 +4,7 @@ import javax.annotation.Nullable; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllTags; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; @@ -61,7 +61,7 @@ public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour { @Override public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) { return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos) - .isEmpty() && !AllBlocks.TRACK.has(state); + .isEmpty() && !AllTags.AllBlockTags.TRACKS.matches(state); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java index 0fb8b8b73..6c70c56b0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java @@ -3,8 +3,8 @@ package com.simibubi.create.content.contraptions.components.press; import java.util.List; import java.util.Optional; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.AllTags; import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCraftingRecipe; import com.simibubi.create.content.contraptions.components.press.PressingBehaviour.Mode; @@ -69,7 +69,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity implemen public void onItemPressed(ItemStack result) { award(AllAdvancements.PRESS); - if (AllBlocks.TRACK.isIn(result)) + if (AllTags.AllBlockTags.TRACKS.matches(result)) tracksCreated += result.getCount(); if (tracksCreated >= 1000) { award(AllAdvancements.TRACK_CRAFTING); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java index ce06099e4..72cc6524a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java @@ -30,7 +30,7 @@ import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock; import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlock; import com.simibubi.create.foundation.config.ContraptionMovementSetting; @@ -337,7 +337,7 @@ public class BlockMovementChecks { return direction == state.getValue(StickerBlock.FACING) && !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite()); } - if (block instanceof IBogeyBlock bogey) + if (block instanceof AbstractBogeyBlock bogey) return bogey.getStickySurfaces(world, pos, state) .contains(direction); if (block instanceof WhistleBlock) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index 1133742ea..12807830f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -63,7 +63,7 @@ import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; import com.simibubi.create.content.logistics.block.inventories.CreativeCrateTileEntity; import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock; import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; @@ -342,7 +342,7 @@ public abstract class Contraption { } // Bogeys tend to have sticky sides - if (state.getBlock()instanceof IBogeyBlock bogey) + if (state.getBlock()instanceof AbstractBogeyBlock bogey) for (Direction d : bogey.getStickySurfaces(world, pos, state)) if (!visited.contains(pos.relative(d))) frontier.add(pos.relative(d)); @@ -1006,7 +1006,7 @@ public abstract class Contraption { if (disassembled) return; disassembled = true; - + for (boolean nonBrittles : Iterate.trueAndFalse) { for (StructureBlockInfo block : blocks.values()) { if (nonBrittles == BlockMovementChecks.isBrittle(block.state)) diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java b/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java index ff20a1c6b..4e206b1d9 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java +++ b/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java @@ -8,6 +8,7 @@ import java.util.Random; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; +import com.simibubi.create.AllTags; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlock; import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; @@ -224,7 +225,7 @@ public class GirderBlock extends Block implements SimpleWaterloggedBlock, IWrenc for (Direction d2 : Iterate.directionsInAxis(axis == Axis.X ? Axis.Z : Axis.X)) { BlockState above = level.getBlockState(pos.above() .relative(d2)); - if (AllBlocks.TRACK.has(above)) { + if (AllTags.AllBlockTags.GIRDABLE_TRACKS.matches(above)) { TrackShape shape = above.getValue(TrackBlock.SHAPE); if (shape == (axis == Axis.X ? TrackShape.XO : TrackShape.ZO)) state = state.setValue(updateProperty, true); diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java index 6889a801e..a3aec3eab 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java @@ -9,7 +9,6 @@ import java.util.Optional; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintCraftingInventory; import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; @@ -106,7 +105,7 @@ public class BlueprintOverlayRenderer { int tracks = info.requiredTracks; while (tracks > 0) { - ingredients.add(Pair.of(AllBlocks.TRACK.asStack(Math.min(64, tracks)), info.hasRequiredTracks)); + ingredients.add(Pair.of(new ItemStack(info.trackMaterial.getTrackBlock().get(), Math.min(64, tracks)), info.hasRequiredTracks)); tracks -= 64; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java new file mode 100644 index 000000000..3f86c660c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java @@ -0,0 +1,361 @@ +package com.simibubi.create.content.logistics.trains; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.annotation.Nullable; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; +import com.simibubi.create.content.logistics.trains.entity.Carriage; +import com.simibubi.create.content.logistics.trains.entity.CarriageBogey; +import com.simibubi.create.content.logistics.trains.entity.TravellingPoint; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; +import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.ItemRequirement; +import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.RegisteredObjects; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.registries.ForgeRegistries; + +import org.jetbrains.annotations.NotNull; + +public abstract class AbstractBogeyBlock extends Block implements ITE, ProperWaterloggedBlock, ISpecialBlockItemRequirement, IWrenchable { + public static final EnumProperty AXIS = BlockStateProperties.HORIZONTAL_AXIS; + static final List BOGEYS = new ArrayList<>(); + public BogeySizes.BogeySize size; + + + public AbstractBogeyBlock(Properties pProperties, BogeySizes.BogeySize size) { + super(pProperties); + registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); + this.size = size; + } + + public boolean isOnIncompatibleTrack(Carriage carriage, boolean leading) { + TravellingPoint point = leading ? carriage.getLeadingPoint() : carriage.getTrailingPoint(); + CarriageBogey bogey = leading ? carriage.leadingBogey() : carriage.trailingBogey(); + return point.edge.getTrackMaterial().trackType != getTrackType(bogey.getStyle()); + } + + public Set getValidPathfindingTypes(BogeyStyle style) { + return ImmutableSet.of(getTrackType(style)); + } + + public abstract TrackMaterial.TrackType getTrackType(BogeyStyle style); + + /** + * Only for internal Create use. If you have your own style set, do not call this method + */ + @Deprecated + public static void registerStandardBogey(ResourceLocation block) { + BOGEYS.add(block); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(AXIS, WATERLOGGED); + super.createBlockStateDefinition(builder); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, + LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + updateWater(pLevel, pState, pCurrentPos); + return pState; + } + + @Override + public FluidState getFluidState(BlockState pState) { + return fluidState(pState); + } + + static final EnumSet STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST); + static final EnumSet STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH); + + public EnumSet getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state) { + return state.getValue(BlockStateProperties.HORIZONTAL_AXIS) == Direction.Axis.X ? STICKY_X : STICKY_Z; + } + + public abstract double getWheelPointSpacing(); + + public abstract double getWheelRadius(); + + public Vec3 getConnectorAnchorOffset(boolean upsideDown) { + return getConnectorAnchorOffset(); + } + + /** + * This should be implemented, but not called directly + */ + protected abstract Vec3 getConnectorAnchorOffset(); + + public boolean allowsSingleBogeyCarriage() { + return true; + } + + public abstract BogeyStyle getDefaultStyle(); + + /** + * Legacy system doesn't capture bogey tile entities when constructing a train + */ + public boolean captureTileEntityForTrain() { + return false; + } + + @OnlyIn(Dist.CLIENT) + public void render(@Nullable BlockState state, float wheelAngle, PoseStack ms, float partialTicks, + MultiBufferSource buffers, int light, int overlay, BogeyStyle style, CompoundTag bogeyData) { + if (style == null) + style = getDefaultStyle(); + + final Optional commonRenderer + = style.getInWorldCommonRenderInstance(); + final BogeyRenderer renderer = style.getInWorldRenderInstance(this.getSize()); + if (state != null) { + ms.translate(.5f, .5f, .5f); + if (state.getValue(AXIS) == Direction.Axis.X) + ms.mulPose(Vector3f.YP.rotationDegrees(90)); + } + ms.translate(0, -1.5 - 1 / 128f, 0); + VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped()); + if (bogeyData == null) + bogeyData = new CompoundTag(); + renderer.render(bogeyData, wheelAngle, ms, light, vb, state == null); + CompoundTag finalBogeyData = bogeyData; + commonRenderer.ifPresent(common -> + common.render(finalBogeyData, wheelAngle, ms, light, vb, state == null)); + } + + public BogeySizes.BogeySize getSize() { + return this.size; + } + + public Direction getBogeyUpDirection() { + return Direction.UP; + } + + public boolean isTrackAxisAlongFirstCoordinate(BlockState state) { + return state.getValue(AXIS) == Direction.Axis.X; + } + + @Nullable + public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst) { + if (upDirection != Direction.UP) + return null; + return defaultBlockState().setValue(AXIS, axisAlongFirst ? Direction.Axis.X : Direction.Axis.Z); + } + + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult hit) { + if (level.isClientSide) + return InteractionResult.PASS; + ItemStack stack = player.getItemInHand(hand); + + if (!player.isShiftKeyDown() && stack.is(AllItems.WRENCH.get()) && !player.getCooldowns().isOnCooldown(stack.getItem()) + && AllBogeyStyles.BOGEY_STYLES.size() > 1) { + + BlockEntity be = level.getBlockEntity(pos); + + if (!(be instanceof AbstractBogeyTileEntity sbte)) + return InteractionResult.FAIL; + + player.getCooldowns().addCooldown(stack.getItem(), 20); + BogeyStyle currentStyle = sbte.getStyle(); + + BogeySizes.BogeySize size = getSize(); + + BogeyStyle style = this.getNextStyle(currentStyle); + if (style == currentStyle) + return InteractionResult.PASS; + + Set validSizes = style.validSizes(); + + for (int i = 0; i < BogeySizes.count(); i++) { + if (validSizes.contains(size)) break; + size = size.increment(); + } + + sbte.setBogeyStyle(style); + + CompoundTag defaultData = style.defaultData; + sbte.setBogeyData(sbte.getBogeyData().merge(defaultData)); + + if (size == getSize()) { + player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style") + .append(": ").append(style.displayName), true); + } else { + CompoundTag oldData = sbte.getBogeyData(); + level.setBlock(pos, this.getStateOfSize(sbte, size), 3); + BlockEntity newBlockEntity = level.getBlockEntity(pos); + if (!(newBlockEntity instanceof AbstractBogeyTileEntity newTileEntity)) + return InteractionResult.FAIL; + newTileEntity.setBogeyData(oldData); + player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style_and_size") + .append(": ").append(style.displayName), true); + } + + return InteractionResult.CONSUME; + } + + return InteractionResult.PASS; + } + + /** + * If, instead of using the style-based cycling system you prefer to use separate blocks, return them from this method + */ + protected List getBogeyBlockCycle() { + return BOGEYS; + } + + + @Override + public BlockState getRotatedBlockState(BlockState state, Direction targetedFace) { + Block block = state.getBlock(); + List bogeyCycle = getBogeyBlockCycle(); + int indexOf = bogeyCycle.indexOf(RegisteredObjects.getKeyOrThrow(block)); + if (indexOf == -1) + return state; + int index = (indexOf + 1) % bogeyCycle.size(); + Direction bogeyUpDirection = getBogeyUpDirection(); + boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state); + + while (index != indexOf) { + ResourceLocation id = bogeyCycle.get(index); + Block newBlock = ForgeRegistries.BLOCKS.getValue(id); + if (newBlock instanceof AbstractBogeyBlock bogey) { + BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate); + if (matchingBogey != null) + return copyProperties(state, matchingBogey); + } + index = (index + 1) % bogeyCycle.size(); + } + + return state; + } + + public BlockState getNextSize(Level level, BlockPos pos) { + BlockEntity te = level.getBlockEntity(pos); + if (te instanceof AbstractBogeyTileEntity sbte) + return this.getNextSize(sbte); + return level.getBlockState(pos); + } + + /** + * List of BlockState Properties to copy between sizes + */ + public List> propertiesToCopy() { + return ImmutableList.of(WATERLOGGED, AXIS); + } + + // generic method needed to satisfy Property and BlockState's generic requirements + private > BlockState copyProperty(BlockState source, BlockState target, Property property) { + if (source.hasProperty(property) && target.hasProperty(property)) { + return target.setValue(property, source.getValue(property)); + } + return target; + } + + private BlockState copyProperties(BlockState source, BlockState target) { + for (Property property : propertiesToCopy()) + target = copyProperty(source, target, property); + return target; + } + + public BlockState getNextSize(AbstractBogeyTileEntity sbte) { + BogeySizes.BogeySize size = this.getSize(); + BogeyStyle style = sbte.getStyle(); + BlockState nextBlock = style.getNextBlock(size).defaultBlockState(); + nextBlock = copyProperties(sbte.getBlockState(), nextBlock); + return nextBlock; + } + + public BlockState getStateOfSize(AbstractBogeyTileEntity sbte, BogeySizes.BogeySize size) { + BogeyStyle style = sbte.getStyle(); + BlockState state = style.getBlockOfSize(size).defaultBlockState(); + return copyProperties(sbte.getBlockState(), state); + } + + public BogeyStyle getNextStyle(Level level, BlockPos pos) { + BlockEntity te = level.getBlockEntity(pos); + if (te instanceof AbstractBogeyTileEntity sbte) + return this.getNextStyle(sbte.getStyle()); + return getDefaultStyle(); + } + + public BogeyStyle getNextStyle(BogeyStyle style) { + Collection allStyles = style.getCycleGroup().values(); + if (allStyles.size() <= 1) + return style; + List list = new ArrayList<>(allStyles); + return Iterate.cycleValue(list, style); + } + + + @Override + public @NotNull BlockState rotate(@NotNull BlockState pState, Rotation pRotation) { + return switch (pRotation) { + case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> pState.cycle(AXIS); + default -> pState; + }; + } + + @Override + public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { + return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack()); + } + + public boolean canBeUpsideDown() { + return false; + } + + public boolean isUpsideDown(BlockState state) { + return false; + } + + public BlockState getVersion(BlockState base, boolean upsideDown) { + return base; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java b/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java index 5c543536d..a65cdb8f6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java @@ -24,6 +24,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; @@ -39,6 +40,7 @@ public class BezierConnection implements Iterable { public Couple normals; public boolean primary; public boolean hasGirder; + protected TrackMaterial trackMaterial; // runtime @@ -55,19 +57,37 @@ public class BezierConnection implements Iterable { private AABB bounds; public BezierConnection(Couple positions, Couple starts, Couple axes, Couple normals, - boolean primary, boolean girder) { + boolean primary, boolean girder, TrackMaterial material) { tePositions = positions; this.starts = starts; this.axes = axes; this.normals = normals; this.primary = primary; this.hasGirder = girder; + this.trackMaterial = material; resolved = false; } public BezierConnection secondary() { return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), !primary, - hasGirder); + hasGirder, trackMaterial); + } + + private static boolean coupleEquals(Couple a, Couple b) { + return (a.getFirst().equals(b.getFirst()) && a.getSecond().equals(b.getSecond())) + || (a.getFirst() instanceof Vec3 aFirst && a.getSecond() instanceof Vec3 aSecond + && b.getFirst() instanceof Vec3 bFirst && b.getSecond() instanceof Vec3 bSecond + && aFirst.closerThan(bFirst, 1e-6) && aSecond.closerThan(bSecond, 1e-6)); + } + + public boolean equalsSansMaterial(BezierConnection other) { + return equalsSansMaterialInner(other) || equalsSansMaterialInner(other.secondary()); + } + + private boolean equalsSansMaterialInner(BezierConnection other) { + return this == other || (other != null && coupleEquals(this.tePositions, other.tePositions) && coupleEquals(this.starts, other.starts) + && coupleEquals(this.axes, other.axes) && coupleEquals(this.normals, other.normals) + && this.hasGirder == other.hasGirder); } public BezierConnection(CompoundTag compound, BlockPos localTo) { @@ -77,7 +97,7 @@ public class BezierConnection implements Iterable { .map(v -> v.add(Vec3.atLowerCornerOf(localTo))), Couple.deserializeEach(compound.getList("Axes", Tag.TAG_COMPOUND), VecHelper::readNBTCompound), Couple.deserializeEach(compound.getList("Normals", Tag.TAG_COMPOUND), VecHelper::readNBTCompound), - compound.getBoolean("Primary"), compound.getBoolean("Girder")); + compound.getBoolean("Primary"), compound.getBoolean("Girder"), TrackMaterial.deserialize(compound.getString("Material"))); } public CompoundTag write(BlockPos localTo) { @@ -91,13 +111,14 @@ public class BezierConnection implements Iterable { compound.put("Starts", starts.serializeEach(VecHelper::writeNBTCompound)); compound.put("Axes", axes.serializeEach(VecHelper::writeNBTCompound)); compound.put("Normals", normals.serializeEach(VecHelper::writeNBTCompound)); + compound.putString("Material", getMaterial().id.toString()); return compound; } public BezierConnection(FriendlyByteBuf buffer) { this(Couple.create(buffer::readBlockPos), Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)), - buffer.readBoolean(), buffer.readBoolean()); + buffer.readBoolean(), buffer.readBoolean(), TrackMaterial.deserialize(buffer.readUtf())); } public void write(FriendlyByteBuf buffer) { @@ -107,6 +128,7 @@ public class BezierConnection implements Iterable { normals.forEach(v -> VecHelper.write(v, buffer)); buffer.writeBoolean(primary); buffer.writeBoolean(hasGirder); + buffer.writeUtf(getMaterial().id.toString()); } public BlockPos getKey() { @@ -300,7 +322,7 @@ public class BezierConnection implements Iterable { Inventory inv = player.getInventory(); int tracks = getTrackItemCost(); while (tracks > 0) { - inv.placeItemBackInInventory(AllBlocks.TRACK.asStack(Math.min(64, tracks))); + inv.placeItemBackInInventory(new ItemStack(getMaterial().getTrackBlock().get(), Math.min(64, tracks))); tracks -= 64; } int girders = getGirderItemCost(); @@ -328,7 +350,7 @@ public class BezierConnection implements Iterable { continue; Vec3 v = VecHelper.offsetRandomly(segment.position, level.random, .125f) .add(origin); - ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, AllBlocks.TRACK.asStack()); + ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, new ItemStack(getMaterial().getTrackBlock().get())); entity.setDefaultPickUpDelay(); level.addFreshEntity(entity); if (!hasGirder) @@ -342,7 +364,7 @@ public class BezierConnection implements Iterable { } public void spawnDestroyParticles(Level level) { - BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.TRACK.getDefaultState()); + BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, getMaterial().getTrackBlock().get().defaultBlockState()); BlockParticleOption girderData = new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.METAL_GIRDER.getDefaultState()); if (!(level instanceof ServerLevel slevel)) @@ -360,6 +382,14 @@ public class BezierConnection implements Iterable { } } + public TrackMaterial getMaterial() { + return trackMaterial; + } + + public void setMaterial(TrackMaterial material) { + trackMaterial = material; + } + public static class Segment { public int index; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BogeyRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/BogeyRenderer.java new file mode 100644 index 000000000..02ea4f185 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BogeyRenderer.java @@ -0,0 +1,309 @@ +package com.simibubi.create.content.logistics.trains; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.jozufozu.flywheel.util.transform.Transform; +import com.mojang.blaze3d.vertex.PoseStack; + +import com.mojang.blaze3d.vertex.VertexConsumer; + +import com.simibubi.create.foundation.render.CachedBufferer; +import com.simibubi.create.foundation.render.SuperByteBuffer; + +import net.minecraft.nbt.CompoundTag; + +import net.minecraft.world.level.block.Blocks; + +import net.minecraft.world.level.block.state.BlockState; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public abstract class BogeyRenderer { + Map contraptionModelData = new HashMap<>(); + + /** + * A common interface for getting transform data for both in-world and in-contraption model data safely from a + * partial model + * + * @param model The key for the model data to instantiate or retrieve + * @param ms The posestack used for contraption model data + * @param inInstancedContraption The type of model needed + * @param size The amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + public Transform[] getTransformsFromPartial(PartialModel model, PoseStack ms, boolean inInstancedContraption, int size) { + return (inInstancedContraption) ? transformContraptionModelData(keyFromModel(model), ms) : createModelData(model, size); + } + + /** + * A common interface for getting transform data for both in-world and in-contraption model data safely from a + * blockstate + * + * @param state The key for the model data to instantiate or retrieve + * @param ms The posestack used for contraption model data + * @param inContraption The type of model needed + * @param size The amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + public Transform[] getTransformsFromBlockState(BlockState state, PoseStack ms, boolean inContraption, int size) { + return inContraption ? transformContraptionModelData(keyFromModel(state), ms) : createModelData(state, size); + } + + /** + * Used for calling both in-world and in-contraption rendering + * + * @param bogeyData Custom data stored on the bogey able to be used for rendering + * @param wheelAngle The angle of the wheel + * @param ms The posestack to render to + * @param light (Optional) Light used for in-world rendering + * @param vb (Optional) Vertex Consumer used for in-world rendering + */ + @OnlyIn(Dist.CLIENT) + public abstract void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption); + + /** + * Used for calling in-contraption rendering ensuring that falsey data is handled correctly + * + * @param bogeyData Custom data stored on the bogey able to be used for rendering + * @param wheelAngle The angle of the wheel + * @param ms The posestack to render to + */ + @OnlyIn(Dist.CLIENT) + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms) { + this.render(bogeyData, wheelAngle, ms, 0, null, true); + } + + public abstract BogeySizes.BogeySize getSize(); + + /** + * Used to collect Contraption Model Data for in-contraption rendering, should not be utilised directly when + * rendering to prevent render type mismatch + * + * @param key The key used to access the model + * @param ms Posestack of the contraption to bind the model data to + * @return A generic transform which can be used for both in-world and in-contraption models + */ + private Transform[] transformContraptionModelData(String key, PoseStack ms) { + ModelData[] modelData = contraptionModelData.get(key); + Arrays.stream(modelData).forEach(modelDataElement -> modelDataElement.setTransform(ms)); + return modelData; + } + + + /** + * Used for in world rendering, creates a set count of model data to be rendered, allowing for a generic response + * when rendering multiple models both in-world and in-contraption for example, with wheels + * + * @param model The partial model of the model data ot be made + * @param size The Amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + private Transform[] createModelData(PartialModel model, int size) { + BlockState air = Blocks.AIR.defaultBlockState(); + SuperByteBuffer[] data = { CachedBufferer.partial(model, air) }; + return expandArrayToLength(data, size); + } + + /** + * Used for in world rendering, creates a set count of model data to be rendered, allowing for a generic response + * when rendering multiple models both in-world and in-contraption for example, with wheels + * + * @param state The state of the model data to be made + * @param size Amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + private Transform[] createModelData(BlockState state, int size) { + SuperByteBuffer[] data = { CachedBufferer.block(state) }; + return expandArrayToLength(data, size); + } + + /** + * Utility function to clone in-world models to a set size to allow for common handling of rendering with multiple + * instances of the same model for example with wheels + * + * @param data An in-world model to be replicated + * @param size Amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + private Transform[] expandArrayToLength(SuperByteBuffer[] data, int size) { + return Arrays.stream(Collections.nCopies(size, data).toArray()) + .flatMap(inner -> Arrays.stream((SuperByteBuffer[]) inner)) + .toArray(SuperByteBuffer[]::new); + } + + /** + * Helper function to collect or create a single model from a partial model used for both in-world and + * in-contraption rendering + * + * @param model The key of the model to be collected or instantiated + * @param ms Posestack to bind the model to if it is within a contraption + * @param inInstancedContraption Type of rendering required + * @return A generic transform which can be used for both in-world and in-contraption models + */ + public Transform getTransformFromPartial(PartialModel model, PoseStack ms, boolean inInstancedContraption) { + BlockState air = Blocks.AIR.defaultBlockState(); + return inInstancedContraption ? contraptionModelData.get(keyFromModel(model))[0].setTransform(ms) + : CachedBufferer.partial(model, air); + } + + /** + * A common interface for getting transform data for blockstates, for a single model + * + * @param state The state of the model to be collected or instantiated + * @param ms Posestack to bind the model to if it is within a contraption + * @param inContraption Type of model required + * @return A generic transform which can be used for both in-world and in-contraption models + */ + public Transform getTransformFromBlockState(BlockState state, PoseStack ms, boolean inContraption) { + return (inContraption) ? contraptionModelData.get(keyFromModel(state))[0].setTransform(ms) + : CachedBufferer.block(state); + } + + /** + * Provides render implementations a point in setup to instantiate all model data to be needed + * + * @param materialManager The material manager + */ + @OnlyIn(Dist.CLIENT) + public abstract void initialiseContraptionModelData(MaterialManager materialManager); + + /** + * Creates instances of models for in-world rendering to a set length from a provided partial model + * + * @param materialManager The material manager + * @param model Partial model to be instanced + * @param count Amount of models neeeded + */ + public void createModelInstances(MaterialManager materialManager, PartialModel model, int count) { + ModelData[] modelData = new ModelData[count]; + materialManager.defaultSolid().material(Materials.TRANSFORMED) + .getModel(model).createInstances(modelData); + contraptionModelData.put(keyFromModel(model), modelData); + } + + /** + * Creates instances of models for in-contraption rendering to a set length from a provided blockstate + * + * @param materialManager The material manager + * @param state Blockstate of the model to be created + * @param count Amount of models needed + */ + public void createModelInstances(MaterialManager materialManager, BlockState state, int count) { + ModelData[] modelData = new ModelData[count]; + materialManager.defaultSolid().material(Materials.TRANSFORMED) + .getModel(state).createInstances(modelData); + contraptionModelData.put(keyFromModel(state), modelData); + } + + /** + * Creates a single instance of models for in-contraption rendering from a provided blockstate + * + * @param materialManager The material manager + * @param state Blockstate of the model to be created + */ + public void createModelInstance(MaterialManager materialManager, BlockState state) { + this.createModelInstances(materialManager, state, 1); + } + + /** + * Helper function to create a single model instance for in-contraption rendering + * + * @param materialManager The material manager + * @param models The type of model to create instances of + */ + public void createModelInstances(MaterialManager materialManager, PartialModel... models) { + for (PartialModel model : models) + createModelInstances(materialManager, model, 1); + } + + /** + * Handles scale for all model data and renders non contraption model data + * + * @param b The model data itself + * @param ms Pose stack to render to + * @param light light level of the scene + * @param vb Vertex Consumber to render to + * @param Generic alias for both contraption and in-world model data + */ + + public static > void finalize(B b, PoseStack ms, int light, @Nullable VertexConsumer vb) { + b.scale(1 - 1/512f); + if (b instanceof SuperByteBuffer byteBuf && vb != null) + byteBuf.light(light).renderInto(ms, vb); + } + + /** + * Automatic handling for setting empty transforms for all model data + * + */ + + public void emptyTransforms() { + for (ModelData[] data : contraptionModelData.values()) + for (ModelData model : data) + model.setEmptyTransform(); + } + + /** + * Automatic handling for updating all model data's light + * + * @param blockLight the blocklight to be applied + * @param skyLight the skylight to be applied + */ + + public void updateLight(int blockLight, int skyLight) { + for (ModelData[] data : contraptionModelData.values()) + for (ModelData model : data) + model.setBlockLight(blockLight).setSkyLight(skyLight); + } + + /** + * Automatic handling for clearing all model data of a contraption + * + */ + + public void remove() { + for (ModelData[] data : contraptionModelData.values()) + for (ModelData model : data) + model.delete(); + contraptionModelData.clear(); + } + + /** + * Create a model key from a partial model, so it can be easily accessed + * + * @param partialModel the model we want a unique key for + * @return Key of the model + */ + + private String keyFromModel(PartialModel partialModel) { + return partialModel.getLocation().toString(); + } + + /** + * Create a model key from a blockstate, so it can be easily accessed + * + * @param state Blockstate of the model + * @return Key of the model + */ + + private String keyFromModel(BlockState state) { + return state.toString(); + } + + public static abstract class CommonRenderer extends BogeyRenderer { + @Override + public BogeySizes.BogeySize getSize() { + return null; + } + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java b/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java new file mode 100644 index 000000000..95bf3a5c8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java @@ -0,0 +1,70 @@ +package com.simibubi.create.content.logistics.trains; + +import com.simibubi.create.Create; + +import net.minecraft.resources.ResourceLocation; + +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; + +public class BogeySizes { + private static final Collection BOGEY_SIZES = new HashSet<>(); + public static final BogeySize SMALL = new BogeySize(Create.ID, "small", 6.5f / 16f); + public static final BogeySize LARGE = new BogeySize(Create.ID, "large", 12.5f / 16f); + + static { + BOGEY_SIZES.add(SMALL); + BOGEY_SIZES.add(LARGE); + } + + public static BogeySize addSize(String modId, String name, float size) { + ResourceLocation location = new ResourceLocation(modId, name); + return addSize(location, size); + } + + public static BogeySize addSize(ResourceLocation location, float size) { + BogeySize customSize = new BogeySize(location, size); + BOGEY_SIZES.add(customSize); + return customSize; + } + + public static List getAllSizesSmallToLarge() { + return BOGEY_SIZES.stream() + .sorted(Comparator.comparing(BogeySize::wheelRadius)) + .collect(Collectors.toList()); + } + + public static List getAllSizesLargeToSmall() { + List sizes = getAllSizesSmallToLarge(); + Collections.reverse(sizes); + return sizes; + } + + public static int count() { + return BOGEY_SIZES.size(); + } + + public record BogeySize(ResourceLocation location, Float wheelRadius) { + public BogeySize(String modId, String name, float wheelRadius) { + this(new ResourceLocation(modId, name), wheelRadius); + } + + public BogeySize increment() { + List values = getAllSizesSmallToLarge(); + int ordinal = values.indexOf(this); + return values.get((ordinal + 1) % values.size()); + } + + public boolean is(BogeySize size) { + return size.location == this.location; + } + } + + public static void init() { + + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java index 94a08b145..fb96b989b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java @@ -1,7 +1,7 @@ package com.simibubi.create.content.logistics.trains; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import net.minecraft.client.renderer.MultiBufferSource; @@ -17,11 +17,11 @@ public class BogeyTileEntityRenderer extends SafeTileEnti protected void renderSafe(T te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { BlockState blockState = te.getBlockState(); - float angle = 0; - if (te instanceof StandardBogeyTileEntity sbte) - angle = sbte.getVirtualAngle(partialTicks); - if (blockState.getBlock()instanceof IBogeyBlock bogey) - bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay); + if (te instanceof AbstractBogeyTileEntity sbte) { + float angle = sbte.getVirtualAngle(partialTicks); + if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) + bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay, sbte.getStyle(), sbte.getBogeyData()); + } } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java index 990e876cb..4dda3fb56 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java @@ -265,13 +265,17 @@ public class GlobalRailwayManager { public void clientTick() { if (isTrackGraphDebugActive()) for (TrackGraph trackGraph : trackNetworks.values()) - TrackGraphVisualizer.debugViewGraph(trackGraph); + TrackGraphVisualizer.debugViewGraph(trackGraph, isTrackGraphDebugExtended()); } - + private static boolean isTrackGraphDebugActive() { return KineticDebugger.isF3DebugModeActive() && AllConfigs.CLIENT.showTrackGraphOnF3.get(); } + private static boolean isTrackGraphDebugExtended() { + return AllConfigs.CLIENT.showExtendedTrackGraphOnF3.get(); + } + public GlobalRailwayManager sided(LevelAccessor level) { if (level != null && !level.isClientSide()) return this; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java deleted file mode 100644 index dea2966aa..000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; - -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.logistics.trains.entity.BogeyInstance; -import com.simibubi.create.content.logistics.trains.entity.CarriageBogey; -import com.simibubi.create.foundation.utility.RegisteredObjects; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.registries.ForgeRegistries; - -public interface IBogeyBlock extends IWrenchable { - - static final List BOGEYS = new ArrayList<>(); - - public static void register(ResourceLocation block) { - BOGEYS.add(block); - } - - public EnumSet getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state); - - public double getWheelPointSpacing(); - - public double getWheelRadius(); - - public boolean allowsSingleBogeyCarriage(); - - public Vec3 getConnectorAnchorOffset(); - - @OnlyIn(Dist.CLIENT) - public void render(@Nullable BlockState state, float wheelAngle, PoseStack ms, float partialTicks, - MultiBufferSource buffers, int light, int overlay); - - @OnlyIn(Dist.CLIENT) - public BogeyInstance createInstance(MaterialManager materialManager, CarriageBogey bogey); - - public default Direction getBogeyUpDirection() { - return Direction.UP; - } - - public boolean isTrackAxisAlongFirstCoordinate(BlockState state); - - @Nullable - public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst); - - @Override - default BlockState getRotatedBlockState(BlockState state, Direction targetedFace) { - Block block = state.getBlock(); - int indexOf = BOGEYS.indexOf(RegisteredObjects.getKeyOrThrow(block)); - if (indexOf == -1) - return state; - - int index = (indexOf + 1) % BOGEYS.size(); - Direction bogeyUpDirection = getBogeyUpDirection(); - boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state); - - while (index != indexOf) { - ResourceLocation id = BOGEYS.get(index); - Block newBlock = ForgeRegistries.BLOCKS.getValue(id); - if (newBlock instanceof IBogeyBlock bogey) { - BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate); - if (matchingBogey != null) - return matchingBogey.hasProperty(WATERLOGGED) - ? matchingBogey.setValue(WATERLOGGED, state.getValue(WATERLOGGED)) - : matchingBogey; - } - index = (index + 1) % BOGEYS.size(); - } - - return state; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java index 33946c2a5..f0ef234d9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java @@ -25,6 +25,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; @@ -74,22 +75,42 @@ public interface ITrackBlock { getTrackAxes(world, pos, state).forEach(axis -> { addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d) .add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, - axis, null); + axis, null, (b, v) -> getMaterialSimple(world, v)); }); return list; } + public static TrackMaterial getMaterialSimple(BlockGetter world, Vec3 pos) { + return getMaterialSimple(world, pos, TrackMaterial.ANDESITE); + } + + public static TrackMaterial getMaterialSimple(BlockGetter world, Vec3 pos, TrackMaterial defaultMaterial) { + if (defaultMaterial == null) + defaultMaterial = TrackMaterial.ANDESITE; + if (world != null) { + Block block = world.getBlockState(new BlockPos(pos)).getBlock(); + if (block instanceof ITrackBlock track) { + return track.getMaterial(); + } + } + return defaultMaterial; + } + public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection list, BiFunction offsetFactory, Function normalFactory, - Function> dimensionFactory, Vec3 axis, BezierConnection viaTurn) { + Function> dimensionFactory, Vec3 axis, BezierConnection viaTurn, BiFunction materialFactory) { DiscoveredLocation firstLocation = new DiscoveredLocation(dimensionFactory.apply(true), offsetFactory.apply(0.5d, true)).viaTurn(viaTurn) + .materialA(materialFactory.apply(true, offsetFactory.apply(0.0d, true))) + .materialB(materialFactory.apply(true, offsetFactory.apply(1.0d, true))) .withNormal(normalFactory.apply(true)) .withDirection(axis); DiscoveredLocation secondLocation = new DiscoveredLocation(dimensionFactory.apply(false), offsetFactory.apply(0.5d, false)).viaTurn(viaTurn) + .materialA(materialFactory.apply(false, offsetFactory.apply(0.0d, false))) + .materialB(materialFactory.apply(false, offsetFactory.apply(1.0d, false))) .withNormal(normalFactory.apply(false)) .withDirection(axis); @@ -97,7 +118,7 @@ public interface ITrackBlock { firstLocation.forceNode(); secondLocation.forceNode(); } - + boolean skipFirst = false; boolean skipSecond = false; @@ -152,4 +173,6 @@ public interface ITrackBlock { .normalize()) < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE); } + TrackMaterial getMaterial(); + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java new file mode 100644 index 000000000..d49625a2f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java @@ -0,0 +1,137 @@ +package com.simibubi.create.content.logistics.trains; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.util.transform.Transform; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.Iterate; + +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; + +import org.jetbrains.annotations.Nullable; + +import static com.simibubi.create.AllBlockPartials.LARGE_BOGEY_WHEELS; +import static com.simibubi.create.AllBlockPartials.BOGEY_PIN; +import static com.simibubi.create.AllBlockPartials.BOGEY_DRIVE; +import static com.simibubi.create.AllBlockPartials.BOGEY_PISTON; +import static com.simibubi.create.AllBlockPartials.SMALL_BOGEY_WHEELS; +import static com.simibubi.create.AllBlockPartials.BOGEY_FRAME; + +public class StandardBogeyRenderer { + public static class CommonStandardBogeyRenderer extends BogeyRenderer.CommonRenderer { + @Override + public void initialiseContraptionModelData(MaterialManager materialManager) { + createModelInstances(materialManager, AllBlocks.SHAFT.getDefaultState() + .setValue(ShaftBlock.AXIS, Direction.Axis.Z), 2); + } + + @Override + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) { + boolean inInstancedContraption = vb == null; + Transform[] shafts = getTransformsFromBlockState(AllBlocks.SHAFT.getDefaultState() + .setValue(ShaftBlock.AXIS, Direction.Axis.Z), ms, inInstancedContraption, 2); + for (int i : Iterate.zeroAndOne) { + shafts[i].translate(-.5f, .25f, i * -1) + .centre() + .rotateZ(wheelAngle) + .unCentre(); + finalize(shafts[i], ms, light, vb); + } + } + } + + + public static class SmallStandardBogeyRenderer extends BogeyRenderer { + @Override + public void initialiseContraptionModelData(MaterialManager materialManager) { + createModelInstances(materialManager, SMALL_BOGEY_WHEELS, 2); + createModelInstances(materialManager, BOGEY_FRAME); + } + + + @Override + public BogeySizes.BogeySize getSize() { + return BogeySizes.SMALL; + } + + @Override + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) { + boolean inInstancedContraption = vb == null; + Transform transform = getTransformFromPartial(BOGEY_FRAME, ms, inInstancedContraption); + finalize(transform, ms, light, vb); + + Transform[] wheels = getTransformsFromPartial(SMALL_BOGEY_WHEELS, ms, inInstancedContraption, 2); + for (int side : Iterate.positiveAndNegative) { + if (!inInstancedContraption) + ms.pushPose(); + Transform wheel = wheels[(side + 1)/2]; + wheel.translate(0, 12 / 16f, side) + .rotateX(wheelAngle); + finalize(wheel, ms, light, vb); + if (!inInstancedContraption) + ms.popPose(); + } + } + } + + public static class LargeStandardBogeyRenderer extends BogeyRenderer { + @Override + public void initialiseContraptionModelData(MaterialManager materialManager) { + createModelInstances(materialManager, LARGE_BOGEY_WHEELS, BOGEY_DRIVE, BOGEY_PISTON, BOGEY_PIN); + createModelInstances(materialManager, AllBlocks.SHAFT.getDefaultState() + .setValue(ShaftBlock.AXIS, Direction.Axis.X), 2); + } + + @Override + public BogeySizes.BogeySize getSize() { + return BogeySizes.LARGE; + } + + @Override + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) { + boolean inInstancedContraption = vb == null; + + Transform[] secondaryShafts = getTransformsFromBlockState(AllBlocks.SHAFT.getDefaultState() + .setValue(ShaftBlock.AXIS, Direction.Axis.X), ms, inInstancedContraption, 2); + + for (int i : Iterate.zeroAndOne) { + Transform secondShaft = secondaryShafts[i]; + secondShaft.translate(-.5f, .25f, .5f + i * -2) + .centre() + .rotateX(wheelAngle) + .unCentre(); + finalize(secondShaft, ms, light, vb); + } + + Transform bogeyDrive = getTransformFromPartial(BOGEY_DRIVE, ms, inInstancedContraption); + finalize(bogeyDrive, ms, light, vb); + + Transform bogeyPiston = getTransformFromPartial(BOGEY_PISTON, ms, inInstancedContraption) + .translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle))); + finalize(bogeyPiston, ms, light, vb); + + if (!inInstancedContraption) + ms.pushPose(); + + Transform bogeyWheels = getTransformFromPartial(LARGE_BOGEY_WHEELS, ms, inInstancedContraption) + .translate(0, 1, 0) + .rotateX(wheelAngle); + finalize(bogeyWheels, ms, light, vb); + + Transform bogeyPin = getTransformFromPartial(BOGEY_PIN, ms, inInstancedContraption) + .translate(0, 1, 0) + .rotateX(wheelAngle) + .translate(0, 1 / 4f, 0) + .rotateX(-wheelAngle); + finalize(bogeyPin, ms, light, vb); + + if (!inInstancedContraption) + ms.popPose(); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java index d5e3affe0..501b437bf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java @@ -22,13 +22,19 @@ public class TrackEdge { BezierConnection turn; EdgeData edgeData; boolean interDimensional; + TrackMaterial trackMaterial; - public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn) { + public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn, TrackMaterial trackMaterial) { this.interDimensional = !node1.location.dimension.equals(node2.location.dimension); this.edgeData = new EdgeData(this); this.node1 = node1; this.node2 = node2; this.turn = turn; + this.trackMaterial = trackMaterial; + } + + public TrackMaterial getTrackMaterial() { + return trackMaterial; } public boolean isTurn() { @@ -181,13 +187,15 @@ public class TrackEdge { public CompoundTag write(DimensionPalette dimensions) { CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag(); baseCompound.put("Signals", edgeData.write(dimensions)); + baseCompound.putString("Material", getTrackMaterial().id.toString()); return baseCompound; } public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { TrackEdge trackEdge = - new TrackEdge(node1, node2, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null); + new TrackEdge(node1, node2, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null, + TrackMaterial.deserialize(tag.getString("Material"))); trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph, dimensions); return trackEdge; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java index 897713e94..8bb92da9f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java @@ -393,14 +393,15 @@ public class TrackGraph { return connectionsFrom.get(nodes.getSecond()); } - public void connectNodes(LevelAccessor reader, TrackNodeLocation location, TrackNodeLocation location2, + public void connectNodes(LevelAccessor reader, DiscoveredLocation location, DiscoveredLocation location2, @Nullable BezierConnection turn) { TrackNode node1 = nodes.get(location); TrackNode node2 = nodes.get(location2); boolean bezier = turn != null; - TrackEdge edge = new TrackEdge(node1, node2, turn); - TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null); + TrackMaterial material = bezier ? turn.getMaterial() : location2.materialA; + TrackEdge edge = new TrackEdge(node1, node2, turn, material); + TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null, material); for (TrackGraph graph : Create.RAILWAYS.trackNetworks.values()) { for (TrackNode otherNode1 : graph.nodes.values()) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java index dfd5d0e36..36e1fa5f4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java @@ -60,7 +60,7 @@ public class TrackGraphSync { public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) { flushGraphPacket(graph); currentGraphSyncPacket.addedEdges - .add(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge.getTurn())); + .add(Pair.of(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge.getTrackMaterial()), edge.getTurn())); currentPayload++; } @@ -82,7 +82,7 @@ public class TrackGraphSync { if (currentGraphSyncPacket.addedNodes.remove(nodeId) == null) currentGraphSyncPacket.removedNodes.add(nodeId); currentGraphSyncPacket.addedEdges.removeIf(pair -> { - Couple ids = pair.getFirst(); + Couple ids = pair.getFirst().getFirst(); return ids.getFirst() .intValue() == nodeId || ids.getSecond() @@ -156,7 +156,7 @@ public class TrackGraphSync { graph.connectionsByNode.get(node) .forEach((node2, edge) -> { Couple key = Couple.create(node.getNetId(), node2.getNetId()); - currentPacket.addedEdges.add(Pair.of(key, edge.getTurn())); + currentPacket.addedEdges.add(Pair.of(Pair.of(key, edge.getTrackMaterial()), edge.getTurn())); currentPacket.syncEdgeData(node, node2, edge); }); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java index 33e5e0790..7707db41b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java @@ -22,7 +22,7 @@ import net.minecraft.world.phys.Vec3; public class TrackGraphSyncPacket extends TrackGraphPacket { Map> addedNodes; - List, BezierConnection>> addedEdges; + List, TrackMaterial>, BezierConnection>> addedEdges; List removedNodes; List addedEdgePoints; List removedEdgePoints; @@ -79,7 +79,7 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { size = buffer.readVarInt(); for (int i = 0; i < size; i++) addedEdges.add( - Pair.of(Couple.create(buffer::readVarInt), buffer.readBoolean() ? new BezierConnection(buffer) : null)); + Pair.of(Pair.of(Couple.create(buffer::readVarInt), TrackMaterial.deserialize(buffer.readUtf())), buffer.readBoolean() ? new BezierConnection(buffer) : null)); size = buffer.readVarInt(); for (int i = 0; i < size; i++) @@ -134,8 +134,9 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { buffer.writeVarInt(addedEdges.size()); addedEdges.forEach(pair -> { - pair.getFirst() + pair.getFirst().getFirst() .forEach(buffer::writeVarInt); + buffer.writeUtf(pair.getFirst().getSecond().id.toString()); BezierConnection turn = pair.getSecond(); buffer.writeBoolean(turn != null); if (turn != null) @@ -192,13 +193,13 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond()); } - for (Pair, BezierConnection> pair : addedEdges) { - Couple nodes = pair.getFirst() + for (Pair, TrackMaterial>, BezierConnection> pair : addedEdges) { + Couple nodes = pair.getFirst().getFirst() .map(graph::getNode); TrackNode node1 = nodes.getFirst(); TrackNode node2 = nodes.getSecond(); if (node1 != null && node2 != null) - graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond())); + graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond(), pair.getFirst().getSecond())); } for (TrackEdgePoint edgePoint : addedEdgePoints) @@ -268,4 +269,4 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { updatedEdgeData.put(key, Pair.of(groupType, list)); } -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java index 66988f041..bc2c24241 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java @@ -5,6 +5,15 @@ import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.world.item.ItemStack; + +import net.minecraft.world.item.Items; + +import net.minecraft.world.level.block.Blocks; + import org.lwjgl.glfw.GLFW; import com.simibubi.create.AllKeys; @@ -209,7 +218,7 @@ public class TrackGraphVisualizer { } } - public static void debugViewGraph(TrackGraph graph) { + public static void debugViewGraph(TrackGraph graph, boolean extended) { Minecraft mc = Minecraft.getInstance(); Entity cameraEntity = mc.cameraEntity; if (cameraEntity == null) @@ -262,6 +271,13 @@ public class TrackGraphVisualizer { yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0); if (!edge.isTurn()) { + if (extended) { + Vec3 materialPos = edge.getPosition(0.5).add(0, 1, 0); + CreateClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos, + new ItemStack(edge.getTrackMaterial().trackBlock.get().get())); + CreateClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, 1, 1, 1)) + .colored(graph.color); + } CreateClient.OUTLINER.showLine(edge, edge.getPosition(0) .add(yOffset), edge.getPosition(1) @@ -273,6 +289,13 @@ public class TrackGraphVisualizer { Vec3 previous = null; BezierConnection turn = edge.getTurn(); + if (extended) { + Vec3 materialPos = edge.getPosition(0.5).add(0, 1, 0); + CreateClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos, + new ItemStack(edge.getTrackMaterial().trackBlock.get().get())); + CreateClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, 1, 1, 1)) + .colored(graph.color); + } for (int i = 0; i <= turn.getSegmentCount(); i++) { Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount()); if (previous != null) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java new file mode 100644 index 000000000..03794a220 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java @@ -0,0 +1,144 @@ +package com.simibubi.create.content.logistics.trains; + +import static com.simibubi.create.content.logistics.trains.TrackMaterialFactory.make; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.Create; +import com.simibubi.create.content.logistics.trains.track.TrackBlock; +import com.tterrag.registrate.util.nullness.NonNullSupplier; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class TrackMaterial { + public static final Map ALL = new HashMap<>(); + + public static final TrackMaterial ANDESITE = make(Create.asResource("andesite")) + .lang("Andesite") + .block(NonNullSupplier.lazy(() -> AllBlocks.TRACK)) + .particle(Create.asResource("block/palettes/stone_types/polished/andesite_cut_polished")) + .defaultModels() + .build(); + + public final ResourceLocation id; + public final String langName; + public final NonNullSupplier> trackBlock; + public final Ingredient sleeperIngredient; + public final Ingredient railsIngredient; + public final ResourceLocation particle; + public final TrackType trackType; + + @OnlyIn(Dist.CLIENT) + protected TrackModelHolder modelHolder; + + @OnlyIn(Dist.CLIENT) + public TrackModelHolder getModelHolder() { + return modelHolder; + } + + public TrackMaterial(ResourceLocation id, String langName, NonNullSupplier> trackBlock, + ResourceLocation particle, Ingredient sleeperIngredient, Ingredient railsIngredient, + TrackType trackType, Supplier> modelHolder) { + this.id = id; + this.langName = langName; + this.trackBlock = trackBlock; + this.sleeperIngredient = sleeperIngredient; + this.railsIngredient = railsIngredient; + this.particle = particle; + this.trackType = trackType; + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.modelHolder = modelHolder.get().get()); + ALL.put(this.id, this); + } + + public NonNullSupplier getTrackBlock() { + return this.trackBlock.get(); + } + + public TrackBlock createBlock(BlockBehaviour.Properties properties) { + return this.trackType.factory.create(properties, this); + } + + public boolean isCustom(String modId) { + return this.id.getNamespace().equals(modId); + } + + public static TrackMaterial[] allCustom(String modid) { + return ALL.values().stream().filter(tm -> tm.isCustom(modid)).toArray(TrackMaterial[]::new); + } + + public static List> allCustomBlocks(String modid) { + List> list = new ArrayList<>(); + for (TrackMaterial material : allCustom(modid)) { + list.add(material.getTrackBlock()); + } + return list; + } + + public static List> allBlocks() { + List> list = new ArrayList<>(); + for (TrackMaterial material : ALL.values()) { + list.add(material.getTrackBlock()); + } + return list; + } + + public String resourceName() { + return this.id.getPath(); + } + + public static TrackMaterial deserialize(String serializedName) { + if (serializedName.isBlank()) // Data migrating from 0.5 + return ANDESITE; + + ResourceLocation id = ResourceLocation.tryParse(serializedName); + if (id != null) + for (TrackMaterial material : ALL.values()) + if (material.id.equals(id)) + return material; + + Create.LOGGER.error("Failed to locate serialized track material: " + serializedName); + return ANDESITE; + } + + public static class TrackType { + @FunctionalInterface + protected interface TrackBlockFactory { + TrackBlock create(BlockBehaviour.Properties properties, TrackMaterial material); + } + + public static final TrackType STANDARD = new TrackType(Create.asResource("standard"), TrackBlock::new); + + public final ResourceLocation id; + protected final TrackBlockFactory factory; + + public TrackType(ResourceLocation id, TrackBlockFactory factory) { + this.id = id; + this.factory = factory; + } + } + + public static TrackMaterial fromItem(Item item) { + if (item instanceof BlockItem blockItem && blockItem.getBlock() instanceof ITrackBlock trackBlock) + return trackBlock.getMaterial(); + return TrackMaterial.ANDESITE; + } + + @OnlyIn(Dist.CLIENT) + public record TrackModelHolder(PartialModel tie, PartialModel segment_left, PartialModel segment_right) { + static final TrackModelHolder DEFAULT = new TrackModelHolder(AllBlockPartials.TRACK_TIE, AllBlockPartials.TRACK_SEGMENT_LEFT, AllBlockPartials.TRACK_SEGMENT_RIGHT); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java new file mode 100644 index 000000000..878f09ce2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java @@ -0,0 +1,133 @@ +package com.simibubi.create.content.logistics.trains; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.logistics.trains.track.TrackBlock; + +import com.tterrag.registrate.util.nullness.NonNullSupplier; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.level.ItemLike; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +import java.util.function.Supplier; +import java.util.stream.Stream; + +public class TrackMaterialFactory { + private final ResourceLocation id; + private String langName; + private NonNullSupplier> trackBlock; + private Ingredient sleeperIngredient = Ingredient.EMPTY; + private Ingredient railsIngredient = Ingredient.fromValues(Stream.of(new Ingredient.TagValue(AllTags.forgeItemTag("nuggets/iron")), new Ingredient.TagValue(AllTags.forgeItemTag("nuggets/zinc")))); + private ResourceLocation particle; + private TrackMaterial.TrackType trackType = TrackMaterial.TrackType.STANDARD; + + @OnlyIn(Dist.CLIENT) + private TrackMaterial.TrackModelHolder modelHolder; + @OnlyIn(Dist.CLIENT) + private PartialModel tieModel; + @OnlyIn(Dist.CLIENT) + private PartialModel leftSegmentModel; + @OnlyIn(Dist.CLIENT) + private PartialModel rightSegmentModel; + + public TrackMaterialFactory(ResourceLocation id) { + this.id = id; + } + + public static TrackMaterialFactory make(ResourceLocation id) { // Convenience function for static import + return new TrackMaterialFactory(id); + } + + public TrackMaterialFactory lang(String langName) { + this.langName = langName; + return this; + } + + public TrackMaterialFactory block(NonNullSupplier> trackBlock) { + this.trackBlock = trackBlock; + return this; + } + + public TrackMaterialFactory defaultModels() { // was setBuiltin + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.modelHolder = TrackMaterial.TrackModelHolder.DEFAULT); + return this; + } + + public TrackMaterialFactory sleeper(Ingredient sleeperIngredient) { + this.sleeperIngredient = sleeperIngredient; + return this; + } + + public TrackMaterialFactory sleeper(ItemLike... items) { + this.sleeperIngredient = Ingredient.of(items); + return this; + } + + public TrackMaterialFactory rails(Ingredient railsIngredient) { + this.railsIngredient = railsIngredient; + return this; + } + + public TrackMaterialFactory rails(ItemLike... items) { + this.railsIngredient = Ingredient.of(items); + return this; + } + + public TrackMaterialFactory noRecipeGen() { + this.railsIngredient = Ingredient.EMPTY; + this.sleeperIngredient = Ingredient.EMPTY; + return this; + } + + public TrackMaterialFactory particle(ResourceLocation particle) { + this.particle = particle; + return this; + } + + public TrackMaterialFactory trackType(TrackMaterial.TrackType trackType) { + this.trackType = trackType; + return this; + } + + public TrackMaterialFactory standardModels() { // was defaultModels + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + String namespace = id.getNamespace(); + String prefix = "block/track/" + id.getPath() + "/"; + tieModel = new PartialModel(new ResourceLocation(namespace, prefix + "tie")); + leftSegmentModel = new PartialModel(new ResourceLocation(namespace, prefix + "segment_left")); + rightSegmentModel = new PartialModel(new ResourceLocation(namespace, prefix + "segment_right")); + }); + return this; + } + + public TrackMaterialFactory customModels(Supplier> tieModel, Supplier> leftSegmentModel, Supplier> rightSegmentModel) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + this.tieModel = tieModel.get().get(); + this.leftSegmentModel = leftSegmentModel.get().get(); + this.rightSegmentModel = rightSegmentModel.get().get(); + }); + return this; + } + + public TrackMaterial build() { + assert trackBlock != null; + assert langName != null; + assert particle != null; + assert trackType != null; + assert sleeperIngredient != null; + assert railsIngredient != null; + assert id != null; + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + assert modelHolder != null; + if (tieModel != null || leftSegmentModel != null || rightSegmentModel != null) { + assert tieModel != null && leftSegmentModel != null && rightSegmentModel != null; + modelHolder = new TrackMaterial.TrackModelHolder(tieModel, leftSegmentModel, rightSegmentModel); + } + }); + return new TrackMaterial(id, langName, trackBlock, particle, sleeperIngredient, railsIngredient, trackType, () -> () -> modelHolder); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java index 509eedd23..ad8c0e009 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java @@ -24,8 +24,8 @@ public class TrackNodeLocation extends Vec3i { this(vec.x, vec.y, vec.z); } - public TrackNodeLocation(double p_121865_, double p_121866_, double p_121867_) { - super(Math.round(p_121865_ * 2), Math.floor(p_121866_ * 2), Math.round(p_121867_ * 2)); + public TrackNodeLocation(double x, double y, double z) { + super(Math.round(x * 2), Math.floor(y * 2), Math.round(z * 2)); } public TrackNodeLocation in(Level level) { @@ -116,9 +116,11 @@ public class TrackNodeLocation extends Vec3i { boolean forceNode = false; Vec3 direction; Vec3 normal; + TrackMaterial materialA; + TrackMaterial materialB; - public DiscoveredLocation(Level level, double p_121865_, double p_121866_, double p_121867_) { - super(p_121865_, p_121866_, p_121867_); + public DiscoveredLocation(Level level, double x, double y, double z) { + super(x, y, z); in(level); } @@ -131,6 +133,22 @@ public class TrackNodeLocation extends Vec3i { this(level.dimension(), vec); } + public DiscoveredLocation materialA(TrackMaterial material) { + this.materialA = material; + return this; + } + + public DiscoveredLocation materialB(TrackMaterial material) { + this.materialB = material; + return this; + } + + public DiscoveredLocation materials(TrackMaterial materialA, TrackMaterial materialB) { + this.materialA = materialA; + this.materialB = materialB; + return this; + } + public DiscoveredLocation viaTurn(BezierConnection turn) { this.turn = turn; if (turn != null) @@ -165,6 +183,10 @@ public class TrackNodeLocation extends Vec3i { return forceNode; } + public boolean differentMaterials() { + return materialA != materialB; + } + public boolean notInLineWith(Vec3 direction) { return this.direction != null && Math.max(direction.dot(this.direction), direction.dot(this.direction.scale(-1))) < 7 / 8f; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java index 611787364..c755b4613 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java @@ -234,10 +234,12 @@ public class TrackPropagator { return true; if (location.shouldForceNode()) return true; + if (location.differentMaterials()) + return true; if (next.stream() .anyMatch(DiscoveredLocation::shouldForceNode)) return true; - + Vec3 direction = location.direction; if (direction != null && next.stream() .anyMatch(dl -> dl.notInLineWith(direction))) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BackupBogeyRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BackupBogeyRenderer.java new file mode 100644 index 000000000..80494a94a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BackupBogeyRenderer.java @@ -0,0 +1,22 @@ +package com.simibubi.create.content.logistics.trains.entity; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.content.logistics.trains.BogeyRenderer; + +import net.minecraft.nbt.CompoundTag; + +public class BackupBogeyRenderer extends BogeyRenderer.CommonRenderer { + public static BackupBogeyRenderer INSTANCE = new BackupBogeyRenderer(); + + @Override + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) { + + } + + @Override + public void initialiseContraptionModelData(MaterialManager materialManager) { + + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java index 9a8a6c9c1..a9b0ff8af 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java @@ -1,235 +1,72 @@ package com.simibubi.create.content.logistics.trains.entity; -import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.content.logistics.trains.BogeyRenderer; + +import com.simibubi.create.content.logistics.trains.BogeySizes; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.LightLayer; import net.minecraft.world.phys.Vec3; -public sealed class BogeyInstance { +import java.util.Optional; + +public final class BogeyInstance { + private final BogeySizes.BogeySize size; + private final BogeyStyle style; public final CarriageBogey bogey; - private final ModelData[] shafts; + public final BogeyRenderer renderer; + public final Optional commonRenderer; - protected BogeyInstance(CarriageBogey bogey, MaterialManager materialManager) { + public BogeyInstance(CarriageBogey bogey, BogeyStyle style, BogeySizes.BogeySize size, MaterialManager materialManager) { this.bogey = bogey; + this.size = size; + this.style = style; - shafts = new ModelData[2]; - - materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, Direction.Axis.Z)) - .createInstances(shafts); + this.renderer = this.style.createRendererInstance(this.size); + this.commonRenderer = this.style.getNewCommonRenderInstance(); + commonRenderer.ifPresent(bogeyRenderer -> + bogeyRenderer.initialiseContraptionModelData(materialManager)); + renderer.initialiseContraptionModelData(materialManager); } - public void remove() { - for (ModelData shaft : shafts) - shaft.delete(); - } - - public void hiddenFrame() { + void hiddenFrame() { beginFrame(0, null); } - + public void beginFrame(float wheelAngle, PoseStack ms) { if (ms == null) { - for (int i : Iterate.zeroAndOne) - shafts[i].setEmptyTransform(); + renderer.emptyTransforms(); return; } - for (int i : Iterate.zeroAndOne) - shafts[i].setTransform(ms) - .translate(-.5f, .25f, i * -1) - .centre() - .rotateZ(wheelAngle) - .unCentre(); + commonRenderer.ifPresent(bogeyRenderer -> + bogeyRenderer.render(bogey.bogeyData, wheelAngle, ms)); + renderer.render(bogey.bogeyData, wheelAngle, ms); } public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) { var lightPos = new BlockPos(getLightPos(entity)); - - updateLight(world.getBrightness(LightLayer.BLOCK, lightPos), world.getBrightness(LightLayer.SKY, lightPos)); + commonRenderer.ifPresent(bogeyRenderer + -> bogeyRenderer.updateLight(world.getBrightness(LightLayer.BLOCK, lightPos), + world.getBrightness(LightLayer.SKY, lightPos))); + renderer.updateLight(world.getBrightness(LightLayer.BLOCK, lightPos), + world.getBrightness(LightLayer.SKY, lightPos)); } private Vec3 getLightPos(CarriageContraptionEntity entity) { - if (bogey.getAnchorPosition() != null) { - return bogey.getAnchorPosition(); - } else { - return entity.getLightProbePosition(AnimationTickHolder.getPartialTicks()); - } + return bogey.getAnchorPosition() != null ? bogey.getAnchorPosition() + : entity.getLightProbePosition(AnimationTickHolder.getPartialTicks()); } - public void updateLight(int blockLight, int skyLight) { - for (ModelData shaft : shafts) { - shaft.setBlockLight(blockLight) - .setSkyLight(skyLight); - } - } - - public static final class Frame extends BogeyInstance { - - private final ModelData frame; - private final ModelData[] wheels; - - public Frame(CarriageBogey bogey, MaterialManager materialManager) { - super(bogey, materialManager); - - frame = materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlockPartials.BOGEY_FRAME) - .createInstance(); - - wheels = new ModelData[2]; - - materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlockPartials.SMALL_BOGEY_WHEELS) - .createInstances(wheels); - } - - @Override - public void beginFrame(float wheelAngle, PoseStack ms) { - super.beginFrame(wheelAngle, ms); - - if (ms == null) { - frame.setEmptyTransform(); - for (int side : Iterate.positiveAndNegative) - wheels[(side + 1) / 2].setEmptyTransform(); - return; - } - - frame.setTransform(ms); - - for (int side : Iterate.positiveAndNegative) { - wheels[(side + 1) / 2].setTransform(ms) - .translate(0, 12 / 16f, side) - .rotateX(wheelAngle); - } - } - - @Override - public void updateLight(int blockLight, int skyLight) { - super.updateLight(blockLight, skyLight); - frame.setBlockLight(blockLight) - .setSkyLight(skyLight); - for (ModelData wheel : wheels) - wheel.setBlockLight(blockLight) - .setSkyLight(skyLight); - } - - @Override - public void remove() { - super.remove(); - frame.delete(); - for (ModelData wheel : wheels) - wheel.delete(); - } - } - - public static final class Drive extends BogeyInstance { - - private final ModelData[] secondShaft; - private final ModelData drive; - private final ModelData piston; - private final ModelData wheels; - private final ModelData pin; - - public Drive(CarriageBogey bogey, MaterialManager materialManager) { - super(bogey, materialManager); - Material mat = materialManager.defaultSolid() - .material(Materials.TRANSFORMED); - - secondShaft = new ModelData[2]; - - mat.getModel(AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, Direction.Axis.X)) - .createInstances(secondShaft); - - drive = mat.getModel(AllBlockPartials.BOGEY_DRIVE) - .createInstance(); - piston = mat.getModel(AllBlockPartials.BOGEY_PISTON) - .createInstance(); - wheels = mat.getModel(AllBlockPartials.LARGE_BOGEY_WHEELS) - .createInstance(); - pin = mat.getModel(AllBlockPartials.BOGEY_PIN) - .createInstance(); - } - - @Override - public void beginFrame(float wheelAngle, PoseStack ms) { - super.beginFrame(wheelAngle, ms); - - if (ms == null) { - for (int i : Iterate.zeroAndOne) - secondShaft[i].setEmptyTransform(); - drive.setEmptyTransform(); - piston.setEmptyTransform(); - wheels.setEmptyTransform(); - pin.setEmptyTransform(); - return; - } - - for (int i : Iterate.zeroAndOne) - secondShaft[i].setTransform(ms) - .translate(-.5f, .25f, .5f + i * -2) - .centre() - .rotateX(wheelAngle) - .unCentre(); - - drive.setTransform(ms); - piston.setTransform(ms) - .translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle))); - - wheels.setTransform(ms) - .translate(0, 1, 0) - .rotateX(wheelAngle); - pin.setTransform(ms) - .translate(0, 1, 0) - .rotateX(wheelAngle) - .translate(0, 1 / 4f, 0) - .rotateX(-wheelAngle); - } - - @Override - public void updateLight(int blockLight, int skyLight) { - super.updateLight(blockLight, skyLight); - for (ModelData shaft : secondShaft) - shaft.setBlockLight(blockLight) - .setSkyLight(skyLight); - drive.setBlockLight(blockLight) - .setSkyLight(skyLight); - piston.setBlockLight(blockLight) - .setSkyLight(skyLight); - wheels.setBlockLight(blockLight) - .setSkyLight(skyLight); - pin.setBlockLight(blockLight) - .setSkyLight(skyLight); - } - - @Override - public void remove() { - super.remove(); - for (ModelData shaft : secondShaft) - shaft.delete(); - drive.delete(); - piston.delete(); - wheels.delete(); - pin.delete(); - } + @FunctionalInterface + interface BogeyInstanceFactory { + BogeyInstance create(CarriageBogey bogey, BogeySizes.BogeySize size, + MaterialManager materialManager); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java new file mode 100644 index 000000000..2b3efc8d7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java @@ -0,0 +1,114 @@ +package com.simibubi.create.content.logistics.trains.entity; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.logistics.trains.BogeyRenderer; + +import com.simibubi.create.content.logistics.trains.BogeyRenderer.CommonRenderer; +import com.simibubi.create.content.logistics.trains.BogeySizes; + +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.registries.ForgeRegistries; + +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Stream; + + +public class BogeyStyle { + private final Optional> commonRendererFactory; + + public final ResourceLocation name; + public final ResourceLocation cycleGroup; + private final Optional commonRenderer; + private final Map sizes; + public final Component displayName; + public final ResourceLocation soundType; + public final ParticleOptions contactParticle; + public final ParticleOptions smokeParticle; + public final CompoundTag defaultData; + + public BogeyStyle(ResourceLocation name, ResourceLocation cycleGroup, Component displayName, ResourceLocation soundType, ParticleOptions contactParticle, ParticleOptions smokeParticle, + CompoundTag defaultData, Map sizes, Optional> commonRenderer) { + this.name = name; + this.cycleGroup = cycleGroup; + this.displayName = displayName; + this.soundType = soundType; + this.contactParticle = contactParticle; + this.smokeParticle = smokeParticle; + this.defaultData = defaultData; + + this.sizes = sizes; + + this.commonRendererFactory = commonRenderer; + this.commonRenderer = commonRenderer.map(Supplier::get); + } + + public Map getCycleGroup() { + return AllBogeyStyles.getCycleGroup(cycleGroup); + } + + public Block getNextBlock(BogeySizes.BogeySize currentSize) { + return Stream.iterate(currentSize.increment(), BogeySizes.BogeySize::increment) + .filter(sizes::containsKey) + .findFirst() + .map(size -> ForgeRegistries.BLOCKS.getValue(sizes.get(size).block())) + .orElse(ForgeRegistries.BLOCKS.getValue(sizes.get(currentSize).block())); + } + + public Block getBlockOfSize(BogeySizes.BogeySize size) { + return ForgeRegistries.BLOCKS.getValue(sizes.get(size).block()); + } + + public Set validSizes() { + return sizes.keySet(); + } + + @NotNull + public SoundEvent getSoundType() { + AllSoundEvents.SoundEntry entry = AllSoundEvents.ALL.get(this.soundType); + if (entry == null || entry.getMainEvent() == null) entry = AllSoundEvents.TRAIN2; + return entry.getMainEvent(); + } + + public BogeyRenderer createRendererInstance(BogeySizes.BogeySize size) { + return this.sizes.get(size).createRenderInstance(); + } + + public BogeyRenderer getInWorldRenderInstance(BogeySizes.BogeySize size) { + SizeData sizeData = this.sizes.get(size); + return sizeData != null ? sizeData.getInWorldInstance() : BackupBogeyRenderer.INSTANCE; + } + + public Optional getInWorldCommonRenderInstance() { + return this.commonRenderer; + } + + public Optional getNewCommonRenderInstance() { + return this.commonRendererFactory.map(Supplier::get); + } + + public BogeyInstance createInstance(CarriageBogey bogey, BogeySizes.BogeySize size, MaterialManager materialManager) { + return new BogeyInstance(bogey, this, size, materialManager); + } + + public record SizeData(ResourceLocation block, Supplier rendererFactory, BogeyRenderer instance) { + public BogeyRenderer createRenderInstance() { + return rendererFactory.get(); + } + + public BogeyRenderer getInWorldInstance() { + return instance; + } + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java index 12d25eea7..ec7e9f1d7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java @@ -85,6 +85,11 @@ public class Carriage { bogey2.carriage = this; } + public boolean isOnIncompatibleTrack() { + return leadingBogey().type.isOnIncompatibleTrack(this, true) + || trailingBogey().type.isOnIncompatibleTrack(this, false); + } + public void setTrain(Train train) { this.train = train; } @@ -306,6 +311,9 @@ public class Carriage { double leadingWheelSpacing = leadingBogey.type.getWheelPointSpacing(); double trailingWheelSpacing = trailingBogey.type.getWheelPointSpacing(); + boolean leadingUpsideDown = leadingBogey.isUpsideDown(); + boolean trailingUpsideDown = trailingBogey.isUpsideDown(); + for (boolean leading : Iterate.trueAndFalse) { TravellingPoint point = leading ? getLeadingPoint() : getTrailingPoint(); TravellingPoint otherPoint = !leading ? getLeadingPoint() : getTrailingPoint(); @@ -321,24 +329,31 @@ public class Carriage { dce.positionAnchor = dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() : pivoted(dce, dimension, point, - leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2); + leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2, + leadingUpsideDown, trailingUpsideDown); + + boolean backAnchorFlip = trailingBogey.isUpsideDown() ^ leadingBogey.isUpsideDown(); if (isOnTwoBogeys()) { dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() : pivoted(dce, dimension, point, - leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2)); - dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition() + leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2, + leadingUpsideDown, trailingUpsideDown)); + dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition(backAnchorFlip) : pivoted(dce, dimension, point, - leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2)); + leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2, + leadingUpsideDown, trailingUpsideDown)); } else { if (dimension.equals(otherDimension)) { dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition); } else { dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition() - : pivoted(dce, dimension, point, leadingWheelSpacing)); + : pivoted(dce, dimension, point, leadingWheelSpacing, + leadingUpsideDown, trailingUpsideDown)); dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition() - : pivoted(dce, dimension, point, leadingWheelSpacing)); + : pivoted(dce, dimension, point, leadingWheelSpacing, + leadingUpsideDown, trailingUpsideDown)); } } @@ -356,15 +371,16 @@ public class Carriage { } private Vec3 pivoted(DimensionalCarriageEntity dce, ResourceKey dimension, TravellingPoint start, - double offset) { + double offset, boolean leadingUpsideDown, boolean trailingUpsideDown) { if (train.graph == null) return dce.pivot == null ? null : dce.pivot.getLocation(); TrackNodeLocation pivot = dce.findPivot(dimension, start == getLeadingPoint()); if (pivot == null) return null; - Vec3 startVec = start.getPosition(); + boolean flipped = start != getLeadingPoint() && (leadingUpsideDown != trailingUpsideDown); + Vec3 startVec = start.getPosition(flipped); Vec3 portalVec = pivot.getLocation() - .add(0, 1, 0); + .add(0, leadingUpsideDown ? -1.0 : 1.0, 0); return VecHelper.lerp((float) (offset / startVec.distanceTo(portalVec)), startVec, portalVec); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java index c9e2d7220..1d22c4aec 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java @@ -3,13 +3,16 @@ package com.simibubi.create.content.logistics.trains.entity; import javax.annotation.Nullable; import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllBogeyStyles; import com.simibubi.create.Create; import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.content.logistics.trains.TrackGraph; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.RegisteredObjects; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.animation.LerpedFloat; @@ -25,13 +28,20 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.phys.Vec3; import net.minecraftforge.registries.ForgeRegistries; +import static com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity.BOGEY_DATA_KEY; +import static com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity.BOGEY_STYLE_KEY; + public class CarriageBogey { - public Carriage carriage; + public static final String UPSIDE_DOWN_KEY = "UpsideDown"; + public Carriage carriage; boolean isLeading; - IBogeyBlock type; + public CompoundTag bogeyData; + + AbstractBogeyBlock type; + boolean upsideDown; Couple points; LerpedFloat wheelAngle; @@ -42,8 +52,15 @@ public class CarriageBogey { int derailAngle; - public CarriageBogey(IBogeyBlock type, TravellingPoint point, TravellingPoint point2) { + public CarriageBogey(AbstractBogeyBlock type, boolean upsideDown, CompoundTag bogeyData, TravellingPoint point, TravellingPoint point2) { this.type = type; + this.upsideDown = type.canBeUpsideDown() && upsideDown; + point.upsideDown = this.upsideDown; + point2.upsideDown = this.upsideDown; + if (bogeyData == null || bogeyData.isEmpty()) + bogeyData = this.createBogeyData(); // Prevent Crash When Updating + bogeyData.putBoolean(UPSIDE_DOWN_KEY, upsideDown); + this.bogeyData = bogeyData; points = Couple.create(point, point2); wheelAngle = LerpedFloat.angular(); yaw = LerpedFloat.angular(); @@ -100,11 +117,15 @@ public class CarriageBogey { } public TravellingPoint leading() { - return points.getFirst(); + TravellingPoint point = points.getFirst(); + point.upsideDown = isUpsideDown(); + return point; } public TravellingPoint trailing() { - return points.getSecond(); + TravellingPoint point = points.getSecond(); + point.upsideDown = isUpsideDown(); + return point; } public double getStress() { @@ -118,18 +139,25 @@ public class CarriageBogey { @Nullable public Vec3 getAnchorPosition() { + return getAnchorPosition(false); + } + + @Nullable + public Vec3 getAnchorPosition(boolean flipUpsideDown) { if (leading().edge == null) return null; return points.getFirst() - .getPosition() - .add(points.getSecond() - .getPosition()) - .scale(.5); + .getPosition(flipUpsideDown) + .add(points.getSecond() + .getPosition(flipUpsideDown)) + .scale(.5); } public void updateCouplingAnchor(Vec3 entityPos, float entityXRot, float entityYRot, int bogeySpacing, float partialTicks, boolean leading) { - Vec3 thisOffset = type.getConnectorAnchorOffset(); + boolean selfUpsideDown = isUpsideDown(); + boolean leadingUpsideDown = carriage.leadingBogey().isUpsideDown(); + Vec3 thisOffset = type.getConnectorAnchorOffset(selfUpsideDown); thisOffset = thisOffset.multiply(1, 1, leading ? -1 : 1); thisOffset = VecHelper.rotate(thisOffset, pitch.getValue(partialTicks), Axis.X); @@ -141,6 +169,8 @@ public class CarriageBogey { thisOffset = VecHelper.rotate(thisOffset, 180, Axis.Y); thisOffset = VecHelper.rotate(thisOffset, -entityXRot, Axis.X); thisOffset = VecHelper.rotate(thisOffset, entityYRot + 90, Axis.Y); + if (selfUpsideDown != leadingUpsideDown) + thisOffset = thisOffset.add(0, selfUpsideDown ? -2 : 2, 0); couplingAnchors.set(leading, entityPos.add(thisOffset)); } @@ -150,23 +180,46 @@ public class CarriageBogey { tag.putString("Type", RegisteredObjects.getKeyOrThrow((Block) type) .toString()); tag.put("Points", points.serializeEach(tp -> tp.write(dimensions))); + tag.putBoolean("UpsideDown", upsideDown); + bogeyData.putBoolean(UPSIDE_DOWN_KEY, upsideDown); + NBTHelper.writeResourceLocation(bogeyData, BOGEY_STYLE_KEY, getStyle().name); + tag.put(BOGEY_DATA_KEY, bogeyData); return tag; } public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { ResourceLocation location = new ResourceLocation(tag.getString("Type")); - IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(location); + AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(location); + boolean upsideDown = tag.getBoolean("UpsideDown"); Couple points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND), c -> TravellingPoint.read(c, graph, dimensions)); - CarriageBogey carriageBogey = new CarriageBogey(type, points.getFirst(), points.getSecond()); - return carriageBogey; + CompoundTag data = tag.getCompound(AbstractBogeyTileEntity.BOGEY_DATA_KEY); + return new CarriageBogey(type, upsideDown, data, points.getFirst(), points.getSecond()); } public BogeyInstance createInstance(MaterialManager materialManager) { - return type.createInstance(materialManager, this); + return this.getStyle().createInstance(this, type.getSize(), materialManager); + } + + public BogeyStyle getStyle() { + ResourceLocation location = NBTHelper.readResourceLocation(this.bogeyData, BOGEY_STYLE_KEY); + BogeyStyle style = AllBogeyStyles.BOGEY_STYLES.get(location); + return style != null ? style : AllBogeyStyles.STANDARD; // just for safety + } + + private CompoundTag createBogeyData() { + BogeyStyle style = type != null ? type.getDefaultStyle() : AllBogeyStyles.STANDARD; + CompoundTag nbt = style.defaultData != null ? style.defaultData : new CompoundTag(); + NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, style.name); + nbt.putBoolean(UPSIDE_DOWN_KEY, isUpsideDown()); + return nbt; } void setLeading() { isLeading = true; } + + public boolean isUpsideDown() { + return type.canBeUpsideDown() && upsideDown; + } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java index ad2396191..1b185055f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java @@ -22,7 +22,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.ren import com.simibubi.create.content.contraptions.components.structureMovement.train.TrainCargoManager; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; @@ -71,7 +71,7 @@ public class CarriageContraption extends Contraption { // render public int portalCutoffMin; public int portalCutoffMax; - + static final IItemHandlerModifiable fallbackItems = new ItemStackHandler(); static final IFluidHandler fallbackFluids = new FluidTank(0); @@ -162,11 +162,13 @@ public class CarriageContraption extends Contraption { .getStep(), toLocalPos(pos)); } - if (blockState.getBlock() instanceof IBogeyBlock) { + if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) { + boolean captureTE = bogey.captureTileEntityForTrain(); bogeys++; if (bogeys == 2) secondBogeyPos = pos; - return Pair.of(new StructureBlockInfo(pos, blockState, null), null); + return Pair.of(new StructureBlockInfo(pos, blockState, captureTE ? getTileEntityNBT(world, pos) : null), + captureTE ? world.getBlockEntity(pos) : null); } if (AllBlocks.BLAZE_BURNER.has(blockState) @@ -235,7 +237,7 @@ public class CarriageContraption extends Contraption { protected MountedStorageManager getStorageForSpawnPacket() { return storageProxy; } - + @Override protected ContraptionType getType() { return ContraptionType.CARRIAGE; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java index 5de635e4a..02b219074 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java @@ -13,6 +13,7 @@ import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.core.BlockPos; import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.phys.Vec3; public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer { @@ -37,7 +38,7 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer MultiBufferSource buffers, int overlay) { if (!entity.validForRender || entity.firstPositionUpdate) return; - + super.render(entity, yaw, partialTicks, ms, buffers, overlay); Carriage carriage = entity.getCarriage(); @@ -65,8 +66,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks); int light = getBogeyLightCoords(entity, bogey, partialTicks); + bogey.type.render(null, bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light, - overlay); + overlay, bogey.getStyle(), bogey.bogeyData); ms.popPose(); } @@ -80,6 +82,8 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot, float viewXRot, float partialTicks) { + boolean selfUpsideDown = bogey.isUpsideDown(); + boolean leadingUpsideDown = bogey.carriage.leadingBogey().isUpsideDown(); TransformStack.cast(ms) .rotateY(viewYRot + 90) .rotateX(-viewXRot) @@ -90,7 +94,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer .rotateY(-viewYRot - 90) .rotateY(bogey.yaw.getValue(partialTicks)) .rotateX(bogey.pitch.getValue(partialTicks)) - .translate(0, .5f, 0); + .translate(0, .5f, 0) + .rotateZ(selfUpsideDown ? 180 : 0) + .translateY(selfUpsideDown != leadingUpsideDown ? 2 : 0); } public static int getBogeyLightCoords(CarriageContraptionEntity entity, CarriageBogey bogey, float partialTicks) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java index 4d18e2525..6797c05cd 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java @@ -7,6 +7,7 @@ import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; +import com.simibubi.create.content.logistics.trains.BogeyRenderer; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; @@ -31,7 +32,8 @@ public class CarriageContraptionInstance extends EntityInstance + bogey.getStyle().createInstance(bogey, bogey.type.getSize(), manager), materialManager); updateLight(); } @@ -98,8 +100,10 @@ public class CarriageContraptionInstance extends EntityInstance { - if (instance != null) - instance.remove(); + if (instance != null) { + instance.commonRenderer.ifPresent(BogeyRenderer::remove); + instance.renderer.remove(); + } }); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java index a77635d64..d736e15f8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java @@ -79,7 +79,7 @@ public class CarriageCouplingRenderer { float margin = 3 / 16f; double couplingDistance = train.carriageSpacing.get(i) - 2 * margin - - bogey1.type.getConnectorAnchorOffset().z - bogey2.type.getConnectorAnchorOffset().z; + - bogey1.type.getConnectorAnchorOffset(bogey1.isUpsideDown()).z - bogey2.type.getConnectorAnchorOffset(bogey2.isUpsideDown()).z; int couplingSegments = (int) Math.round(couplingDistance * 4); double stretch = ((anchor2.distanceTo(anchor) - 2 * margin) * 4) / couplingSegments; for (int j = 0; j < couplingSegments; j++) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java index be2e6fe41..e25db67d8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java @@ -10,7 +10,6 @@ import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; import net.minecraft.client.Minecraft; import net.minecraft.core.Direction.Axis; -import net.minecraft.core.particles.ParticleTypes; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -110,7 +109,7 @@ public class CarriageParticles { m = m.add(contraptionMotion.scale(.75f)); - level.addParticle(spark ? ParticleTypes.CRIT : ParticleTypes.POOF, v.x, v.y, v.z, m.x, m.y, m.z); + level.addParticle(spark ? bogey.getStyle().contactParticle : bogey.getStyle().smokeParticle, v.x, v.y, v.z, m.x, m.y, m.z); } } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java index 6d109d1ad..932ce903f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.trains.entity; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents.SoundEntry; import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity; +import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.animation.LerpedFloat; import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; @@ -29,6 +30,9 @@ public class CarriageSounds { LoopingSound sharedWheelSoundSeated; LoopingSound sharedHonkSound; + Couple bogeySounds; + SoundEvent closestBogeySound; + boolean arrived; int tick; @@ -36,6 +40,10 @@ public class CarriageSounds { public CarriageSounds(CarriageContraptionEntity entity) { this.entity = entity; + bogeySounds = entity.getCarriage().bogeys.map(bogey -> + bogey != null && bogey.getStyle() != null ? bogey.getStyle().getSoundType() + : AllSoundEvents.TRAIN2.getMainEvent()); + closestBogeySound = bogeySounds.getFirst(); distanceFactor = LerpedFloat.linear(); speedFactor = LerpedFloat.linear(); approachFactor = LerpedFloat.linear(); @@ -79,6 +87,15 @@ public class CarriageSounds { double distance1 = toBogey1.length(); double distance2 = toBogey2.length(); + Couple bogeys = entity.getCarriage().bogeys; + CarriageBogey relevantBogey = bogeys.get(distance1 > distance2); + if (relevantBogey == null) { + relevantBogey = bogeys.getFirst(); + } + if (relevantBogey != null) { + closestBogeySound = relevantBogey.getStyle().getSoundType(); + } + Vec3 toCarriage = distance1 > distance2 ? toBogey2 : toBogey1; double distance = Math.min(distance1, distance2); Vec3 soundLocation = cam.add(toCarriage); @@ -97,7 +114,7 @@ public class CarriageSounds { seatCrossfade.tickChaser(); minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent()); - sharedWheelSound = playIfMissing(mc, sharedWheelSound, AllSoundEvents.TRAIN2.getMainEvent()); + sharedWheelSound = playIfMissing(mc, sharedWheelSound, closestBogeySound); sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent()); float volume = Math.min(Math.min(speedFactor.getValue(), distanceFactor.getValue() / 100), @@ -205,7 +222,7 @@ public class CarriageSounds { public void submitSharedSoundVolume(Vec3 location, float volume) { Minecraft mc = Minecraft.getInstance(); minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent()); - sharedWheelSound = playIfMissing(mc, sharedWheelSound, AllSoundEvents.TRAIN2.getMainEvent()); + sharedWheelSound = playIfMissing(mc, sharedWheelSound, closestBogeySound); sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent()); boolean approach = true; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java index 258bc4da1..9e08613d5 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java @@ -14,6 +14,8 @@ import java.util.UUID; import javax.annotation.Nullable; +import com.simibubi.create.content.logistics.trains.TrackMaterial; + import org.apache.commons.lang3.mutable.MutableDouble; import org.apache.commons.lang3.mutable.MutableObject; @@ -251,7 +253,7 @@ public class Navigation { return; } } - + topSpeed *= train.throttle; double turnTopSpeed = Math.min(topSpeed, train.maxTurnSpeed()); @@ -540,6 +542,21 @@ public class Navigation { if (graph == null) return; + // Cache the list of track types that the train can travel on + Set validTypes = new HashSet<>(); + for (int i = 0; i < train.carriages.size(); i++) { + Carriage carriage = train.carriages.get(i); + if (i == 0) { + validTypes.addAll(carriage.leadingBogey().type.getValidPathfindingTypes(carriage.leadingBogey().getStyle())); + } else { + validTypes.retainAll(carriage.leadingBogey().type.getValidPathfindingTypes(carriage.leadingBogey().getStyle())); + } + if (carriage.isOnTwoBogeys()) + validTypes.retainAll(carriage.trailingBogey().type.getValidPathfindingTypes(carriage.trailingBogey().getStyle())); + } + if (validTypes.isEmpty()) // if there are no valid track types, a route can't be found + return; + Map penalties = new IdentityHashMap<>(); boolean costRelevant = maxCost >= 0; if (costRelevant) { @@ -579,7 +596,7 @@ public class Navigation { .get(initialNode2); if (initialEdge == null) return; - + double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position; frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge)); @@ -659,6 +676,8 @@ public class Navigation { continue; for (Entry target : validTargets) { + if (!validTypes.contains(target.getValue().getTrackMaterial().trackType)) + continue; TrackNode newNode = target.getKey(); TrackEdge newEdge = target.getValue(); double newDistance = newEdge.getLength() + distance; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index a5a371013..dea3d9782 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -17,6 +17,10 @@ import java.util.function.Consumer; import javax.annotation.Nullable; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; + +import net.minecraft.world.level.block.entity.BlockEntity; + import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableObject; @@ -124,7 +128,7 @@ public class Train { public int honkPitch; public float accumulatedSteamRelease; - + int tickOffset; double[] stress; @@ -277,7 +281,7 @@ public class Train { int carriageCount = carriages.size(); boolean stalled = false; double maxStress = 0; - + if (carriageWaitingForChunks != -1) distance = 0; @@ -313,11 +317,17 @@ public class Train { if (leadingAnchor == null || trailingAnchor == null) continue; - total += leadingAnchor.distanceTo(trailingAnchor); + double distanceTo = leadingAnchor.distanceToSqr(trailingAnchor); + if (carriage.leadingBogey().isUpsideDown() != previousCarriage.trailingBogey().isUpsideDown()) { + distanceTo = Math.sqrt(distanceTo - 4); + } else { + distanceTo = Math.sqrt(distanceTo); + } + total += distanceTo; entries++; } } - + if (entries > 0) actual = total / entries; @@ -369,13 +379,13 @@ public class Train { .getLeadingPoint(); double totalStress = derailed ? 0 : leadingStress + trailingStress; - + boolean first = i == 0; boolean last = i == carriageCount - 1; int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE; double actualDistance = carriage.travel(level, graph, distance + totalStress, toFollowForward, toFollowBackward, carriageType); - blocked |= carriage.blocked; + blocked |= carriage.blocked || carriage.isOnIncompatibleTrack(); boolean onTwoBogeys = carriage.isOnTwoBogeys(); maxStress = Math.max(maxStress, onTwoBogeys ? carriage.bogeySpacing - carriage.getAnchorDiff() : 0); @@ -722,9 +732,20 @@ public class Train { if (entity.getContraption()instanceof CarriageContraption cc) cc.returnStorageForDisassembly(carriage.storage); entity.setPos(Vec3 - .atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset))); + .atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset).below(carriage.leadingBogey().isUpsideDown() ? 2 : 0))); entity.disassemble(); + for (CarriageBogey bogey : carriage.bogeys) { + if (bogey == null) + continue; + Vec3 bogeyPosition = bogey.getAnchorPosition(); + if (bogeyPosition == null) continue; + BlockEntity be = level.getBlockEntity(new BlockPos(bogeyPosition)); + if (!(be instanceof AbstractBogeyTileEntity sbte)) + continue; + sbte.setBogeyData(bogey.bogeyData); + } + offset += carriage.bogeySpacing; if (i < carriageSpacing.size()) @@ -944,7 +965,7 @@ public class Train { occupiedObservers.clear(); cachedObserverFiltering.clear(); - TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position); + TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position, false); Map allGroups = Create.RAILWAYS.signalEdgeGroups; MutableObject prevGroup = new MutableObject<>(null); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java index 479b2699e..238124743 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java @@ -7,12 +7,13 @@ import java.util.UUID; import java.util.function.Supplier; import com.simibubi.create.CreateClient; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.foundation.networking.SimplePacketBase; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.RegisteredObjects; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.Block; @@ -44,11 +45,13 @@ public class TrainPacket extends SimplePacketBase { int size = buffer.readVarInt(); for (int i = 0; i < size; i++) { Couple bogies = Couple.create(null, null); - for (boolean first : Iterate.trueAndFalse) { - if (!first && !buffer.readBoolean()) + for (boolean isFirst : Iterate.trueAndFalse) { + if (!isFirst && !buffer.readBoolean()) continue; - IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation()); - bogies.set(first, new CarriageBogey(type, new TravellingPoint(), new TravellingPoint())); + AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation()); + boolean upsideDown = buffer.readBoolean(); + CompoundTag data = buffer.readNbt(); + bogies.set(isFirst, new CarriageBogey(type, upsideDown, data, new TravellingPoint(), new TravellingPoint())); } int spacing = buffer.readVarInt(); carriages.add(new Carriage(bogies.getFirst(), bogies.getSecond(), spacing)); @@ -86,6 +89,8 @@ public class TrainPacket extends SimplePacketBase { } CarriageBogey bogey = carriage.bogeys.get(first); buffer.writeResourceLocation(RegisteredObjects.getKeyOrThrow((Block) bogey.type)); + buffer.writeBoolean(bogey.upsideDown); + buffer.writeNbt(bogey.bogeyData); } buffer.writeVarInt(carriage.bogeySpacing); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java index 149120c53..edde7903d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java @@ -115,10 +115,13 @@ public class TrainRelocator { BlockPos blockPos = blockhit.getBlockPos(); BezierTrackPointLocation hoveredBezier = null; + boolean upsideDown = relocating.carriages.get(0).leadingBogey().isUpsideDown(); + Vec3 offset = upsideDown ? new Vec3(0, -0.5, 0) : Vec3.ZERO; + if (simulate && toVisualise != null && lastHoveredResult != null) { for (int i = 0; i < toVisualise.size() - 1; i++) { - Vec3 vec1 = toVisualise.get(i); - Vec3 vec2 = toVisualise.get(i + 1); + Vec3 vec1 = toVisualise.get(i).add(offset); + Vec3 vec2 = toVisualise.get(i + 1).add(offset); CreateClient.OUTLINER.showLine(Pair.of(relocating, i), vec1.add(0, -.925f, 0), vec2.add(0, -.925f, 0)) .colored(lastHoveredResult || i != toVisualise.size() - 2 ? 0x95CD41 : 0xEA5C2B) .disableLineNormals() @@ -150,7 +153,7 @@ public class TrainRelocator { boolean direction = bezierSelection != null && lookAngle.dot(bezierSelection.direction()) < 0; boolean result = relocate(relocating, mc.level, blockPos, hoveredBezier, direction, lookAngle, true); if (!simulate && result) { - relocating.carriages.forEach(c -> c.forEachPresentEntity(e -> e.nonDamageTicks = 10)); + relocating.carriages.forEach(c -> c.forEachPresentEntity(e -> e.nonDamageTicks = 10)); AllPackets.channel.sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, hoveredBezier, direction, lookAngle, relocatingEntityId)); } @@ -182,7 +185,7 @@ public class TrainRelocator { if (edge == null) return false; - TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position); + TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position, false); IEdgePointListener ignoreSignals = probe.ignoreEdgePoints(); ITurnListener ignoreTurns = probe.ignoreTurns(); List, Double>> recordedLocations = new ArrayList<>(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java index 194d926a6..827380139 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java @@ -38,6 +38,7 @@ public class TravellingPoint { public TrackEdge edge; public double position; public boolean blocked; + public boolean upsideDown; public static enum SteerDirection { NONE(0), LEFT(-1), RIGHT(1); @@ -64,11 +65,12 @@ public class TravellingPoint { public TravellingPoint() {} - public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position) { + public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position, boolean upsideDown) { this.node1 = node1; this.node2 = node2; this.edge = edge; this.position = position; + this.upsideDown = upsideDown; } public IEdgePointListener ignoreEdgePoints() { @@ -395,14 +397,22 @@ public class TravellingPoint { } public Vec3 getPosition() { - return getPositionWithOffset(0); + return getPosition(false); + } + + public Vec3 getPosition(boolean flipped) { + return getPositionWithOffset(0, flipped); } public Vec3 getPositionWithOffset(double offset) { + return getPositionWithOffset(offset, false); + } + + public Vec3 getPositionWithOffset(double offset, boolean flipUpsideDown) { double t = (position + offset) / edge.getLength(); return edge.getPosition(t) - .add(edge.getNormal(node1, node2, t) - .scale(1)); + .add(edge.getNormal(node1, node2, t) + .scale(upsideDown^flipUpsideDown ? -1 : 1)); } public void migrateTo(List locations) { @@ -423,12 +433,13 @@ public class TravellingPoint { tag.put("Nodes", nodes.map(TrackNode::getLocation) .serializeEach(loc -> loc.write(dimensions))); tag.putDouble("Position", position); + tag.putBoolean("UpsideDown", upsideDown); return tag; } public static TravellingPoint read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { if (graph == null) - return new TravellingPoint(null, null, null, 0); + return new TravellingPoint(null, null, null, 0, false); Couple locs = tag.contains("Nodes") ? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions)) @@ -436,11 +447,11 @@ public class TravellingPoint { : Couple.create(null, null); if (locs.either(Objects::isNull)) - return new TravellingPoint(null, null, null, 0); + return new TravellingPoint(null, null, null, 0, false); double position = tag.getDouble("Position"); return new TravellingPoint(locs.getFirst(), locs.getSecond(), graph.getConnectionsFrom(locs.getFirst()) - .get(locs.getSecond()), position); + .get(locs.getSecond()), position, tag.getBoolean("UpsideDown")); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java index 9fdb9a96b..5e73be778 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java @@ -21,7 +21,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.ITr import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.logistics.block.depot.DepotBehaviour; import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.TrackEdge; import com.simibubi.create.content.logistics.trains.TrackGraph; @@ -38,6 +38,7 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePoi import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleItem; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.config.AllConfigs; @@ -51,6 +52,7 @@ import com.simibubi.create.foundation.utility.WorldAttached; import com.simibubi.create.foundation.utility.animation.LerpedFloat; import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; +import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos.MutableBlockPos; import net.minecraft.core.Direction; @@ -66,6 +68,7 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; @@ -189,7 +192,8 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable Direction assemblyDirection; int assemblyLength; int[] bogeyLocations; - IBogeyBlock[] bogeyTypes; + AbstractBogeyBlock[] bogeyTypes; + boolean[] upsideDownBogeys; int bogeyCount; @Override @@ -266,14 +270,30 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable return false; BlockPos up = new BlockPos(track.getUpNormal(level, pos, state)); + BlockPos down = new BlockPos(track.getUpNormal(level, pos, state).scale(-1)); int bogeyOffset = pos.distManhattan(edgePoint.getGlobalPosition()) - 1; + if (!isValidBogeyOffset(bogeyOffset)) { - for (int i = -1; i <= 1; i++) { - BlockPos bogeyPos = pos.relative(assemblyDirection, i) - .offset(up); - BlockState blockState = level.getBlockState(bogeyPos); - if (blockState.getBlock() instanceof IBogeyBlock bogey) { - level.setBlock(bogeyPos, bogey.getRotatedBlockState(blockState, Direction.DOWN), 3); + for (boolean upsideDown : Iterate.falseAndTrue) { + for (int i = -1; i <= 1; i++) { + BlockPos bogeyPos = pos.relative(assemblyDirection, i) + .offset(upsideDown ? down : up); + BlockState blockState = level.getBlockState(bogeyPos); + if (!(blockState.getBlock() instanceof AbstractBogeyBlock bogey)) + continue; + BlockEntity be = level.getBlockEntity(bogeyPos); + if (!(be instanceof AbstractBogeyTileEntity oldTE)) + continue; + CompoundTag oldData = oldTE.getBogeyData(); + BlockState newBlock = bogey.getNextSize(oldTE); + if (newBlock.getBlock() == bogey) + player.displayClientMessage(Lang.translateDirect("bogey.style.no_other_sizes") + .withStyle(ChatFormatting.RED), true); + level.setBlock(bogeyPos, newBlock, 3); + BlockEntity newEntity = level.getBlockEntity(bogeyPos); + if (!(newEntity instanceof AbstractBogeyTileEntity newTE)) + continue; + newTE.setBogeyData(oldData); bogey.playRotateSound(level, bogeyPos); return true; } @@ -288,7 +308,9 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable return false; } - BlockPos targetPos = pos.offset(up); + boolean upsideDown = (player.getViewXRot(1.0F) < 0 && (track.getBogeyAnchor(level, pos, state)).getBlock() instanceof AbstractBogeyBlock bogey && bogey.canBeUpsideDown()); + + BlockPos targetPos = upsideDown ? pos.offset(down) : pos.offset(up); if (level.getBlockState(targetPos) .getDestroySpeed(level, targetPos) == -1) { return false; @@ -296,7 +318,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable level.destroyBlock(targetPos, true); - BlockState bogeyAnchor = ProperWaterloggedBlock.withWater(level, track.getBogeyAnchor(level, pos, state), pos); + BlockState bogeyAnchor = track.getBogeyAnchor(level, pos, state); + if (bogeyAnchor.getBlock() instanceof AbstractBogeyBlock bogey) { + bogeyAnchor = bogey.getVersion(bogeyAnchor, upsideDown); + } + bogeyAnchor = ProperWaterloggedBlock.withWater(level, bogeyAnchor, pos); level.setBlock(targetPos, bogeyAnchor, 3); player.displayClientMessage(Lang.translateDirect("train_assembly.bogey_created"), true); SoundType soundtype = bogeyAnchor.getBlock() @@ -370,9 +396,12 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable if (bogeyLocations == null) bogeyLocations = new int[maxBogeyCount]; if (bogeyTypes == null) - bogeyTypes = new IBogeyBlock[maxBogeyCount]; + bogeyTypes = new AbstractBogeyBlock[maxBogeyCount]; + if (upsideDownBogeys == null) + upsideDownBogeys = new boolean[maxBogeyCount]; Arrays.fill(bogeyLocations, -1); Arrays.fill(bogeyTypes, null); + Arrays.fill(upsideDownBogeys, false); for (int i = 0; i < MAX_LENGTH; i++) { if (i == MAX_LENGTH - 1) { @@ -385,10 +414,19 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable } BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos)); - if (potentialBogeyState.getBlock() instanceof IBogeyBlock bogey && bogeyIndex < bogeyLocations.length) { - bogeyTypes[bogeyIndex] = bogey; - bogeyLocations[bogeyIndex] = i; - bogeyIndex++; + BlockPos upsideDownBogeyOffset = new BlockPos(bogeyOffset.getX(), bogeyOffset.getY()*-1, bogeyOffset.getZ()); + if (bogeyIndex < bogeyLocations.length) { + if (potentialBogeyState.getBlock() instanceof AbstractBogeyBlock bogey && !bogey.isUpsideDown(potentialBogeyState)) { + bogeyTypes[bogeyIndex] = bogey; + bogeyLocations[bogeyIndex] = i; + upsideDownBogeys[bogeyIndex] = false; + bogeyIndex++; + } else if ((potentialBogeyState = level.getBlockState(upsideDownBogeyOffset.offset(currentPos))).getBlock() instanceof AbstractBogeyBlock bogey && bogey.isUpsideDown(potentialBogeyState)) { + bogeyTypes[bogeyIndex] = bogey; + bogeyLocations[bogeyIndex] = i; + upsideDownBogeys[bogeyIndex] = true; + bogeyIndex++; + } } currentPos.move(assemblyDirection); @@ -548,7 +586,7 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable return; } - points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge)); + points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge, false)); } secondNode = node; @@ -575,10 +613,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable spacing.add(bogeyLocations[bogeyIndex] - bogeyLocations[bogeyIndex - 1]); CarriageContraption contraption = new CarriageContraption(assemblyDirection); BlockPos bogeyPosOffset = trackPosition.offset(bogeyOffset); + BlockPos upsideDownBogeyPosOffset = trackPosition.offset(new BlockPos(bogeyOffset.getX(), bogeyOffset.getY() * -1, bogeyOffset.getZ())); try { int offset = bogeyLocations[bogeyIndex] + 1; - boolean success = contraption.assemble(level, bogeyPosOffset.relative(assemblyDirection, offset)); + boolean success = contraption.assemble(level, upsideDownBogeys[bogeyIndex] ? upsideDownBogeyPosOffset.relative(assemblyDirection, offset) : bogeyPosOffset.relative(assemblyDirection, offset)); atLeastOneForwardControls |= contraption.hasForwardControls(); contraption.setSoundQueueOffset(offset); if (!success) { @@ -591,24 +630,28 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable return; } - IBogeyBlock typeOfFirstBogey = bogeyTypes[bogeyIndex]; + AbstractBogeyBlock typeOfFirstBogey = bogeyTypes[bogeyIndex]; + boolean firstBogeyIsUpsideDown = upsideDownBogeys[bogeyIndex]; + BlockPos firstBogeyPos = contraption.anchor; + AbstractBogeyTileEntity firstBogeyTileEntity = (AbstractBogeyTileEntity) level.getBlockEntity(firstBogeyPos); CarriageBogey firstBogey = - new CarriageBogey(typeOfFirstBogey, points.get(pointIndex), points.get(pointIndex + 1)); + new CarriageBogey(typeOfFirstBogey, firstBogeyIsUpsideDown, firstBogeyTileEntity.getBogeyData(), points.get(pointIndex), points.get(pointIndex + 1)); CarriageBogey secondBogey = null; BlockPos secondBogeyPos = contraption.getSecondBogeyPos(); int bogeySpacing = 0; if (secondBogeyPos != null) { if (bogeyIndex == bogeyCount - 1 || !secondBogeyPos - .equals(bogeyPosOffset.relative(assemblyDirection, bogeyLocations[bogeyIndex + 1] + 1))) { + .equals((upsideDownBogeys[bogeyIndex + 1] ? upsideDownBogeyPosOffset : bogeyPosOffset).relative(assemblyDirection, bogeyLocations[bogeyIndex + 1] + 1))) { exception(new AssemblyException(Lang.translateDirect("train_assembly.not_connected_in_order")), contraptions.size() + 1); return; } - + AbstractBogeyTileEntity secondBogeyTileEntity = + (AbstractBogeyTileEntity) level.getBlockEntity(secondBogeyPos); bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex]; - secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], points.get(pointIndex + 2), - points.get(pointIndex + 3)); + secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], upsideDownBogeys[bogeyIndex + 1], secondBogeyTileEntity.getBogeyData(), + points.get(pointIndex + 2), points.get(pointIndex + 3)); bogeyIndex++; } else if (!typeOfFirstBogey.allowsSingleBogeyCarriage()) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyTileEntity.java new file mode 100644 index 000000000..8ec37da45 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyTileEntity.java @@ -0,0 +1,119 @@ +package com.simibubi.create.content.logistics.trains.track; + +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; +import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; +import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity; +import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import org.jetbrains.annotations.NotNull; + +import static com.simibubi.create.content.logistics.trains.entity.CarriageBogey.UPSIDE_DOWN_KEY; + +public abstract class AbstractBogeyTileEntity extends CachedRenderBBTileEntity { + public static final String BOGEY_STYLE_KEY = "BogeyStyle"; + public static final String BOGEY_DATA_KEY = "BogeyData"; + + private CompoundTag bogeyData; + + public AbstractBogeyTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + public abstract BogeyStyle getDefaultStyle(); + + public CompoundTag getBogeyData() { + if (this.bogeyData == null || !this.bogeyData.contains(BOGEY_STYLE_KEY)) + this.bogeyData = this.createBogeyData(); + return this.bogeyData; + } + + public void setBogeyData(@NotNull CompoundTag newData) { + if (!newData.contains(BOGEY_STYLE_KEY)) { + ResourceLocation style = getDefaultStyle().name; + NBTHelper.writeResourceLocation(newData, BOGEY_STYLE_KEY, style); + } + this.bogeyData = newData; + } + + public void setBogeyStyle(@NotNull BogeyStyle style) { + ResourceLocation location = style.name; + CompoundTag data = this.getBogeyData(); + NBTHelper.writeResourceLocation(data, BOGEY_STYLE_KEY, location); + markUpdated(); + } + + @NotNull + public BogeyStyle getStyle() { + CompoundTag data = this.getBogeyData(); + ResourceLocation currentStyle = NBTHelper.readResourceLocation(data, BOGEY_STYLE_KEY); + BogeyStyle style = AllBogeyStyles.BOGEY_STYLES.get(currentStyle); + if (style == null) { + setBogeyStyle(getDefaultStyle()); + return getStyle(); + } + return style; + } + + @Override + protected void saveAdditional(@NotNull CompoundTag pTag) { + CompoundTag data = this.getBogeyData(); + if (data != null) pTag.put(BOGEY_DATA_KEY, data); // Now contains style + super.saveAdditional(pTag); + } + + @Override + public void load(CompoundTag pTag) { + if (pTag.contains(BOGEY_DATA_KEY)) + this.bogeyData = pTag.getCompound(BOGEY_DATA_KEY); + else + this.bogeyData = this.createBogeyData(); + super.load(pTag); + } + + private CompoundTag createBogeyData() { + CompoundTag nbt = new CompoundTag(); + NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, getDefaultStyle().name); + boolean upsideDown = false; + if (getBlockState().getBlock() instanceof AbstractBogeyBlock bogeyBlock) + upsideDown = bogeyBlock.isUpsideDown(getBlockState()); + nbt.putBoolean(UPSIDE_DOWN_KEY, upsideDown); + return nbt; + } + + @Override + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().inflate(2); + } + + // Ponder + LerpedFloat virtualAnimation = LerpedFloat.angular(); + + public float getVirtualAngle(float partialTicks) { + return virtualAnimation.getValue(partialTicks); + } + + public void animate(float distanceMoved) { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof AbstractBogeyBlock type)) + return; + double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius()); + double newWheelAngle = (virtualAnimation.getValue() - angleDiff) % 360; + virtualAnimation.setValue(newWheelAngle); + } + + private void markUpdated() { + setChanged(); + Level level = getLevel(); + if (level != null) + getLevel().sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java index 4194b591e..2af5b5f38 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java @@ -1,7 +1,7 @@ package com.simibubi.create.content.logistics.trains.track; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; +import com.simibubi.create.AllTags; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem; import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection; import com.simibubi.create.foundation.networking.AllPackets; @@ -117,7 +117,7 @@ public class CurvedTrackInteraction { if (event.isUseItem()) { ItemStack heldItem = player.getMainHandItem(); Item item = heldItem.getItem(); - if (AllBlocks.TRACK.isIn(heldItem)) { + if (AllTags.AllBlockTags.TRACKS.matches(heldItem)) { player.displayClientMessage(Lang.translateDirect("track.turn_start") .withStyle(ChatFormatting.RED), true); player.swing(InteractionHand.MAIN_HAND); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java index 4d1859325..c488947b1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java @@ -2,7 +2,7 @@ package com.simibubi.create.content.logistics.trains.track; import java.util.function.Supplier; -import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllTags; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.nbt.CompoundTag; @@ -16,7 +16,7 @@ public class PlaceExtendedCurvePacket extends SimplePacketBase { boolean mainHand; boolean ctrlDown; - + public PlaceExtendedCurvePacket(boolean mainHand, boolean ctrlDown) { this.mainHand = mainHand; this.ctrlDown = ctrlDown; @@ -39,7 +39,7 @@ public class PlaceExtendedCurvePacket extends SimplePacketBase { ctx.enqueueWork(() -> { ServerPlayer sender = ctx.getSender(); ItemStack stack = sender.getItemInHand(mainHand ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); - if (!AllBlocks.TRACK.isIn(stack) || !stack.hasTag()) + if (!AllTags.AllBlockTags.TRACKS.matches(stack) || !stack.hasTag()) return; CompoundTag tag = stack.getTag(); tag.putBoolean("ExtendCurve", true); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java index 9db10db41..4e12babab 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java @@ -1,87 +1,35 @@ package com.simibubi.create.content.logistics.trains.track; -import java.util.EnumSet; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllBogeyStyles; import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.content.logistics.trains.entity.BogeyInstance; -import com.simibubi.create.content.logistics.trains.entity.CarriageBogey; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; +import com.simibubi.create.content.logistics.trains.BogeySizes; +import com.simibubi.create.content.logistics.trains.TrackMaterial; +import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; -import com.simibubi.create.foundation.render.CachedBufferer; -import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.Iterate; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -public class StandardBogeyBlock extends Block - implements IBogeyBlock, ITE, ProperWaterloggedBlock, ISpecialBlockItemRequirement { +public class StandardBogeyBlock extends AbstractBogeyBlock implements ITE, ProperWaterloggedBlock, ISpecialBlockItemRequirement { - public static final EnumProperty AXIS = BlockStateProperties.HORIZONTAL_AXIS; - private final boolean large; - - public StandardBogeyBlock(Properties p_i48440_1_, boolean large) { - super(p_i48440_1_); - this.large = large; + public StandardBogeyBlock(Properties props, BogeySizes.BogeySize size) { + super(props, size); registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); } @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(AXIS, WATERLOGGED); - super.createBlockStateDefinition(builder); - } - - static final EnumSet STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST); - static final EnumSet STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH); - - @Override - public EnumSet getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state) { - return state.getValue(BlockStateProperties.HORIZONTAL_AXIS) == Axis.X ? STICKY_X : STICKY_Z; - } - - @Override - public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, - LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { - updateWater(pLevel, pState, pCurrentPos); - return pState; - } - - @Override - public FluidState getFluidState(BlockState pState) { - return fluidState(pState); + public TrackMaterial.TrackType getTrackType(BogeyStyle style) { + return TrackMaterial.TrackType.STANDARD; } @Override @@ -91,7 +39,7 @@ public class StandardBogeyBlock extends Block @Override public double getWheelRadius() { - return (large ? 12.5 : 6.5) / 16d; + return (size == BogeySizes.LARGE ? 12.5 : 6.5) / 16d; } @Override @@ -100,122 +48,8 @@ public class StandardBogeyBlock extends Block } @Override - public boolean allowsSingleBogeyCarriage() { - return true; - } - - @Override - public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst) { - if (upDirection != Direction.UP) - return null; - return defaultBlockState().setValue(AXIS, axisAlongFirst ? Axis.X : Axis.Z); - } - - @Override - public boolean isTrackAxisAlongFirstCoordinate(BlockState state) { - return state.getValue(AXIS) == Axis.X; - } - - @Override - @OnlyIn(Dist.CLIENT) - public void render(BlockState state, float wheelAngle, PoseStack ms, float partialTicks, MultiBufferSource buffers, - int light, int overlay) { - if (state != null) { - ms.translate(.5f, .5f, .5f); - if (state.getValue(AXIS) == Axis.X) - ms.mulPose(Vector3f.YP.rotationDegrees(90)); - } - - ms.translate(0, -1.5 - 1 / 128f, 0); - - VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped()); - BlockState air = Blocks.AIR.defaultBlockState(); - - for (int i : Iterate.zeroAndOne) - CachedBufferer.block(AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, Axis.Z)) - .translate(-.5f, .25f, i * -1) - .centre() - .rotateZ(wheelAngle) - .unCentre() - .light(light) - .renderInto(ms, vb); - - if (large) { - renderLargeBogey(wheelAngle, ms, light, vb, air); - } else { - renderBogey(wheelAngle, ms, light, vb, air); - } - } - - private void renderBogey(float wheelAngle, PoseStack ms, int light, VertexConsumer vb, BlockState air) { - CachedBufferer.partial(AllBlockPartials.BOGEY_FRAME, air) - .scale(1 - 1 / 512f) - .light(light) - .renderInto(ms, vb); - - for (int side : Iterate.positiveAndNegative) { - ms.pushPose(); - CachedBufferer.partial(AllBlockPartials.SMALL_BOGEY_WHEELS, air) - .translate(0, 12 / 16f, side) - .rotateX(wheelAngle) - .light(light) - .renderInto(ms, vb); - ms.popPose(); - } - } - - private void renderLargeBogey(float wheelAngle, PoseStack ms, int light, VertexConsumer vb, BlockState air) { - for (int i : Iterate.zeroAndOne) - CachedBufferer.block(AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, Axis.X)) - .translate(-.5f, .25f, .5f + i * -2) - .centre() - .rotateX(wheelAngle) - .unCentre() - .light(light) - .renderInto(ms, vb); - - CachedBufferer.partial(AllBlockPartials.BOGEY_DRIVE, air) - .scale(1 - 1 / 512f) - .light(light) - .renderInto(ms, vb); - CachedBufferer.partial(AllBlockPartials.BOGEY_PISTON, air) - .translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle))) - .light(light) - .renderInto(ms, vb); - - ms.pushPose(); - CachedBufferer.partial(AllBlockPartials.LARGE_BOGEY_WHEELS, air) - .translate(0, 1, 0) - .rotateX(wheelAngle) - .light(light) - .renderInto(ms, vb); - CachedBufferer.partial(AllBlockPartials.BOGEY_PIN, air) - .translate(0, 1, 0) - .rotateX(wheelAngle) - .translate(0, 1 / 4f, 0) - .rotateX(-wheelAngle) - .light(light) - .renderInto(ms, vb); - ms.popPose(); - } - - @Override - public BogeyInstance createInstance(MaterialManager materialManager, CarriageBogey bogey) { - if (large) { - return new BogeyInstance.Drive(bogey, materialManager); - } else { - return new BogeyInstance.Frame(bogey, materialManager); - } - } - - @Override - public BlockState rotate(BlockState pState, Rotation pRotation) { - return switch (pRotation) { - case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> pState.cycle(AXIS); - default -> pState; - }; + public BogeyStyle getDefaultStyle() { + return AllBogeyStyles.STANDARD; } @Override @@ -233,10 +67,4 @@ public class StandardBogeyBlock extends Block public BlockEntityType getTileEntityType() { return AllTileEntities.BOGEY.get(); } - - @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - return new ItemRequirement(ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack()); - } - } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java index 9a4c8a621..834a1b4c8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java @@ -1,40 +1,19 @@ package com.simibubi.create.content.logistics.trains.track; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity; -import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public class StandardBogeyTileEntity extends CachedRenderBBTileEntity { +public class StandardBogeyTileEntity extends AbstractBogeyTileEntity { public StandardBogeyTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); } @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().inflate(2); + public BogeyStyle getDefaultStyle() { + return AllBogeyStyles.STANDARD; } - - // Ponder - - LerpedFloat virtualAnimation = LerpedFloat.angular(); - - public float getVirtualAngle(float partialTicks) { - return virtualAnimation.getValue(partialTicks); - } - - public void animate(float distanceMoved) { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof IBogeyBlock type)) - return; - double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius()); - double newWheelAngle = (virtualAnimation.getValue() - angleDiff) % 360; - virtualAnimation.setValue(newWheelAngle); - } - } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java index a30072daf..78cc17b3b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java @@ -19,6 +19,13 @@ import java.util.Random; import java.util.Set; import java.util.function.Consumer; +import com.simibubi.create.AllTags; + +import com.simibubi.create.content.logistics.trains.TrackMaterial; + +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; + import org.jetbrains.annotations.Nullable; import com.google.common.base.Predicates; @@ -106,25 +113,30 @@ import net.minecraft.world.ticks.LevelTickAccess; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.IBlockRenderProperties; - +//init public class TrackBlock extends Block implements ITE, IWrenchable, ITrackBlock, ISpecialBlockItemRequirement, ProperWaterloggedBlock { public static final EnumProperty SHAPE = EnumProperty.create("shape", TrackShape.class); public static final BooleanProperty HAS_TE = BooleanProperty.create("turn"); - public TrackBlock(Properties p_49795_) { + protected final TrackMaterial material; + + public TrackBlock(Properties p_49795_, TrackMaterial material) { super(p_49795_); registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO) .setValue(HAS_TE, false) .setValue(WATERLOGGED, false)); + this.material = material; } + + @Override protected void createBlockStateDefinition(Builder p_49915_) { super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TE, WATERLOGGED)); } - + @Override public BlockPathTypes getAiPathNodeType(BlockState state, BlockGetter world, BlockPos pos, Mob entity) { return BlockPathTypes.RAIL; @@ -379,7 +391,7 @@ public class TrackBlock extends Block (d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d) .add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis, - null); + null, (b, v) -> ITrackBlock.getMaterialSimple(world, v)); } else list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo); @@ -395,7 +407,7 @@ public class TrackBlock extends Block Map connections = trackTE.getConnections(); connections.forEach((connectedPos, bc) -> ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get, - b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, null, bc)); + b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, null, bc, (b, v) -> ITrackBlock.getMaterialSimple(world, v, bc.getMaterial()))); if (trackTE.boundLocation == null || !(world instanceof ServerLevel level)) return list; @@ -407,7 +419,7 @@ public class TrackBlock extends Block return list; BlockPos boundPos = trackTE.boundLocation.getSecond(); BlockState boundState = otherLevel.getBlockState(boundPos); - if (!AllBlocks.TRACK.has(boundState)) + if (!AllTags.AllBlockTags.TRACKS.matches(boundState)) return list; Vec3 center = Vec3.atBottomCenterOf(pos) @@ -421,7 +433,7 @@ public class TrackBlock extends Block getTrackAxes(world, pos, state).forEach(axis -> { ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d) .add(b ? center : boundCenter), b -> (b ? shape : boundShape).getNormal(), - b -> b ? level.dimension() : otherLevel.dimension(), axis, null); + b -> b ? level.dimension() : otherLevel.dimension(), axis, null, (b, v) -> ITrackBlock.getMaterialSimple(b ? level : otherLevel, v)); }); return list; @@ -750,7 +762,8 @@ public class TrackBlock extends Block @Override public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - int trackAmount = 1; + int sameTypeTrackAmount = 1; + Object2IntMap otherTrackAmounts = new Object2IntArrayMap<>(); int girderAmount = 0; if (te instanceof TrackTileEntity track) { @@ -758,15 +771,27 @@ public class TrackBlock extends Block .values()) { if (!bezierConnection.isPrimary()) continue; - trackAmount += bezierConnection.getTrackItemCost(); + TrackMaterial material = bezierConnection.getMaterial(); + if (material == getMaterial()) { + sameTypeTrackAmount += bezierConnection.getTrackItemCost(); + } else { + otherTrackAmounts.put(material, otherTrackAmounts.getOrDefault(material, 0) + 1); + } girderAmount += bezierConnection.getGirderItemCost(); } } List stacks = new ArrayList<>(); - while (trackAmount > 0) { - stacks.add(AllBlocks.TRACK.asStack(Math.min(trackAmount, 64))); - trackAmount -= 64; + while (sameTypeTrackAmount > 0) { + stacks.add(new ItemStack(state.getBlock(), Math.min(sameTypeTrackAmount, 64))); + sameTypeTrackAmount -= 64; + } + for (TrackMaterial material : otherTrackAmounts.keySet()) { + int amt = otherTrackAmounts.getOrDefault(material, 0); + while (amt > 0) { + stacks.add(new ItemStack(material.getTrackBlock().get(), Math.min(amt, 64))); + amt -= 64; + } } while (girderAmount > 0) { stacks.add(AllBlocks.METAL_GIRDER.asStack(Math.min(girderAmount, 64))); @@ -776,6 +801,11 @@ public class TrackBlock extends Block return new ItemRequirement(ItemUseType.CONSUME, stacks); } + @Override + public TrackMaterial getMaterial() { + return material; + } + public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler { @Override @Nullable diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java index a8b5929dc..5cd2f93cc 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.track; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.AllTags; import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.track.TrackPlacement.PlacementInfo; import com.simibubi.create.foundation.networking.AllPackets; @@ -111,7 +112,7 @@ public class TrackBlockItem extends BlockItem { return InteractionResult.SUCCESS; stack = player.getMainHandItem(); - if (AllBlocks.TRACK.isIn(stack)) { + if (AllTags.AllBlockTags.TRACKS.matches(stack)) { stack.setTag(null); player.setItemInHand(pContext.getHand(), stack); } @@ -154,7 +155,7 @@ public class TrackBlockItem extends BlockItem { @OnlyIn(Dist.CLIENT) public static void sendExtenderPacket(PlayerInteractEvent.RightClickBlock event) { ItemStack stack = event.getItemStack(); - if (!AllBlocks.TRACK.isIn(stack) || !stack.hasTag()) + if (!AllTags.AllBlockTags.TRACKS.matches(stack) || !stack.hasTag()) return; if (Minecraft.getInstance().options.keySprint.isDown()) AllPackets.channel diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java index 54130e673..dca2e8e1a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java @@ -8,8 +8,8 @@ import java.util.function.Consumer; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; +import com.simibubi.create.AllTags; import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; @@ -162,7 +162,7 @@ public class TrackBlockOutline { .rotateXRadians(angles.x) .translate(-.5, -.125f, -.5); - boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem()); + boolean holdingTrack = AllTags.AllBlockTags.TRACKS.matches(Minecraft.getInstance().player.getMainHandItem()); renderShape(AllShapes.TRACK_ORTHO.get(Direction.SOUTH), ms, vb, holdingTrack ? false : null); ms.popPose(); } @@ -190,7 +190,7 @@ public class TrackBlockOutline { ms.pushPose(); ms.translate(pos.getX() - camPos.x, pos.getY() - camPos.y, pos.getZ() - camPos.z); - boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem()); + boolean holdingTrack = AllTags.AllBlockTags.TRACKS.matches(Minecraft.getInstance().player.getMainHandItem()); TrackShape shape = blockstate.getValue(TrackBlock.SHAPE); boolean isJunction = shape.isJunction(); walkShapes(shape, TransformStack.cast(ms), s -> { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java index 7bb371ede..37cb3b6e0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java @@ -20,6 +20,7 @@ import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles; import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles; +import com.simibubi.create.content.logistics.trains.TrackMaterial; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; @@ -38,7 +39,7 @@ public class TrackInstance extends BlockEntityInstance { @Override public void update() { - if (blockEntity.connections.isEmpty()) + if (blockEntity.connections.isEmpty()) return; remove(); @@ -112,11 +113,13 @@ public class TrackInstance extends BlockEntityInstance { leftLightPos = new BlockPos[segCount]; rightLightPos = new BlockPos[segCount]; - mat.getModel(AllBlockPartials.TRACK_TIE) + TrackMaterial.TrackModelHolder modelHolder = bc.getMaterial().getModelHolder(); + + mat.getModel(modelHolder.tie()) .createInstances(ties); - mat.getModel(AllBlockPartials.TRACK_SEGMENT_LEFT) + mat.getModel(modelHolder.segment_left()) .createInstances(left); - mat.getModel(AllBlockPartials.TRACK_SEGMENT_RIGHT) + mat.getModel(modelHolder.segment_right()) .createInstances(right); SegmentAngles[] segments = bc.getBakedSegments(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java index a34fa562d..adf3e9707 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java @@ -7,12 +7,13 @@ import java.util.List; import java.util.Set; import com.jozufozu.flywheel.util.Color; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.AllTags; import com.simibubi.create.CreateClient; import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer; import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.ITrackBlock; +import com.simibubi.create.content.logistics.trains.TrackMaterial; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.config.AllConfigs; @@ -47,6 +48,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult.Type; @@ -58,6 +60,11 @@ import net.minecraftforge.items.ItemHandlerHelper; public class TrackPlacement { public static class PlacementInfo { + + public PlacementInfo(TrackMaterial material) { + this.trackMaterial = material; + } + BezierConnection curve = null; boolean valid = false; int end1Extent = 0; @@ -69,6 +76,7 @@ public class TrackPlacement { public int requiredPavement = 0; public boolean hasRequiredPavement = false; + public final TrackMaterial trackMaterial; // for visualisation Vec3 end1; @@ -108,7 +116,7 @@ public class TrackPlacement { && hoveringMaxed == maximiseTurn && lookAngle == hoveringAngle) return cached; - PlacementInfo info = new PlacementInfo(); + PlacementInfo info = new PlacementInfo(TrackMaterial.fromItem(stack.getItem())); hoveringMaxed = maximiseTurn; hoveringAngle = lookAngle; hoveringPos = pos2; @@ -192,7 +200,7 @@ public class TrackPlacement { BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z); info.curve = new BezierConnection(Couple.create(targetPos1, targetPos2), Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2), - Couple.create(normal1, normal2), true, girder); + Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem())); } // S curve or Straight @@ -281,10 +289,10 @@ public class TrackPlacement { if (skipCurve && !Mth.equal(ascend, 0)) { int hDistance = info.end1Extent; if (axis1.y == 0 || !Mth.equal(absAscend + 1, dist / axis1.length())) { - + if (axis1.y != 0 && axis1.y == -axis2.y) return info.withMessage("ascending_s_curve"); - + info.end1Extent = 0; double minHDistance = Math.max(absAscend < 4 ? absAscend * 4 : absAscend * 3, 6) / axis1.length(); if (hDistance < minHDistance) @@ -352,7 +360,7 @@ public class TrackPlacement { info.curve = skipCurve ? null : new BezierConnection(Couple.create(targetPos1, targetPos2), Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2), - Couple.create(normal1, normal2), true, girder); + Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem())); info.valid = true; @@ -397,7 +405,7 @@ public class TrackPlacement { continue; ItemStack stackInSlot = (offhand ? inv.offhand : inv.items).get(i); - boolean isTrack = AllBlocks.TRACK.isIn(stackInSlot); + boolean isTrack = AllTags.AllBlockTags.TRACKS.matches(stackInSlot) && stackInSlot.is(stack.getItem()); if (!isTrack && (!shouldPave || offhandItem.getItem() != stackInSlot.getItem())) continue; if (isTrack ? foundTracks >= tracks : foundPavement >= pavement) @@ -445,10 +453,10 @@ public class TrackPlacement { BlockItem paveItem = (BlockItem) offhandItem.getItem(); paveTracks(level, info, paveItem, false); } - + if (info.curve != null && info.curve.getLength() > 29) AllAdvancements.LONG_BEND.awardTo(player); - + return placeTracks(level, info, state1, state2, targetPos1, targetPos2, false); } @@ -474,6 +482,18 @@ public class TrackPlacement { info.requiredPavement += TrackPaver.paveCurve(level, info.curve, block, simulate, visited); } + private static BlockState copyProperties(BlockState from, BlockState onto) { + for (Property property : onto.getProperties()) { + if (from.hasProperty(property)) + onto = onto.setValue(property, from.getValue(property)); + } + return onto; + } + + private static BlockState copyProperties(BlockState from, BlockState onto, boolean keepFrom) { + return keepFrom ? from : copyProperties(from, onto); + } + private static PlacementInfo placeTracks(Level level, PlacementInfo info, BlockState state1, BlockState state2, BlockPos targetPos1, BlockPos targetPos2, boolean simulate) { info.requiredTracks = 0; @@ -501,7 +521,8 @@ public class TrackPlacement { Vec3 offset = axis.scale(i); BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z); BlockState stateAtPos = level.getBlockState(offsetPos); - BlockState toPlace = state; + // copy over all shared properties from the shaped state to the correct track material block + BlockState toPlace = copyProperties(state, info.trackMaterial.getTrackBlock().get().defaultBlockState()); boolean canPlace = stateAtPos.getMaterial() .isReplaceable(); @@ -524,15 +545,16 @@ public class TrackPlacement { return info; if (!simulate) { + BlockState onto = info.trackMaterial.getTrackBlock().get().defaultBlockState(); BlockState stateAtPos = level.getBlockState(targetPos1); level.setBlock(targetPos1, ProperWaterloggedBlock.withWater(level, - (stateAtPos.getBlock() == state1.getBlock() ? stateAtPos : state1).setValue(TrackBlock.HAS_TE, true), - targetPos1), 3); + (AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state1, onto)) + .setValue(TrackBlock.HAS_TE, true), targetPos1), 3); stateAtPos = level.getBlockState(targetPos2); level.setBlock(targetPos2, ProperWaterloggedBlock.withWater(level, - (stateAtPos.getBlock() == state2.getBlock() ? stateAtPos : state2).setValue(TrackBlock.HAS_TE, true), - targetPos2), 3); + (AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state2, onto)) + .setValue(TrackBlock.HAS_TE, true), targetPos2), 3); } BlockEntity te1 = level.getBlockEntity(targetPos1); @@ -579,10 +601,10 @@ public class TrackPlacement { return; InteractionHand hand = InteractionHand.MAIN_HAND; - if (!AllBlocks.TRACK.isIn(stack)) { + if (!AllTags.AllBlockTags.TRACKS.matches(stack)) { stack = player.getOffhandItem(); hand = InteractionHand.OFF_HAND; - if (!AllBlocks.TRACK.isIn(stack)) + if (!AllTags.AllBlockTags.TRACKS.matches(stack)) return; } @@ -621,7 +643,7 @@ public class TrackPlacement { if (bhr.getDirection() == Direction.UP) { Vec3 lookVec = player.getLookAngle(); int lookAngle = (int) (22.5 + AngleHelper.deg(Mth.atan2(lookVec.z, lookVec.x)) % 360) / 8; - + if (!pos.equals(hintPos) || lookAngle != hintAngle) { hints = Couple.create(ArrayList::new); hintAngle = lookAngle; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java index 1ee412ea0..fdb66a005 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java @@ -3,9 +3,6 @@ package com.simibubi.create.content.logistics.trains.track; import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_BOTTOM; import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_MIDDLE; import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_TOP; -import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_LEFT; -import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_RIGHT; -import static com.simibubi.create.AllBlockPartials.TRACK_TIE; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.util.transform.TransformStack; @@ -15,6 +12,7 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles; import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles; +import com.simibubi.create.content.logistics.trains.TrackMaterial; import com.simibubi.create.foundation.render.CachedBufferer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; @@ -66,7 +64,9 @@ public class TrackRenderer extends SafeTileEntityRenderer { SegmentAngles segment = segments[i]; int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition)); - CachedBufferer.partial(TRACK_TIE, air) + TrackMaterial.TrackModelHolder modelHolder = bc.getMaterial().getModelHolder(); + + CachedBufferer.partial(modelHolder.tie(), air) .mulPose(segment.tieTransform.pose()) .mulNormal(segment.tieTransform.normal()) .light(light) @@ -74,7 +74,7 @@ public class TrackRenderer extends SafeTileEntityRenderer { for (boolean first : Iterate.trueAndFalse) { Pose transform = segment.railTransforms.get(first); - CachedBufferer.partial(first ? TRACK_SEGMENT_LEFT : TRACK_SEGMENT_RIGHT, air) + CachedBufferer.partial(first ? modelHolder.segment_left() : modelHolder.segment_right(), air) .mulPose(transform.pose()) .mulNormal(transform.normal()) .light(light) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java index 05431e8fd..317ca94a6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java @@ -9,6 +9,7 @@ import java.util.Set; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllTags; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.logistics.trains.BezierConnection; @@ -112,6 +113,9 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE } public void addConnection(BezierConnection connection) { + // don't replace existing connections with different materials + if (connections.containsKey(connection.getKey()) && connection.equalsSansMaterial(connections.get(connection.getKey()))) + return; connections.put(connection.getKey(), connection); level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); notifyUpdate(); @@ -287,7 +291,7 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE .getLevel(boundLocation.getFirst()); if (otherLevel == null) return; - if (AllBlocks.TRACK.has(otherLevel.getBlockState(boundLocation.getSecond()))) + if (AllTags.AllBlockTags.TRACKS.matches(otherLevel.getBlockState(boundLocation.getSecond()))) otherLevel.destroyBlock(boundLocation.getSecond(), false); } } diff --git a/src/main/java/com/simibubi/create/events/CommonEvents.java b/src/main/java/com/simibubi/create/events/CommonEvents.java index b9a3baa8b..14cf82e86 100644 --- a/src/main/java/com/simibubi/create/events/CommonEvents.java +++ b/src/main/java/com/simibubi/create/events/CommonEvents.java @@ -62,9 +62,11 @@ import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.forgespi.language.IModFileInfo; import net.minecraftforge.forgespi.locating.IModFile; +import net.minecraftforge.registries.NewRegistryEvent; @EventBusSubscriber public class CommonEvents { @@ -90,7 +92,7 @@ public class CommonEvents { ToolboxHandler.playerLogin(player); Create.RAILWAYS.playerLogin(player); } - + @SubscribeEvent public static void playerLoggedOut(PlayerLoggedOutEvent event) { Player player = event.getPlayer(); @@ -166,7 +168,7 @@ public class CommonEvents { public static void onEntityEnterSection(EntityEvent.EnteringSection event) { CarriageEntityHandler.onEntityEnterSection(event); } - + @SubscribeEvent public static void addReloadListeners(AddReloadListenerEvent event) { event.addListener(RecipeFinder.LISTENER); @@ -248,7 +250,5 @@ public class CommonEvents { }); } } - } - } diff --git a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java index 8664b0a5e..676a47d1f 100644 --- a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java +++ b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java @@ -60,6 +60,7 @@ public class AllCommands { .then(CameraDistanceCommand.register()) .then(CameraAngleCommand.register()) .then(FlySpeedCommand.register()) + //.then(DebugValueCommand.register()) //.then(KillTPSCommand.register()) .build(); diff --git a/src/main/java/com/simibubi/create/foundation/command/DebugValueCommand.java b/src/main/java/com/simibubi/create/foundation/command/DebugValueCommand.java new file mode 100644 index 000000000..5272bdc59 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/DebugValueCommand.java @@ -0,0 +1,41 @@ +package com.simibubi.create.foundation.command; + +import com.mojang.brigadier.arguments.FloatArgumentType; + +import com.simibubi.create.Create; + +import net.minecraft.SharedConstants; + +import org.apache.commons.lang3.mutable.MutableInt; + +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.simibubi.create.foundation.utility.Components; + +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.coordinates.BlockPosArgument; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.BaseCommandBlock; +import net.minecraft.world.level.block.CommandBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.CommandBlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public class DebugValueCommand { + + public static float value = 0; + + public static ArgumentBuilder register() { + return Commands.literal("debugValue") + .requires(cs -> cs.hasPermission(4)) + .then(Commands.argument("value", FloatArgumentType.floatArg()) + .executes((ctx) -> { + value = FloatArgumentType.getFloat(ctx, "value"); + ctx.getSource().sendSuccess(Components.literal("Set value to: "+value), true); + return 1; + })); + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/CClient.java b/src/main/java/com/simibubi/create/foundation/config/CClient.java index 4fffd25fe..449c10a3f 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CClient.java +++ b/src/main/java/com/simibubi/create/foundation/config/CClient.java @@ -77,6 +77,7 @@ public class CClient extends ConfigBase { public final ConfigGroup trains = group(1, "trains", Comments.trains); public final ConfigFloat mountedZoomMultiplier = f(3, 0, "mountedZoomMultiplier", Comments.mountedZoomMultiplier); public final ConfigBool showTrackGraphOnF3 = b(false, "showTrackGraphOnF3", Comments.showTrackGraphOnF3); + public final ConfigBool showExtendedTrackGraphOnF3 = b(false, "showExtendedTrackGraphOnF3", Comments.showExtendedTrackGraphOnF3); @Override public String getName() { @@ -147,6 +148,7 @@ public class CClient extends ConfigBase { static String trains = "Railway related settings"; static String mountedZoomMultiplier = "How far away the Camera should zoom when seated on a train"; static String showTrackGraphOnF3 = "Display nodes and edges of a Railway Network while f3 debug mode is active"; + static String showExtendedTrackGraphOnF3 = "Additionally display materials of a Rail Network while f3 debug mode is active"; } } diff --git a/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java b/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java index acf1ce517..c9971fb76 100644 --- a/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java +++ b/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java @@ -33,7 +33,7 @@ import com.simibubi.create.content.curiosities.deco.SlidingDoorMovementBehaviour import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelItem; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; +import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.content.logistics.trains.track.StandardBogeyBlock; import com.simibubi.create.foundation.block.BlockStressDefaults; import com.simibubi.create.foundation.block.ItemUseOverrides; @@ -80,6 +80,7 @@ public class BuilderTransformers { .build(); } + @SuppressWarnings("deprecation") public static NonNullUnaryOperator> bogey() { return b -> b.initialProperties(SharedProperties::softMetal) .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) @@ -88,7 +89,7 @@ public class BuilderTransformers { .blockstate((c, p) -> BlockStateGen.horizontalAxisBlock(c, p, s -> p.models() .getExistingFile(p.modLoc("block/track/bogey/top")))) .loot((p, l) -> p.dropOther(l, AllBlocks.RAILWAY_CASING.get())) - .onRegister(block -> IBogeyBlock.register(RegisteredObjects.getKeyOrThrow(block))); + .onRegister(block -> AbstractBogeyBlock.registerStandardBogey(RegisteredObjects.getKeyOrThrow(block))); } public static NonNullUnaryOperator> trapdoor(boolean orientable) { diff --git a/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java b/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java index e0200c3b5..7a51ce75a 100644 --- a/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java +++ b/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java @@ -16,8 +16,10 @@ import com.simibubi.create.CreateClient; import com.simibubi.create.content.AllSections; import com.simibubi.create.content.contraptions.fluids.VirtualFluid; import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity; +import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; import com.simibubi.create.foundation.block.connected.CTModel; import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; +import com.simibubi.create.foundation.utility.CreateRegistry; import com.simibubi.create.foundation.utility.RegisteredObjects; import com.tterrag.registrate.AbstractRegistrate; import com.tterrag.registrate.builders.BlockBuilder; diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java index ed44673e8..e3905f033 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java @@ -3,6 +3,8 @@ package com.simibubi.create.foundation.ponder.content; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.Create; +import com.simibubi.create.content.logistics.trains.TrackMaterial; +import com.simibubi.create.content.logistics.trains.track.TrackBlock; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.ponder.PonderRegistrationHelper; import com.simibubi.create.foundation.ponder.PonderRegistry; @@ -20,8 +22,15 @@ import com.simibubi.create.foundation.ponder.content.trains.TrainScenes; import com.simibubi.create.foundation.ponder.content.trains.TrainSignalScenes; import com.simibubi.create.foundation.ponder.content.trains.TrainStationScenes; +import com.tterrag.registrate.util.entry.BlockEntry; +import com.tterrag.registrate.util.entry.ItemProviderEntry; + import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.block.Blocks; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; + +import java.util.stream.Collectors; public class PonderIndex { @@ -303,7 +312,12 @@ public class PonderIndex { .addStoryBoard("rose_quartz_lamp", RedstoneScenes2::roseQuartzLamp); // Trains - HELPER.forComponents(AllBlocks.TRACK) + HELPER.forComponents(TrackMaterial.allBlocks().stream() + .map((trackSupplier) -> new BlockEntry( + // note: these blocks probably WON'T be in the Create Registrate, but a simple code trace reveals the Entry's registrate isn't used + Create.REGISTRATE, + RegistryObject.create(trackSupplier.get().getRegistryName(), ForgeRegistries.BLOCKS))) + .toList()) .addStoryBoard("train_track/placement", TrackScenes::placement) .addStoryBoard("train_track/portal", TrackScenes::portal) .addStoryBoard("train_track/chunks", TrackScenes::chunks); diff --git a/src/main/java/com/simibubi/create/foundation/ponder/instruction/AnimateTileEntityInstruction.java b/src/main/java/com/simibubi/create/foundation/ponder/instruction/AnimateTileEntityInstruction.java index cd65b8a36..b11242d80 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/instruction/AnimateTileEntityInstruction.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/instruction/AnimateTileEntityInstruction.java @@ -7,7 +7,7 @@ import java.util.function.Function; import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.IBearingTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; -import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; import com.simibubi.create.foundation.ponder.PonderScene; import com.simibubi.create.foundation.ponder.PonderWorld; @@ -34,7 +34,7 @@ public class AnimateTileEntityInstruction extends TickingInstruction { public static AnimateTileEntityInstruction bogey(BlockPos location, float totalDelta, int ticks) { float movedPerTick = totalDelta / ticks; return new AnimateTileEntityInstruction(location, totalDelta, ticks, - (w, f) -> castIfPresent(w, location, StandardBogeyTileEntity.class) + (w, f) -> castIfPresent(w, location, AbstractBogeyTileEntity.class) .ifPresent(bte -> bte.animate(f.equals(totalDelta) ? 0 : movedPerTick)), (w) -> 0f); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/Iterate.java b/src/main/java/com/simibubi/create/foundation/utility/Iterate.java index e8e541aa1..0e072cf38 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Iterate.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Iterate.java @@ -45,4 +45,13 @@ public class Iterate { public static List hereBelowAndAbove(BlockPos pos) { return Arrays.asList(pos, pos.below(), pos.above()); } + + public static T cycleValue(List list, T current) { + int currentIndex = list.indexOf(current); + if (currentIndex == -1) { + throw new IllegalArgumentException("Current value not found in list"); + } + int nextIndex = (currentIndex + 1) % list.size(); + return list.get(nextIndex); + } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java b/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java index 267a343eb..7bd30cf28 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java @@ -13,6 +13,7 @@ import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.IntTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.AABB; @@ -108,4 +109,12 @@ public class NBTHelper { return new CompoundTag(); } + public static void writeResourceLocation(CompoundTag nbt, String key, ResourceLocation location) { + nbt.putString(key, location.toString()); + } + + public static ResourceLocation readResourceLocation(CompoundTag nbt, String key) { + return new ResourceLocation(nbt.getString(key)); + } + } diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/ItemOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/ItemOutline.java new file mode 100644 index 000000000..7f974cabb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/ItemOutline.java @@ -0,0 +1,51 @@ +package com.simibubi.create.foundation.utility.outliner; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.foundation.render.RenderTypes; +import com.simibubi.create.foundation.render.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; + +import java.util.*; + +public class ItemOutline extends Outline { + + protected Vec3 pos; + protected ItemStack stack; + + public ItemOutline(Vec3 pos, ItemStack stack) { + this.pos = pos; + this.stack = stack; + } + + @Override + public void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt) { + Minecraft mc = Minecraft.getInstance(); + ms.pushPose(); + + TransformStack.cast(ms) + .translate(pos.x - camera.x, pos.y - camera.y, pos.z - camera.z) + .scale(params.alpha); + + mc.getItemRenderer().render(stack, ItemTransforms.TransformType.FIXED, false, ms, + buffer, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, + mc.getItemRenderer().getModel(stack, null, null, 0)); + + ms.popPose(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java index dfeeb7dce..15a21615e 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java @@ -14,6 +14,7 @@ import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; @@ -81,6 +82,13 @@ public class Outliner { // + public OutlineParams showItem(Object slot, Vec3 pos, ItemStack stack) { + ItemOutline outline = new ItemOutline(pos, stack); + OutlineEntry entry = new OutlineEntry(outline); + outlines.put(slot, entry); + return entry.getOutline().getParams(); + } + public void keep(Object slot) { if (outlines.containsKey(slot)) outlines.get(slot).ticksTillRemoval = 1; diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index 86e0d8237..20b959087 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -920,8 +920,14 @@ "create.contraption.minecart_contraption_too_big": "This Cart Contraption seems too big to pick up", "create.contraption.minecart_contraption_illegal_pickup": "A mystical force is binding this Cart Contraption to the world", - + "enchantment.create.capacity.desc": "Increases Backtank air capacity.", - "enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused." + "enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.", + + "create.bogey.style.updated_style": "Updated style", + "create.bogey.style.updated_style_and_size": "Updated style and size", + "create.bogey.style.no_other_sizes": "No other sizes", + "create.bogey.style.invalid": "Unnamed style", + "create.bogey.style.standard": "Standard" } From 2e3101b87a3baa2f4e4ba7f1672b324faf7a6818 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue, 9 May 2023 19:38:03 +0200 Subject: [PATCH 07/22] Fivepointone-ify --- .../java/com/simibubi/create/AllTags.java | 1 + .../logistics/trains/AbstractBogeyBlock.java | 22 +++++++++---------- .../trains/GlobalRailwayManager.java | 2 +- .../trains/StandardBogeyRenderer.java | 17 ++++++-------- .../logistics/trains/TrackMaterial.java | 5 +++-- .../trains/entity/CarriageContraption.java | 2 +- .../logistics/trains/entity/Train.java | 4 ++-- .../edgePoint/station/StationBlockEntity.java | 12 +++++----- .../track/AbstractBogeyBlockEntity.java | 13 ++++++----- 9 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/simibubi/create/AllTags.java b/src/main/java/com/simibubi/create/AllTags.java index 2255e036a..dceb62717 100644 --- a/src/main/java/com/simibubi/create/AllTags.java +++ b/src/main/java/com/simibubi/create/AllTags.java @@ -14,6 +14,7 @@ import net.minecraft.tags.BlockTags; import net.minecraft.tags.FluidTags; import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; +import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java index 3f86c660c..dff97a9ef 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/AbstractBogeyBlock.java @@ -9,6 +9,8 @@ import java.util.Set; import javax.annotation.Nullable; +import org.jetbrains.annotations.NotNull; + import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.mojang.blaze3d.vertex.PoseStack; @@ -22,10 +24,10 @@ import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; import com.simibubi.create.content.logistics.trains.entity.Carriage; import com.simibubi.create.content.logistics.trains.entity.CarriageBogey; import com.simibubi.create.content.logistics.trains.entity.TravellingPoint; -import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyBlockEntity; import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; @@ -59,9 +61,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.registries.ForgeRegistries; -import org.jetbrains.annotations.NotNull; - -public abstract class AbstractBogeyBlock extends Block implements ITE, ProperWaterloggedBlock, ISpecialBlockItemRequirement, IWrenchable { +public abstract class AbstractBogeyBlock extends Block implements IBE, ProperWaterloggedBlock, ISpecialBlockItemRequirement, IWrenchable { public static final EnumProperty AXIS = BlockStateProperties.HORIZONTAL_AXIS; static final List BOGEYS = new ArrayList<>(); public BogeySizes.BogeySize size; @@ -199,7 +199,7 @@ public abstract class AbstractBogeyBlock exte BlockEntity be = level.getBlockEntity(pos); - if (!(be instanceof AbstractBogeyTileEntity sbte)) + if (!(be instanceof AbstractBogeyBlockEntity sbte)) return InteractionResult.FAIL; player.getCooldowns().addCooldown(stack.getItem(), 20); @@ -230,7 +230,7 @@ public abstract class AbstractBogeyBlock exte CompoundTag oldData = sbte.getBogeyData(); level.setBlock(pos, this.getStateOfSize(sbte, size), 3); BlockEntity newBlockEntity = level.getBlockEntity(pos); - if (!(newBlockEntity instanceof AbstractBogeyTileEntity newTileEntity)) + if (!(newBlockEntity instanceof AbstractBogeyBlockEntity newTileEntity)) return InteractionResult.FAIL; newTileEntity.setBogeyData(oldData); player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style_and_size") @@ -278,7 +278,7 @@ public abstract class AbstractBogeyBlock exte public BlockState getNextSize(Level level, BlockPos pos) { BlockEntity te = level.getBlockEntity(pos); - if (te instanceof AbstractBogeyTileEntity sbte) + if (te instanceof AbstractBogeyBlockEntity sbte) return this.getNextSize(sbte); return level.getBlockState(pos); } @@ -304,7 +304,7 @@ public abstract class AbstractBogeyBlock exte return target; } - public BlockState getNextSize(AbstractBogeyTileEntity sbte) { + public BlockState getNextSize(AbstractBogeyBlockEntity sbte) { BogeySizes.BogeySize size = this.getSize(); BogeyStyle style = sbte.getStyle(); BlockState nextBlock = style.getNextBlock(size).defaultBlockState(); @@ -312,7 +312,7 @@ public abstract class AbstractBogeyBlock exte return nextBlock; } - public BlockState getStateOfSize(AbstractBogeyTileEntity sbte, BogeySizes.BogeySize size) { + public BlockState getStateOfSize(AbstractBogeyBlockEntity sbte, BogeySizes.BogeySize size) { BogeyStyle style = sbte.getStyle(); BlockState state = style.getBlockOfSize(size).defaultBlockState(); return copyProperties(sbte.getBlockState(), state); @@ -320,7 +320,7 @@ public abstract class AbstractBogeyBlock exte public BogeyStyle getNextStyle(Level level, BlockPos pos) { BlockEntity te = level.getBlockEntity(pos); - if (te instanceof AbstractBogeyTileEntity sbte) + if (te instanceof AbstractBogeyBlockEntity sbte) return this.getNextStyle(sbte.getStyle()); return getDefaultStyle(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java index d1301a381..046edb367 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java @@ -273,7 +273,7 @@ public class GlobalRailwayManager { } private static boolean isTrackGraphDebugExtended() { - return AllConfigs.CLIENT.showExtendedTrackGraphOnF3.get(); + return AllConfigs.client().showExtendedTrackGraphOnF3.get(); } public GlobalRailwayManager sided(LevelAccessor level) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java index d49625a2f..cfd779dd2 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java @@ -1,10 +1,16 @@ package com.simibubi.create.content.logistics.trains; +import static com.simibubi.create.AllPartialModels.BOGEY_DRIVE; +import static com.simibubi.create.AllPartialModels.BOGEY_FRAME; +import static com.simibubi.create.AllPartialModels.BOGEY_PIN; +import static com.simibubi.create.AllPartialModels.BOGEY_PISTON; +import static com.simibubi.create.AllPartialModels.LARGE_BOGEY_WHEELS; +import static com.simibubi.create.AllPartialModels.SMALL_BOGEY_WHEELS; + import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.util.transform.Transform; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; - import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; import com.simibubi.create.foundation.utility.AngleHelper; @@ -13,15 +19,6 @@ import com.simibubi.create.foundation.utility.Iterate; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; -import org.jetbrains.annotations.Nullable; - -import static com.simibubi.create.AllBlockPartials.LARGE_BOGEY_WHEELS; -import static com.simibubi.create.AllBlockPartials.BOGEY_PIN; -import static com.simibubi.create.AllBlockPartials.BOGEY_DRIVE; -import static com.simibubi.create.AllBlockPartials.BOGEY_PISTON; -import static com.simibubi.create.AllBlockPartials.SMALL_BOGEY_WHEELS; -import static com.simibubi.create.AllBlockPartials.BOGEY_FRAME; - public class StandardBogeyRenderer { public static class CommonStandardBogeyRenderer extends BogeyRenderer.CommonRenderer { @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java index 03794a220..e3136a7f7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java @@ -9,8 +9,8 @@ import java.util.Map; import java.util.function.Supplier; import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.Create; import com.simibubi.create.content.logistics.trains.track.TrackBlock; import com.tterrag.registrate.util.nullness.NonNullSupplier; @@ -139,6 +139,7 @@ public class TrackMaterial { @OnlyIn(Dist.CLIENT) public record TrackModelHolder(PartialModel tie, PartialModel segment_left, PartialModel segment_right) { - static final TrackModelHolder DEFAULT = new TrackModelHolder(AllBlockPartials.TRACK_TIE, AllBlockPartials.TRACK_SEGMENT_LEFT, AllBlockPartials.TRACK_SEGMENT_RIGHT); + static final TrackModelHolder DEFAULT = new TrackModelHolder(AllPartialModels.TRACK_TIE, + AllPartialModels.TRACK_SEGMENT_LEFT, AllPartialModels.TRACK_SEGMENT_RIGHT); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java index cc8df1801..de323e7ec 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java @@ -167,7 +167,7 @@ public class CarriageContraption extends Contraption { bogeys++; if (bogeys == 2) secondBogeyPos = pos; - return Pair.of(new StructureBlockInfo(pos, blockState, captureTE ? getTileEntityNBT(world, pos) : null), + return Pair.of(new StructureBlockInfo(pos, blockState, captureTE ? getBlockEntityNBT(world, pos) : null), captureTE ? world.getBlockEntity(pos) : null); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index e91fc85f5..7190ccfe0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -17,7 +17,7 @@ import java.util.function.Consumer; import javax.annotation.Nullable; -import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; @@ -741,7 +741,7 @@ public class Train { Vec3 bogeyPosition = bogey.getAnchorPosition(); if (bogeyPosition == null) continue; BlockEntity be = level.getBlockEntity(new BlockPos(bogeyPosition)); - if (!(be instanceof AbstractBogeyTileEntity sbte)) + if (!(be instanceof AbstractBogeyBlockEntity sbte)) continue; sbte.setBogeyData(bogey.bogeyData); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlockEntity.java index 7803d7cd5..b162d47ff 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlockEntity.java @@ -39,7 +39,7 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePoi import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleItem; -import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity; +import com.simibubi.create.content.logistics.trains.track.AbstractBogeyBlockEntity; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; @@ -285,7 +285,7 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab if (!(blockState.getBlock() instanceof AbstractBogeyBlock bogey)) continue; BlockEntity be = level.getBlockEntity(bogeyPos); - if (!(be instanceof AbstractBogeyTileEntity oldTE)) + if (!(be instanceof AbstractBogeyBlockEntity oldTE)) continue; CompoundTag oldData = oldTE.getBogeyData(); BlockState newBlock = bogey.getNextSize(oldTE); @@ -294,7 +294,7 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab .withStyle(ChatFormatting.RED), true); level.setBlock(bogeyPos, newBlock, 3); BlockEntity newEntity = level.getBlockEntity(bogeyPos); - if (!(newEntity instanceof AbstractBogeyTileEntity newTE)) + if (!(newEntity instanceof AbstractBogeyBlockEntity newTE)) continue; newTE.setBogeyData(oldData); bogey.playRotateSound(level, bogeyPos); @@ -636,7 +636,7 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab AbstractBogeyBlock typeOfFirstBogey = bogeyTypes[bogeyIndex]; boolean firstBogeyIsUpsideDown = upsideDownBogeys[bogeyIndex]; BlockPos firstBogeyPos = contraption.anchor; - AbstractBogeyTileEntity firstBogeyTileEntity = (AbstractBogeyTileEntity) level.getBlockEntity(firstBogeyPos); + AbstractBogeyBlockEntity firstBogeyTileEntity = (AbstractBogeyBlockEntity) level.getBlockEntity(firstBogeyPos); CarriageBogey firstBogey = new CarriageBogey(typeOfFirstBogey, firstBogeyIsUpsideDown, firstBogeyTileEntity.getBogeyData(), points.get(pointIndex), points.get(pointIndex + 1)); CarriageBogey secondBogey = null; @@ -650,8 +650,8 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab contraptions.size() + 1); return; } - AbstractBogeyTileEntity secondBogeyTileEntity = - (AbstractBogeyTileEntity) level.getBlockEntity(secondBogeyPos); + AbstractBogeyBlockEntity secondBogeyTileEntity = + (AbstractBogeyBlockEntity) level.getBlockEntity(secondBogeyPos); bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex]; secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], upsideDownBogeys[bogeyIndex + 1], secondBogeyTileEntity.getBogeyData(), points.get(pointIndex + 2), points.get(pointIndex + 3)); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyBlockEntity.java index 8ec37da45..548e99151 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/AbstractBogeyBlockEntity.java @@ -1,9 +1,13 @@ package com.simibubi.create.content.logistics.trains.track; +import static com.simibubi.create.content.logistics.trains.entity.CarriageBogey.UPSIDE_DOWN_KEY; + +import org.jetbrains.annotations.NotNull; + import com.simibubi.create.AllBogeyStyles; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; -import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity; +import com.simibubi.create.foundation.blockEntity.CachedRenderBBBlockEntity; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.animation.LerpedFloat; @@ -14,17 +18,14 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; -import org.jetbrains.annotations.NotNull; -import static com.simibubi.create.content.logistics.trains.entity.CarriageBogey.UPSIDE_DOWN_KEY; - -public abstract class AbstractBogeyTileEntity extends CachedRenderBBTileEntity { +public abstract class AbstractBogeyBlockEntity extends CachedRenderBBBlockEntity { public static final String BOGEY_STYLE_KEY = "BogeyStyle"; public static final String BOGEY_DATA_KEY = "BogeyData"; private CompoundTag bogeyData; - public AbstractBogeyTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { + public AbstractBogeyBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); } From fe713b1966fdfbd617460a39339ce1b91b70beb6 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 10 May 2023 11:11:36 +0200 Subject: [PATCH 08/22] Squashed commit of the following: commit 4323a7133ae29f204bfc34b373ef4946a435e775 Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed May 10 10:58:12 2023 +0200 Deferred validBlocks() option for block entities commit b79330f4efe14746f0c2b35f13469862e148f88c Merge: 053dd09df 7cc35698a Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed May 10 10:23:33 2023 +0200 Merge branch '1.18/api' of https://github.com/Layers-of-Railways/Create into pr/4692 commit 7cc35698ae2e26118daa8e2e21e2f8bb660ff633 Merge: bae824487 ecc645eba Author: techno-sam Date: Tue May 9 20:15:15 2023 -0700 Merge remote-tracking branch 'origin/1.18/api' into 1.18/api commit bae8244873bf20148cd29161a03320831b94018f Author: techno-sam Date: Tue May 9 20:15:00 2023 -0700 resolve review issues commit b1bffbf7fde7d9d3f69df87c28c95619d7597e80 Author: techno-sam Date: Tue May 9 19:46:58 2023 -0700 clean up testing residue commit 053dd09df6c426ab5e570f42a1edb5df3d0fbd01 Merge: 6d1e1c71d ecc645eba Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue May 9 18:22:42 2023 +0200 Merge branch '1.18/api' of https://github.com/Layers-of-Railways/Create into pr/4692 commit ecc645eba7bfd5f86b9bfb16ee1236a5d6432d3d Author: Rabbitminers Date: Tue May 9 11:24:11 2023 +0100 Implemented support for creating and removing individual blockstate models commit 6d1e1c71de7ce20f6fd9fc8ed4ed9bdd1072829a Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue May 9 12:16:54 2023 +0200 Less error logging when migrating old worlds commit 205e47352ec46f8e300167db69023c7938a52b58 Author: techno-sam Date: Mon May 8 21:02:19 2023 -0700 Fix up ItemOutline commit 6cf204f6afd12671060d198d5a09efe9cd04c7b5 Merge: fe049bc77 2e3c906ce Author: techno-sam Date: Mon May 8 20:28:56 2023 -0700 Merge remote-tracking branch 'upstream/mc1.18/dev' into 1.18/api # Conflicts: # src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java commit fe049bc771cc3a4dd91f5c91f098aa7448af6c8d Author: techno-sam Date: Mon May 8 20:26:16 2023 -0700 Revert "Revert "Rewrite outline buffering"" This reverts commit 726bfaf0 commit 435b4c1c16153e30740d6878cf1f676b7a442c19 Author: techno-sam Date: Mon May 8 20:20:23 2023 -0700 Clean up last bits of upside down rendering commit 662da6bab1f6ad96a4fa05c9ff8538080ac69ac2 Merge: 122fe77af d83285e8a Author: techno-sam Date: Mon May 8 20:16:32 2023 -0700 Merge remote-tracking branch 'origin/1.18/api' into 1.18/api # Conflicts: # src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java commit 122fe77afa2df18dde7afe0bc6aee536f33b18bd Author: techno-sam Date: Mon May 8 20:15:46 2023 -0700 Fix up upside down rendering commit d83285e8a4da5fcb6900c032e6bd8cd59f81bde8 Merge: 00e953a58 cdb0ad210 Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Sun May 7 07:02:18 2023 -0700 Merge pull request #3 from Layers-of-Railways/1.18/bogey-api Cleanup cycle groups and unused imports commit cdb0ad210b7c984b9fcfbecae8a2a0ebf052eb9d Author: Rabbitminers Date: Sun May 7 10:15:47 2023 +0100 Fixed merge artifact commit 457d5f33ed05075dbd0ffc38c17d3135b494dc26 Merge: 4e4e227a3 00e953a58 Author: Rabbitminers Date: Sun May 7 10:14:07 2023 +0100 Merge remote-tracking branch 'origin/1.18/api' into 1.18/api commit 00e953a585bd8e146b6304a19cebd174404ab1c3 Merge: 1e4d5504e a7a25896c Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Sun May 7 10:13:49 2023 +0100 Merge pull request #2 from Rabbitminers/mc1.18/dev Added Return Values and Small Cleanup commit a7a25896c1a5a0a353400ed329a46a461347553e Merge: 7622128be 1e4d5504e Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Sun May 7 10:13:40 2023 +0100 Merge branch '1.18/api' into mc1.18/dev commit 4e4e227a351cb7f70aa4476bebfad1c0e963b561 Author: Rabbitminers Date: Sun May 7 10:10:30 2023 +0100 Cleanup to cycle groups commit aa94fc97d154dcdcaaaa5b4d5e8311af9470d38a Author: Rabbitminers Date: Sun May 7 09:50:50 2023 +0100 Removed unused import of Railways commit 7622128bec17931ea4029792d62c645d0f354e5f Merge: 81eeadb85 d52065808 Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Sun May 7 09:11:59 2023 +0100 Merge branch 'Layers-of-Railways:mc1.18/dev' into mc1.18/dev commit 1e4d5504ee4fe32d655e08acbeb6c492b5e8bb0b Author: techno-sam Date: Sat May 6 18:03:39 2023 -0700 Don't revert non-buggy changes commit b306cf212471f2842311af071dc6b595cbf79216 Author: techno-sam Date: Sat May 6 18:00:59 2023 -0700 Take materials into consideration when trains pathfind commit fca02ae4bfade6f839533c11785cc3e56332f463 Author: techno-sam Date: Sat May 6 10:25:51 2023 -0700 Add materials to track graph commit 726bfaf0b5226a657b45ce4bd1aa365d891a27a4 Author: techno-sam Date: Fri May 5 21:16:49 2023 -0700 Revert "Rewrite outline buffering" This reverts commit d4106d545b0381c3bec304e727a136ea105a8468. commit 171897bed25ed8f7ad3999c8527bb649bb932c81 Author: techno-sam Date: Fri May 5 20:55:25 2023 -0700 Fix up style cycling commit cbd0cf20da482851f98f5312cbc40770a6c14f16 Author: techno-sam Date: Fri May 5 07:32:06 2023 -0700 clean up nether portal carriage handling commit d556f0887632664126a2e10cbb1c8fc6d37e2582 Author: techno-sam Date: Fri May 5 07:06:02 2023 -0700 upside down bogeys work in nether portals fixed coupling anchor offsets commit da26c0ccbf26b892013f6e365556eea6952009f2 Author: techno-sam Date: Thu May 4 09:32:53 2023 -0700 working on upside down bogeys in nether portals commit 81eeadb8532599d482f2259e58cedeaa602e8628 Author: Rabbitminers Date: Mon May 1 16:15:28 2023 +0100 Small cleanup commit c7e9df973cf3d0dab15992d06e6a51985d305ba8 Author: Rabbitminers Date: Mon May 1 16:13:51 2023 +0100 Fixed issue raised in #1 commit 2f285b6eb7341879899895b1c5bbadd0137abb83 Author: techno-sam Date: Mon May 1 08:13:27 2023 -0700 add data gen commit 206de013111a879de133f62846e4f10d7228ea0a Merge: e91753a33 6564f4fa7 Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Mon May 1 06:49:21 2023 -0700 Merge pull request #1 from Rabbitminers/mc1.18/dev Bogey API commit 6564f4fa730f71920552fd2ad6f2c8255df69995 Merge: e5d759582 e91753a33 Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Mon May 1 10:40:32 2023 +0100 Merge branch '1.18/api' into mc1.18/dev commit e5d759582279b3a761c7011174ec77119f4f4f93 Author: Rabbitminers Date: Mon May 1 10:09:03 2023 +0100 Connected Custom Bogey Particle Types To CarriageParticles commit e91753a33cde6dbe0caaface45a7f377d75acbed Author: techno-sam Date: Sun Apr 30 19:51:26 2023 -0700 Fix up some problems commit 9815f1490f9d540986f85f49f297e2f014c312c4 Author: Rabbitminers Date: Sun Apr 30 21:12:43 2023 +0100 Implemented default data when shifting styles commit da30e78815afd7906ea82a9fba293f202c036fa8 Author: Rabbitminers Date: Sun Apr 30 21:12:14 2023 +0100 Added Particles To Bogey Style (And Respective Builder) commit 08c000b8ba302a1c14f7479e70445e2c6d360bc3 Author: Rabbitminers Date: Sun Apr 30 21:01:19 2023 +0100 Added Backup Rendering If A Size Is Not Present commit 2b76e8d7b3b8d88355868ea31d4b6e3df11a7169 Author: Rabbitminers Date: Sun Apr 30 21:00:40 2023 +0100 Added Common Renderer To Remove Function commit 411ec36f573a570284b2bda566d8a006550983e8 Author: Rabbitminers Date: Sun Apr 30 20:59:50 2023 +0100 Added Display Name To Standard Bogey Style commit 112306d5d49db10176d091f1f2ece893afb274dd Author: Rabbitminers Date: Sun Apr 30 20:59:30 2023 +0100 Displayed new style name when changing betweeen them commit 5634670b2750a2df5dfee6de3f93bc895391300d Author: Rabbitminers Date: Sun Apr 30 20:06:00 2023 +0100 General Cleanup commit 0f7a8b7b24ef25c4266fc88f82995b609087904e Author: Rabbitminers Date: Sun Apr 30 20:05:50 2023 +0100 Implemented Changes To Remaining Classes commit 8aedc00f963413ac0a02335bc9f914d45a82b4de Author: Rabbitminers Date: Sun Apr 30 20:02:06 2023 +0100 Removed Bogey Style Handling From Registrate commit edf8079abf9750dc9f3ccf1aedf58fef80428385 Author: Rabbitminers Date: Sun Apr 30 20:01:40 2023 +0100 Removed Unused Registry Handling commit 6a185c4e727ecf55183cb885b109c0f5c5319854 Author: Rabbitminers Date: Sun Apr 30 20:01:16 2023 +0100 Refactored Bogey Sizes commit e10d07ddc3b70cfa6f4a210aa9a9e6bcc6200b7f Author: Rabbitminers Date: Sun Apr 30 20:01:00 2023 +0100 Overhauled Bogey Style commit 74d98a2ad538e2b9d35fdfd2270a14597d29f957 Merge: e629d02f5 4ebcf8201 Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Sun Apr 23 07:16:33 2023 -0700 Merge branch 'Creators-of-Create:mc1.18/dev' into 1.18/api commit e629d02f505c7de2d786a126fe49168351f17124 Author: techno-sam Date: Sun Apr 9 07:18:22 2023 -0700 Track API Clean up code a bit commit d9ce6ce995128e64d079145b96273235c4fec783 Author: techno-sam Date: Sun Apr 9 07:14:46 2023 -0700 Track API? Fix placement commit 7fbf08ba54ce3397045a8acdd6b7be813009ee7b Author: techno-sam Date: Sat Apr 8 11:11:24 2023 -0700 Track API? Fix up some placement issues commit 35644f143426bc2cae1a63c4f09d7145a4e18983 Author: techno-sam Date: Sat Apr 8 08:11:13 2023 -0700 Track API maybe? Datagen Seems to be working commit f7c56b867a6afe52fa742f4d4c310db9788cc2ef Author: techno-sam Date: Thu Apr 6 21:24:31 2023 -0700 Track API maybe? Fix build - broken generic Not yet tested, but it is progress commit 2a59fd7e8ab91a6004abe4b92152a2a936a22c1b Author: techno-sam Date: Thu Apr 6 21:13:54 2023 -0700 Track API maybe? Not yet tested, but it is progress commit 5ba30d6a85dd2cfa49434cb55a25b258b02a9665 Merge: e4e5ac1c4 c2977bbff Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Thu Apr 6 17:10:39 2023 -0700 Merge branch 'Creators-of-Create:mc1.18/dev' into 1.18/api commit d52065808c5d250e6aec35878a5349be563c1d24 Merge: e4e5ac1c4 c2977bbff Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Thu Apr 6 17:10:26 2023 -0700 Merge branch 'Creators-of-Create:mc1.18/dev' into mc1.18/dev commit 53240bd42f08d839b233a3b75cb59aabb4648fb9 Author: Rabbitminers Date: Mon Apr 3 21:42:29 2023 +0100 Corrected Bogey InteractionResult To Pass commit 69326e361ab7d982a577f1e864c772967ad9c134 Author: Rabbitminers Date: Mon Apr 3 21:30:28 2023 +0100 Fixed Default Values When Used Styles Are Removed commit 4f176979de161c35d6c7b07744bf0b982490f49f Author: Rabbitminers Date: Mon Apr 3 19:33:17 2023 +0100 Fixed Carriage Sounds (Again) commit 1e80af3303e5bf9f9179857944cc233b4be7ebaf Author: Rabbitminers Date: Mon Apr 3 19:27:58 2023 +0100 Refactored Bogey Sizes To Seperate Class commit 129be61fee13e15e17c2e2a4ee0b08c9bc004846 Author: Rabbitminers Date: Mon Apr 3 17:20:17 2023 +0100 Fixed Bogey Sound Loading commit 2543185a55a60197494850582ca45d729e463f40 Author: Rabbitminers Date: Mon Apr 3 09:45:23 2023 +0100 Added Bogey Sound Customisation commit 1ad5ae95143f5240fcb83448a99a3924e6d96ce8 Author: Rabbitminers Date: Mon Apr 3 00:44:53 2023 +0100 Added Size Transforms If Size Is Not Available For New Style commit 96566b161441928f2b419340796a27631e1aeb91 Author: Rabbitminers Date: Sun Apr 2 23:02:02 2023 +0100 Moved Bogey Style Inside Of Bogey Data And Implemented Bogey Data Communication commit eedd98473807f1261c7d5edaf0a222c081b57e69 Author: Rabbitminers Date: Sun Apr 2 16:53:55 2023 +0100 Fixed Large Bogey Size commit 68ca0974c6867e61980990a345634963079faf10 Author: Rabbitminers Date: Sun Apr 2 16:47:58 2023 +0100 Implemented Style Cycling & Default Values commit a55ba4267a5fd01ec77e9d826a01f0157c3a1271 Author: Rabbitminers Date: Sun Apr 2 16:46:15 2023 +0100 Implemented renderer instance creator commit 43523302c22d5da374d71c69499269eb8c98dadf Author: Rabbitminers Date: Sun Apr 2 16:45:33 2023 +0100 Removed Unused Standard Bogey Instance commit 773e084422d5cba7e0c599c4e9e9199252e843a3 Merge: 0c0b5a1ed d1e1f7ec5 Author: Rabbitminers Date: Sat Apr 1 18:50:15 2023 +0100 Merge remote-tracking branch 'origin/mc1.18/dev' into mc1.18/dev # Conflicts: # src/main/java/com/simibubi/create/AllBogeyStyles.java # src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java # src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java # src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java # src/main/java/com/simibubi/create/content/logistics/trains/entity/StandardBogeyInstance.java # src/main/java/com/simibubi/create/foundation/data/BogeyStyleBuilder.java commit 0c0b5a1ed65c5f425265b340772b1177a309c46d Author: Rabbitminers Date: Sat Apr 1 18:39:58 2023 +0100 Linked Style Registry To Bogey Blocks commit 71f839ee51c4d609a19fe57632fb2e8fb0d2e5b7 Author: Rabbitminers Date: Sat Apr 1 18:39:03 2023 +0100 Replaced size boolean with direct use of size enum commit 50ff0817045029c721a0a5e38956b3ecd228e52f Author: Rabbitminers Date: Thu Mar 30 18:47:13 2023 +0100 Added Resource Location To NBT helper methods commit d1e1f7ec5abeb825a3170a8f6972ffae43d58381 Author: Rabbitminers Date: Thu Mar 30 18:47:13 2023 +0100 Re-worked BogeyStyles commit da593fccb1cb95232290289775affd097153e30d Author: Rabbitminers Date: Thu Mar 30 18:46:02 2023 +0100 Refactored IBogeyBlock to AbstractBogeyBlock and extracted relevant StandardBogeyBlock implementations commit 17432c911342b1d4937a8d2d22d50a58296639e6 Author: Rabbitminers Date: Sat Mar 25 10:20:50 2023 +0000 Fixed Incorrect Registry Loading commit c7d899369a4ad1a9962ed18c2ab02f58c985f5ae Author: Rabbitminers Date: Fri Mar 24 23:44:03 2023 +0000 Registered Registers commit 6d862290d71b24b1d841444fa21dcb44ecc0d6c7 Author: Rabbitminers Date: Fri Mar 24 23:43:23 2023 +0000 Added BogeyStyleBuilder To Registrate commit 3dfb9e3b3b4b7cec3833b65838ce9523b0cf7666 Author: Rabbitminers Date: Fri Mar 24 23:43:08 2023 +0000 Implemented AllBogeyStyles commit c9e71b462d00e138778f3064bfcc3549a6f28f22 Author: Rabbitminers Date: Fri Mar 24 23:42:56 2023 +0000 Created BogeyStyleBuilder commit a90977d6429657ade13c889d90ec8cd733f176e9 Author: Rabbitminers Date: Fri Mar 24 23:42:25 2023 +0000 Created AllRegistries and BogeyStyle Registry commit 154d455f3fbdef3000ad3e35e88b0909b66c69f8 Author: Rabbitminers Date: Fri Mar 24 23:41:56 2023 +0000 Added BogeyStyle Wrapper commit dfb7640bfc9850604c4ce05ff56338a4e2bbe2fa Author: Rabbitminers Date: Thu Mar 23 18:50:41 2023 +0000 Removed left over logging statement commit 9920536cc319897a89dc1fc974c67cd0975fbcfd Author: Rabbitminers Date: Thu Mar 23 18:50:18 2023 +0000 Implemented Secondary Shaft To Large Renderer commit 6cd40cc6f982226f2bbb9e04e3b8241f9cc36cb5 Author: Rabbitminers Date: Thu Mar 23 18:49:56 2023 +0000 Prevented Overwrite When Using Two BlockStates Of The Same Type With Different Properties commit 06fb901144de8d8df5b907e6261c76a018468f7d Author: Rabbitminers Date: Thu Mar 23 18:39:11 2023 +0000 Implemented Common Rendering For StandardBogeyRenderer commit 435b0f826663284f6544c034217516e36a0687d8 Author: Rabbitminers Date: Thu Mar 23 18:38:40 2023 +0000 Added Common Renderer commit 96a0623dab84d7062a0871ddacabf4342e568867 Author: Rabbitminers Date: Thu Mar 23 18:38:29 2023 +0000 Implemented BlockState Models For Rendering commit 469d9d592b9aa925b26b1206a4ad03d73d422a92 Author: Rabbitminers Date: Thu Mar 23 17:42:28 2023 +0000 Added Standard Bogey Instance (Might be redundant) commit 2661d260d8c21e57df751b17812d89919713120f Author: Rabbitminers Date: Thu Mar 23 17:42:06 2023 +0000 Refactored Changes To Existing Methods commit 9ded16fbabb38e3415cc7b5452cbaea1bef98f61 Author: Rabbitminers Date: Thu Mar 23 17:41:15 2023 +0000 Integrated BogeyRenderer To BogeyInstance (Also Corrected Rendering In Contraption) commit 4a82fcbca1002267fc70998e7ac9c22cd92de52e Author: Rabbitminers Date: Thu Mar 23 17:40:13 2023 +0000 Implemented Changes To StandardBogeyBlock commit 7238fb93f3d0fed43b091f44fd30814e505c544c Author: Rabbitminers Date: Thu Mar 23 17:39:51 2023 +0000 Added Renderer To IBogeyBlock commit ded4c1f613cb33ae29b6bf631eb49abd2ec037f4 Merge: 91727cc84 3c02fe6ec Author: Rabbitminers Date: Wed Mar 22 17:03:37 2023 +0000 Merge remote-tracking branch 'origin/mc1.18/dev' into mc1.18/dev commit 91727cc84a12b2fd27b1ce6e0d67bd182e34880b Author: Rabbitminers Date: Wed Mar 22 17:03:28 2023 +0000 Implemented Model Data Initializer to StandardBogeyRenderer commit 6d98a1f46942d319729c2d61451da462f4188167 Author: Rabbitminers Date: Wed Mar 22 17:03:00 2023 +0000 Added Contraption Model Instance Initializer commit 3c02fe6ecc0c20f1c8ba6bd2ffd2334c2d9d9d73 Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Tue Mar 21 22:45:34 2023 +0000 Added missing render type check commit 6672c49649026e6a6f9a71d9a0bc9411016bcfce Author: Rabbitminers Date: Tue Mar 21 22:37:36 2023 +0000 Re-created standard bogey with test api commit a8a9491fa07777218c7de3fe780ae17e05d5ac03 Author: Rabbitminers Date: Tue Mar 21 22:34:54 2023 +0000 Implemented Proof Of Concept Generic Bogey Renderer commit e4e5ac1c40cadb708429018dc17439eca87ee74e Author: SpottyTheTurtle <69260662+SpottyTheTurtle@users.noreply.github.com> Date: Sat Mar 11 21:34:59 2023 +0000 init --- .../com/simibubi/create/AllTileEntities.java | 2 +- .../tools/BlueprintOverlayRenderer.java | 2 +- .../logistics/trains/BezierConnection.java | 6 +- .../content/logistics/trains/BogeySizes.java | 2 +- .../trains/TrackGraphVisualizer.java | 13 +--- .../logistics/trains/TrackMaterial.java | 62 +++++++++++++------ .../trains/TrackMaterialFactory.java | 19 ++++-- .../logistics/trains/track/TrackBlock.java | 2 +- .../trains/track/TrackPlacement.java | 4 +- .../data/CreateTileEntityBuilder.java | 37 +++++++++-- .../ponder/content/PonderIndex.java | 18 +++--- 11 files changed, 110 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index a6f0f7456..889856947 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -785,8 +785,8 @@ public class AllTileEntities { public static final BlockEntityEntry TRACK = REGISTRATE .tileEntity("track", TrackTileEntity::new) .instance(() -> TrackInstance::new) + .validBlocksDeferred(TrackMaterial::allBlocks) .renderer(() -> TrackRenderer::new) - .validBlocks((NonNullSupplier[]) TrackMaterial.allBlocks().toArray(new NonNullSupplier[0])) .register(); public static final BlockEntityEntry FAKE_TRACK = REGISTRATE diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java index a3aec3eab..a7058a785 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java @@ -105,7 +105,7 @@ public class BlueprintOverlayRenderer { int tracks = info.requiredTracks; while (tracks > 0) { - ingredients.add(Pair.of(new ItemStack(info.trackMaterial.getTrackBlock().get(), Math.min(64, tracks)), info.hasRequiredTracks)); + ingredients.add(Pair.of(new ItemStack(info.trackMaterial.getBlock(), Math.min(64, tracks)), info.hasRequiredTracks)); tracks -= 64; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java b/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java index a65cdb8f6..992f670ae 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java @@ -322,7 +322,7 @@ public class BezierConnection implements Iterable { Inventory inv = player.getInventory(); int tracks = getTrackItemCost(); while (tracks > 0) { - inv.placeItemBackInInventory(new ItemStack(getMaterial().getTrackBlock().get(), Math.min(64, tracks))); + inv.placeItemBackInInventory(new ItemStack(getMaterial().getBlock(), Math.min(64, tracks))); tracks -= 64; } int girders = getGirderItemCost(); @@ -350,7 +350,7 @@ public class BezierConnection implements Iterable { continue; Vec3 v = VecHelper.offsetRandomly(segment.position, level.random, .125f) .add(origin); - ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, new ItemStack(getMaterial().getTrackBlock().get())); + ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, getMaterial().asStack()); entity.setDefaultPickUpDelay(); level.addFreshEntity(entity); if (!hasGirder) @@ -364,7 +364,7 @@ public class BezierConnection implements Iterable { } public void spawnDestroyParticles(Level level) { - BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, getMaterial().getTrackBlock().get().defaultBlockState()); + BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, getMaterial().getBlock().defaultBlockState()); BlockParticleOption girderData = new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.METAL_GIRDER.getDefaultState()); if (!(level instanceof ServerLevel slevel)) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java b/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java index 95bf3a5c8..41fc13344 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BogeySizes.java @@ -48,7 +48,7 @@ public class BogeySizes { return BOGEY_SIZES.size(); } - public record BogeySize(ResourceLocation location, Float wheelRadius) { + public record BogeySize(ResourceLocation location, float wheelRadius) { public BogeySize(String modId, String name, float wheelRadius) { this(new ResourceLocation(modId, name), wheelRadius); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java index bc2c24241..94216ec4d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java @@ -5,15 +5,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.UUID; -import com.mojang.blaze3d.vertex.PoseStack; - -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.world.item.ItemStack; - -import net.minecraft.world.item.Items; - -import net.minecraft.world.level.block.Blocks; - import org.lwjgl.glfw.GLFW; import com.simibubi.create.AllKeys; @@ -274,7 +265,7 @@ public class TrackGraphVisualizer { if (extended) { Vec3 materialPos = edge.getPosition(0.5).add(0, 1, 0); CreateClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos, - new ItemStack(edge.getTrackMaterial().trackBlock.get().get())); + edge.getTrackMaterial().asStack()); CreateClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, 1, 1, 1)) .colored(graph.color); } @@ -292,7 +283,7 @@ public class TrackGraphVisualizer { if (extended) { Vec3 materialPos = edge.getPosition(0.5).add(0, 1, 0); CreateClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos, - new ItemStack(edge.getTrackMaterial().trackBlock.get().get())); + edge.getTrackMaterial().asStack()); CreateClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, 1, 1, 1)) .colored(graph.color); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java index 03794a220..3eb571bca 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterial.java @@ -8,6 +8,8 @@ import java.util.List; import java.util.Map; import java.util.function.Supplier; +import org.jetbrains.annotations.Nullable; + import com.jozufozu.flywheel.core.PartialModel; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; @@ -18,7 +20,9 @@ import com.tterrag.registrate.util.nullness.NonNullSupplier; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -42,6 +46,9 @@ public class TrackMaterial { public final ResourceLocation particle; public final TrackType trackType; + @Nullable + private final TrackMaterial.TrackType.TrackBlockFactory customFactory; + @OnlyIn(Dist.CLIENT) protected TrackModelHolder modelHolder; @@ -53,6 +60,13 @@ public class TrackMaterial { public TrackMaterial(ResourceLocation id, String langName, NonNullSupplier> trackBlock, ResourceLocation particle, Ingredient sleeperIngredient, Ingredient railsIngredient, TrackType trackType, Supplier> modelHolder) { + this(id, langName, trackBlock, particle, sleeperIngredient, railsIngredient, trackType, modelHolder, null); + } + + public TrackMaterial(ResourceLocation id, String langName, NonNullSupplier> trackBlock, + ResourceLocation particle, Ingredient sleeperIngredient, Ingredient railsIngredient, + TrackType trackType, Supplier> modelHolder, + @Nullable TrackType.TrackBlockFactory customFactory) { this.id = id; this.langName = langName; this.trackBlock = trackBlock; @@ -60,38 +74,52 @@ public class TrackMaterial { this.railsIngredient = railsIngredient; this.particle = particle; this.trackType = trackType; + this.customFactory = customFactory; DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.modelHolder = modelHolder.get().get()); ALL.put(this.id, this); } - public NonNullSupplier getTrackBlock() { + public NonNullSupplier getBlockSupplier() { return this.trackBlock.get(); } - public TrackBlock createBlock(BlockBehaviour.Properties properties) { - return this.trackType.factory.create(properties, this); + public TrackBlock getBlock() { + return getBlockSupplier().get(); } - public boolean isCustom(String modId) { + public ItemStack asStack() { + return asStack(1); + } + + public ItemStack asStack(int count) { + return new ItemStack(getBlock(), count); + } + + public TrackBlock createBlock(BlockBehaviour.Properties properties) { + return (this.customFactory != null ? this.customFactory : this.trackType.factory) + .create(properties, this); + } + + public boolean isFromMod(String modId) { return this.id.getNamespace().equals(modId); } - public static TrackMaterial[] allCustom(String modid) { - return ALL.values().stream().filter(tm -> tm.isCustom(modid)).toArray(TrackMaterial[]::new); + public static List allFromMod(String modid) { + return ALL.values().stream().filter(tm -> tm.isFromMod(modid)).toList(); } - public static List> allCustomBlocks(String modid) { - List> list = new ArrayList<>(); - for (TrackMaterial material : allCustom(modid)) { - list.add(material.getTrackBlock()); + public static List> allBlocksFromMod(String modid) { + List> list = new ArrayList<>(); + for (TrackMaterial material : allFromMod(modid)) { + list.add(material.getBlockSupplier()); } return list; } - public static List> allBlocks() { - List> list = new ArrayList<>(); + public static List> allBlocks() { + List> list = new ArrayList<>(); for (TrackMaterial material : ALL.values()) { - list.add(material.getTrackBlock()); + list.add(material.getBlockSupplier()); } return list; } @@ -105,10 +133,8 @@ public class TrackMaterial { return ANDESITE; ResourceLocation id = ResourceLocation.tryParse(serializedName); - if (id != null) - for (TrackMaterial material : ALL.values()) - if (material.id.equals(id)) - return material; + if (ALL.containsKey(id)) + return ALL.get(id); Create.LOGGER.error("Failed to locate serialized track material: " + serializedName); return ANDESITE; @@ -116,7 +142,7 @@ public class TrackMaterial { public static class TrackType { @FunctionalInterface - protected interface TrackBlockFactory { + public interface TrackBlockFactory { TrackBlock create(BlockBehaviour.Properties properties, TrackMaterial material); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java index 878f09ce2..19c15180c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackMaterialFactory.java @@ -1,9 +1,13 @@ package com.simibubi.create.content.logistics.trains; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; + import com.jozufozu.flywheel.core.PartialModel; import com.simibubi.create.AllTags; import com.simibubi.create.content.logistics.trains.track.TrackBlock; - import com.tterrag.registrate.util.nullness.NonNullSupplier; import net.minecraft.resources.ResourceLocation; @@ -13,9 +17,6 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.DistExecutor; -import java.util.function.Supplier; -import java.util.stream.Stream; - public class TrackMaterialFactory { private final ResourceLocation id; private String langName; @@ -25,6 +26,9 @@ public class TrackMaterialFactory { private ResourceLocation particle; private TrackMaterial.TrackType trackType = TrackMaterial.TrackType.STANDARD; + @Nullable + private TrackMaterial.TrackType.TrackBlockFactory customFactory = null; + @OnlyIn(Dist.CLIENT) private TrackMaterial.TrackModelHolder modelHolder; @OnlyIn(Dist.CLIENT) @@ -113,6 +117,11 @@ public class TrackMaterialFactory { return this; } + public TrackMaterialFactory customBlockFactory(TrackMaterial.TrackType.TrackBlockFactory factory) { + this.customFactory = factory; + return this; + } + public TrackMaterial build() { assert trackBlock != null; assert langName != null; @@ -128,6 +137,6 @@ public class TrackMaterialFactory { modelHolder = new TrackMaterial.TrackModelHolder(tieModel, leftSegmentModel, rightSegmentModel); } }); - return new TrackMaterial(id, langName, trackBlock, particle, sleeperIngredient, railsIngredient, trackType, () -> () -> modelHolder); + return new TrackMaterial(id, langName, trackBlock, particle, sleeperIngredient, railsIngredient, trackType, () -> () -> modelHolder, customFactory); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java index 78cc17b3b..5cec4088c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java @@ -789,7 +789,7 @@ public class TrackBlock extends Block for (TrackMaterial material : otherTrackAmounts.keySet()) { int amt = otherTrackAmounts.getOrDefault(material, 0); while (amt > 0) { - stacks.add(new ItemStack(material.getTrackBlock().get(), Math.min(amt, 64))); + stacks.add(material.asStack(Math.min(amt, 64))); amt -= 64; } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java index adf3e9707..e8ac39927 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java @@ -522,7 +522,7 @@ public class TrackPlacement { BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z); BlockState stateAtPos = level.getBlockState(offsetPos); // copy over all shared properties from the shaped state to the correct track material block - BlockState toPlace = copyProperties(state, info.trackMaterial.getTrackBlock().get().defaultBlockState()); + BlockState toPlace = copyProperties(state, info.trackMaterial.getBlock().defaultBlockState()); boolean canPlace = stateAtPos.getMaterial() .isReplaceable(); @@ -545,7 +545,7 @@ public class TrackPlacement { return info; if (!simulate) { - BlockState onto = info.trackMaterial.getTrackBlock().get().defaultBlockState(); + BlockState onto = info.trackMaterial.getBlock().defaultBlockState(); BlockState stateAtPos = level.getBlockState(targetPos1); level.setBlock(targetPos1, ProperWaterloggedBlock.withWater(level, (AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state1, onto)) diff --git a/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java b/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java index d336936a8..88650803b 100644 --- a/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java +++ b/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java @@ -1,6 +1,9 @@ package com.simibubi.create.foundation.data; +import java.util.ArrayList; +import java.util.Collection; import java.util.function.BiFunction; +import java.util.function.Supplier; import javax.annotation.Nullable; @@ -13,7 +16,9 @@ import com.tterrag.registrate.builders.BuilderCallback; import com.tterrag.registrate.util.OneTimeEventReceiver; import com.tterrag.registrate.util.nullness.NonNullSupplier; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.util.NonNullPredicate; import net.minecraftforge.fml.DistExecutor; @@ -25,6 +30,9 @@ public class CreateTileEntityBuilder extends BlockEnti private NonNullSupplier>> instanceFactory; private NonNullPredicate renderNormally; + private Collection>>> deferredValidBlocks = + new ArrayList<>(); + public static BlockEntityBuilder create(AbstractRegistrate owner, P parent, String name, BuilderCallback callback, BlockEntityFactory factory) { return new CreateTileEntityBuilder<>(owner, parent, name, callback, factory); @@ -35,15 +43,35 @@ public class CreateTileEntityBuilder extends BlockEnti super(owner, parent, name, callback, factory); } - public CreateTileEntityBuilder instance(NonNullSupplier>> instanceFactory) { + public CreateTileEntityBuilder validBlocksDeferred( + NonNullSupplier>> blocks) { + deferredValidBlocks.add(blocks); + return this; + } + + @Override + protected BlockEntityType createEntry() { + deferredValidBlocks.stream() + .map(Supplier::get) + .flatMap(Collection::stream) + .forEach(this::validBlock); + return super.createEntry(); + } + + public CreateTileEntityBuilder instance( + NonNullSupplier>> instanceFactory) { return instance(instanceFactory, true); } - public CreateTileEntityBuilder instance(NonNullSupplier>> instanceFactory, boolean renderNormally) { + public CreateTileEntityBuilder instance( + NonNullSupplier>> instanceFactory, + boolean renderNormally) { return instance(instanceFactory, be -> renderNormally); } - public CreateTileEntityBuilder instance(NonNullSupplier>> instanceFactory, NonNullPredicate renderNormally) { + public CreateTileEntityBuilder instance( + NonNullSupplier>> instanceFactory, + NonNullPredicate renderNormally) { if (this.instanceFactory == null) { DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::registerInstance); } @@ -56,7 +84,8 @@ public class CreateTileEntityBuilder extends BlockEnti protected void registerInstance() { OneTimeEventReceiver.addModListener(FMLClientSetupEvent.class, $ -> { - NonNullSupplier>> instanceFactory = this.instanceFactory; + NonNullSupplier>> instanceFactory = + this.instanceFactory; if (instanceFactory != null) { NonNullPredicate renderNormally = this.renderNormally; InstancedRenderRegistry.configure(getEntry()) diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java index e3905f033..c1faea210 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java @@ -21,17 +21,13 @@ import com.simibubi.create.foundation.ponder.content.trains.TrackScenes; import com.simibubi.create.foundation.ponder.content.trains.TrainScenes; import com.simibubi.create.foundation.ponder.content.trains.TrainSignalScenes; import com.simibubi.create.foundation.ponder.content.trains.TrainStationScenes; - import com.tterrag.registrate.util.entry.BlockEntry; -import com.tterrag.registrate.util.entry.ItemProviderEntry; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.block.Blocks; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; -import java.util.stream.Collectors; - public class PonderIndex { static final PonderRegistrationHelper HELPER = new PonderRegistrationHelper(Create.ID); @@ -312,12 +308,14 @@ public class PonderIndex { .addStoryBoard("rose_quartz_lamp", RedstoneScenes2::roseQuartzLamp); // Trains - HELPER.forComponents(TrackMaterial.allBlocks().stream() - .map((trackSupplier) -> new BlockEntry( - // note: these blocks probably WON'T be in the Create Registrate, but a simple code trace reveals the Entry's registrate isn't used - Create.REGISTRATE, - RegistryObject.create(trackSupplier.get().getRegistryName(), ForgeRegistries.BLOCKS))) - .toList()) + HELPER.forComponents(TrackMaterial.allBlocks() + .stream() + .map((trackSupplier) -> new BlockEntry( + // note: these blocks probably WON'T be in the Create Registrate, but a simple + // code trace reveals the Entry's registrate isn't used + Create.REGISTRATE, RegistryObject.create(trackSupplier.get() + .getRegistryName(), ForgeRegistries.BLOCKS))) + .toList()) .addStoryBoard("train_track/placement", TrackScenes::placement) .addStoryBoard("train_track/portal", TrackScenes::portal) .addStoryBoard("train_track/chunks", TrackScenes::chunks); From 81babd3a39438fa8275a6b06975d71661d10b73b Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 10 May 2023 14:41:46 +0200 Subject: [PATCH 09/22] Implement #4597 --- .../structureMovement/gantry/GantryContraptionEntity.java | 1 + .../com/simibubi/create/foundation/config/CLogistics.java | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java index d20f50ef2..7c7cc7ada 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java @@ -176,6 +176,7 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { } @Override + @OnlyIn(Dist.CLIENT) public void applyLocalTransforms(PoseStack matrixStack, float partialTicks) { } public void updateClientMotion() { 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 b850a88a7..401cb24ac 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CLogistics.java +++ b/src/main/java/com/simibubi/create/foundation/config/CLogistics.java @@ -10,7 +10,8 @@ public class CLogistics extends ConfigBase { public final ConfigInt linkRange = i(256, 1, "linkRange", Comments.linkRange); public final ConfigInt displayLinkRange = i(64, 1, "displayLinkRange", Comments.displayLinkRange); public final ConfigInt vaultCapacity = i(20, 1, "vaultCapacity", Comments.vaultCapacity); - public final ConfigInt brassTunnelTimer = i(10,1,10, "brassTunnelTimer",Comments.brassTunnelTimer); + public final ConfigInt brassTunnelTimer = i(10, 1, 10, "brassTunnelTimer", Comments.brassTunnelTimer); + @Override public String getName() { return "logistics"; @@ -28,7 +29,7 @@ public class CLogistics extends ConfigBase { "The amount of ticks a portable storage interface waits for transfers until letting contraptions move along."; static String mechanicalArmRange = "Maximum distance in blocks a Mechanical Arm can reach across."; static String vaultCapacity = "The total amount of stacks a vault can hold per block in size."; - static String brassTunnelTimer = "The amount of ticks a brass tunnel waits between distributions"; + static String brassTunnelTimer = "The amount of ticks a brass tunnel waits between distributions."; } } From 9e3140938bf50647217fc2ac24aba7ef2a97632b Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 10 May 2023 15:13:39 +0200 Subject: [PATCH 10/22] Implement #4577 for Encased Pipes --- .../fluids/pipes/EncasedPipeBlock.java | 23 ++++++++- .../fluids/pipes/FluidPipeBlock.java | 24 ++++++++- .../fluids/pipes/FluidPipeBlockRotation.java | 49 +++++++++++++++++++ 3 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlockRotation.java diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/EncasedPipeBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/EncasedPipeBlock.java index 6ec931713..720227771 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/EncasedPipeBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/EncasedPipeBlock.java @@ -13,6 +13,8 @@ import java.util.function.Supplier; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.fluids.FluidPropagator; import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; import com.simibubi.create.content.contraptions.relays.elementary.EncasedBlock; @@ -36,7 +38,9 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.PipeBlock; +import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; @@ -46,7 +50,8 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.ticks.TickPriority; -public class EncasedPipeBlock extends Block implements IWrenchable, ISpecialBlockItemRequirement, ITE, EncasedBlock { +public class EncasedPipeBlock extends Block + implements IWrenchable, ISpecialBlockItemRequirement, ITE, EncasedBlock, ITransformableBlock { public static final Map FACING_TO_PROPERTY_MAP = PipeBlock.PROPERTY_BY_DIRECTION; private final Supplier casing; @@ -173,4 +178,20 @@ public class EncasedPipeBlock extends Block implements IWrenchable, ISpecialBloc EncasedPipeBlock.transferSixWayProperties(state, defaultBlockState())); FluidTransportBehaviour.loadFlows(level, pos); } + + @Override + public BlockState rotate(BlockState pState, Rotation pRotation) { + return FluidPipeBlockRotation.rotate(pState, pRotation); + } + + @Override + public BlockState mirror(BlockState pState, Mirror pMirror) { + return FluidPipeBlockRotation.mirror(pState, pMirror); + } + + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + return FluidPipeBlockRotation.transform(state, transform); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlock.java index 50a46213a..765dfbfca 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlock.java @@ -8,6 +8,8 @@ import javax.annotation.Nullable; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.fluids.FluidPropagator; import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; @@ -36,7 +38,9 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.PipeBlock; +import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.SimpleWaterloggedBlock; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; @@ -50,8 +54,8 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.ticks.TickPriority; -public class FluidPipeBlock extends PipeBlock - implements SimpleWaterloggedBlock, IWrenchableWithBracket, ITE, EncasableBlock { +public class FluidPipeBlock extends PipeBlock implements SimpleWaterloggedBlock, IWrenchableWithBracket, + ITE, EncasableBlock, ITransformableBlock { private static final VoxelShape OCCLUSION_BOX = Block.box(4, 4, 4, 12, 12, 12); @@ -337,4 +341,20 @@ public class FluidPipeBlock extends PipeBlock public VoxelShape getOcclusionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos) { return OCCLUSION_BOX; } + + @Override + public BlockState rotate(BlockState pState, Rotation pRotation) { + return FluidPipeBlockRotation.rotate(pState, pRotation); + } + + @Override + public BlockState mirror(BlockState pState, Mirror pMirror) { + return FluidPipeBlockRotation.mirror(pState, pMirror); + } + + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + return FluidPipeBlockRotation.transform(state, transform); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlockRotation.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlockRotation.java new file mode 100644 index 000000000..c60a3a2a7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlockRotation.java @@ -0,0 +1,49 @@ +package com.simibubi.create.content.contraptions.fluids.pipes; + +import java.util.Map; + +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; +import com.simibubi.create.foundation.utility.Iterate; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.PipeBlock; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; + +public class FluidPipeBlockRotation { + + public static final Map FACING_TO_PROPERTY_MAP = PipeBlock.PROPERTY_BY_DIRECTION; + + public static BlockState rotate(BlockState state, Rotation rotation) { + BlockState rotated = state; + for (Direction direction : Iterate.horizontalDirections) + rotated = rotated.setValue(FACING_TO_PROPERTY_MAP.get(rotation.rotate(direction)), + state.getValue(FACING_TO_PROPERTY_MAP.get(direction))); + return rotated; + } + + public static BlockState mirror(BlockState state, Mirror mirror) { + BlockState mirrored = state; + for (Direction direction : Iterate.horizontalDirections) + mirrored = mirrored.setValue(FACING_TO_PROPERTY_MAP.get(mirror.mirror(direction)), + state.getValue(FACING_TO_PROPERTY_MAP.get(direction))); + return mirrored; + } + + public static BlockState transform(BlockState state, StructureTransform transform) { + if (transform.mirror != null) + state = mirror(state, transform.mirror); + + if (transform.rotationAxis == Direction.Axis.Y) + return rotate(state, transform.rotation); + + BlockState rotated = state; + for (Direction direction : Iterate.directions) + rotated = rotated.setValue(FACING_TO_PROPERTY_MAP.get(transform.rotateFacing(direction)), + state.getValue(FACING_TO_PROPERTY_MAP.get(direction))); + return rotated; + } + +} From b4a8386cd8d9febf5528d34a20cebe52a1ed90c6 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 10 May 2023 15:31:28 +0200 Subject: [PATCH 11/22] Implement #4534 as configurable multipliers --- .../com/simibubi/create/events/ClientEvents.java | 4 ++-- .../simibubi/create/foundation/config/CClient.java | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 0c4c4ffbb..883fa45ab 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -319,14 +319,14 @@ public class ClientEvents { if (AllFluids.CHOCOLATE.get() .isSame(fluid)) { - event.scaleFarPlaneDistance(1f / 32f); + event.scaleFarPlaneDistance(1f / 32f * AllConfigs.CLIENT.chocolateTransparencyMultiplier.getF()); event.setCanceled(true); return; } if (AllFluids.HONEY.get() .isSame(fluid)) { - event.scaleFarPlaneDistance(1f / 8f); + event.scaleFarPlaneDistance(1f / 8f * AllConfigs.CLIENT.honeyTransparencyMultiplier.getF()); event.setCanceled(true); return; } diff --git a/src/main/java/com/simibubi/create/foundation/config/CClient.java b/src/main/java/com/simibubi/create/foundation/config/CClient.java index 4fffd25fe..8b5a470a5 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CClient.java +++ b/src/main/java/com/simibubi/create/foundation/config/CClient.java @@ -31,7 +31,14 @@ public class CClient extends ConfigBase { public final ConfigInt ingameMenuConfigButtonOffsetX = i(-4, Integer.MIN_VALUE, Integer.MAX_VALUE, "ingameMenuConfigButtonOffsetX", Comments.ingameMenuConfigButtonOffsetX); public final ConfigBool ignoreFabulousWarning = b(false, "ignoreFabulousWarning", - Comments.ignoreFabulousWarning); + Comments.ignoreFabulousWarning); + + // custom fluid fog + public final ConfigGroup fluidFogSettings = group(1, "fluidFogSettings", Comments.fluidFogSettings); + public final ConfigFloat honeyTransparencyMultiplier = + f(1, .125f, 256, "honey", Comments.honeyTransparencyMultiplier); + public final ConfigFloat chocolateTransparencyMultiplier = + f(1, .125f, 256, "chocolate", Comments.chocolateTransparencyMultiplier); //overlay group public final ConfigGroup overlay = group(1, "goggleOverlay", @@ -147,6 +154,10 @@ public class CClient extends ConfigBase { static String trains = "Railway related settings"; static String mountedZoomMultiplier = "How far away the Camera should zoom when seated on a train"; static String showTrackGraphOnF3 = "Display nodes and edges of a Railway Network while f3 debug mode is active"; + + static String fluidFogSettings = "Configure your vision range when submerged in Create's custom fluids"; + static String honeyTransparencyMultiplier = "The vision range through honey will be multiplied by this factor"; + static String chocolateTransparencyMultiplier = "The vision range though chocolate will be multiplied by this factor"; } } From ee33858ddcf9ff91026c0fff6a6e4c829c7a8211 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 10 May 2023 16:09:03 +0200 Subject: [PATCH 12/22] Move event invocation in case transferAll gets re-used --- .../simibubi/create/content/logistics/trains/TrackGraph.java | 3 --- .../create/content/logistics/trains/TrackPropagator.java | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java index cda0e5f2f..897713e94 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java @@ -19,7 +19,6 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; import com.simibubi.create.Create; -import com.simibubi.create.api.event.TrackGraphMergeEvent; import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; import com.simibubi.create.content.logistics.trains.entity.Train; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; @@ -42,7 +41,6 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.MinecraftForge; public class TrackGraph { @@ -249,7 +247,6 @@ public class TrackGraph { } public void transferAll(TrackGraph toOther) { - MinecraftForge.EVENT_BUS.post(new TrackGraphMergeEvent(this, toOther)); nodes.forEach((loc, node) -> { if (toOther.addNodeIfAbsent(node)) Create.RAILWAYS.sync.nodeAdded(toOther, node); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java index 611787364..75ca5e9eb 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Set; import com.simibubi.create.Create; +import com.simibubi.create.api.event.TrackGraphMergeEvent; import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalPropagator; @@ -16,6 +17,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.MinecraftForge; public class TrackPropagator { @@ -135,6 +137,7 @@ public class TrackPropagator { if (graph == null) graph = other; else { + MinecraftForge.EVENT_BUS.post(new TrackGraphMergeEvent(other, graph)); other.transferAll(graph); manager.removeGraphAndGroup(other); sync.graphRemoved(other); From 3c1961c846acb8eb48fecda67672e9ac8540120f Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 10 May 2023 16:53:29 +0200 Subject: [PATCH 13/22] Implement #3906 - Fixed players dismounting from Trains upon assembly --- .../create/content/logistics/trains/entity/Carriage.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java index 12d25eea7..5b628b511 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java @@ -103,7 +103,7 @@ public class Carriage { DimensionalCarriageEntity dimensional = getDimensional(level); dimensional.alignEntity(entity); - dimensional.removeAndSaveEntity(entity, false); + dimensional.removeAndSaveEntity(entity, true); } public DimensionalCarriageEntity getDimensional(Level level) { @@ -723,8 +723,8 @@ public class Carriage { } - private void dismountPlayer(ServerLevel sLevel, ServerPlayer sp, Integer seat, boolean portal) { - if (!portal) { + private void dismountPlayer(ServerLevel sLevel, ServerPlayer sp, Integer seat, boolean capture) { + if (!capture) { sp.stopRiding(); return; } From f8ec8e5dedad061f736d602bf0c3f80b71d01f28 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 10 May 2023 21:36:18 +0200 Subject: [PATCH 14/22] Fixed #4744 --- .../trains/management/display/GlobalTrainDisplayData.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/GlobalTrainDisplayData.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/display/GlobalTrainDisplayData.java index 605d6c03f..24a4ed405 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/GlobalTrainDisplayData.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/display/GlobalTrainDisplayData.java @@ -30,10 +30,11 @@ public class GlobalTrainDisplayData { } public static List prepare(String filter, int maxLines) { + String regex = filter.isBlank() ? filter : "\\Q" + filter.replace("*", "\\E.*\\Q") + "\\E"; return statusByDestination.entrySet() .stream() .filter(e -> e.getKey() - .matches(filter.replace("*", ".*"))) + .matches(regex)) .flatMap(e -> e.getValue() .stream()) .sorted() From 8e03372bb3eaa0b88a553dd9236db17a967fa28b Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Thu, 11 May 2023 14:15:56 +0200 Subject: [PATCH 15/22] Hacking the printer - Fixed Smart Fluid Pipe not dropping filter when broken - Fixed Clipboard crashing game when removing the first entry of a page - Placards and Creative Crates will no longer hold on to special nbt content (except potion data, damage, enchants) of the contained item when imported via Schematicannon - Schematicannons can no longer print mobs - Fixed item frames not requiring an exact nbt match for printed contents --- src/generated/resources/.cache/cache | 4 +- .../resources/assets/create/lang/en_us.json | 2 +- .../java/com/simibubi/create/AllBlocks.java | 3 - .../fluids/pipes/SmartFluidPipeBlock.java | 3 +- .../clipboard/ClipboardScreen.java | 2 +- .../content/schematics/ItemRequirement.java | 44 +++++++------ .../ponder/content/RollerScenes.java | 2 +- .../foundation/utility/NBTProcessors.java | 61 +++++++++++++++++-- 8 files changed, 87 insertions(+), 34 deletions(-) diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 8b51b26dd..cd3a59bbf 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -582,7 +582,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json fcaad84ac4ebdb1e6d9301b77245ce855dbde503 assets/create/lang/en_ud.json -8c536f441c4515d44faf340cefb2c0247b49033a assets/create/lang/en_us.json +a0e7d027d022330c5358d75165a76383d86ba122 assets/create/lang/en_us.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json @@ -5321,7 +5321,7 @@ ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/girdable_tracks 6e5d3b2123fbb00e7f439c091623619502551bca data/create/tags/blocks/non_movable.json 10781e8cfcbb3486327aace3aa00e437fb44b331 data/create/tags/blocks/ore_override_stone.json 760adb521c2e475a6414f97291f46c02d294fa74 data/create/tags/blocks/passive_boiler_heaters.json -af314e7ec90377e69387523a4c9af19e0056734e data/create/tags/blocks/safe_nbt.json +57f49df02be3d3cacaecf0315da34ea3fb614b8d data/create/tags/blocks/safe_nbt.json 6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json d063e12c9ef75f39518c6d129ea35d833464d547 data/create/tags/blocks/toolboxes.json ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/tracks.json diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index badbba0ef..8407d688d 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -2816,7 +2816,7 @@ "create.ponder.mechanical_roller_fill.text_5": "As opposed to 'clear & pave', neither of these modes will cause the rollers to break existing blocks", "create.ponder.mechanical_roller_pave.header": "Clearing and Paving with the Roller", - "create.ponder.mechanical_roller_pave.text_1": "Mechanical rollers help to clean up long tracks or paths conveniently", + "create.ponder.mechanical_roller_pave.text_1": "Mechanical rollers help to clean up terrain around tracks or paths", "create.ponder.mechanical_roller_pave.text_2": "In its default mode, without a material set, it will simply clear blocks like a Drill", "create.ponder.mechanical_roller_pave.text_3": "While disassembled, a suitable paving material can be specified", "create.ponder.mechanical_roller_pave.text_4": "Materials can be supplied via chests or barrels attached to the structure", diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 35e189c16..fa0877b19 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -230,7 +230,6 @@ import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock; import com.simibubi.create.content.logistics.block.vault.ItemVaultCTBehaviour; import com.simibubi.create.content.logistics.block.vault.ItemVaultItem; import com.simibubi.create.content.logistics.item.LecternControllerBlock; -import com.simibubi.create.content.logistics.trains.BogeyRenderer; import com.simibubi.create.content.logistics.trains.BogeySizes; import com.simibubi.create.content.logistics.trains.TrackMaterial; import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayBlock; @@ -1770,7 +1769,6 @@ public class AllBlocks { REGISTRATE.block("creative_crate", CreativeCrateBlock::new) .transform(BuilderTransformers.crate("creative")) .properties(p -> p.color(MaterialColor.COLOR_PURPLE)) - .tag(AllBlockTags.SAFE_NBT.tag) .register(); public static final BlockEntry DISPLAY_LINK = @@ -1866,7 +1864,6 @@ public class AllBlocks { public static final BlockEntry PLACARD = REGISTRATE.block("placard", PlacardBlock::new) .initialProperties(SharedProperties::copperMetal) .transform(pickaxeOnly()) - .tag(AllBlockTags.SAFE_NBT.tag) .blockstate((c, p) -> p.horizontalFaceBlock(c.get(), AssetLookup.standardModel(c, p))) .simpleItem() .register(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeBlock.java index 99a64bda6..b9b9692ec 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeBlock.java @@ -93,8 +93,7 @@ public class SmartFluidPipeBlock extends FaceAttachedHorizontalDirectionalBlock boolean blockTypeChanged = state.getBlock() != newState.getBlock(); if (blockTypeChanged && !world.isClientSide) FluidPropagator.propagateChangedPipe(world, pos, state); - if (state.hasBlockEntity() && (blockTypeChanged || !newState.hasBlockEntity())) - world.removeBlockEntity(pos); + IBE.onRemove(state, world, pos, newState); } @Override diff --git a/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreen.java b/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreen.java index bfaf96d7a..bdda12df3 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreen.java +++ b/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreen.java @@ -442,7 +442,7 @@ public class ClipboardScreen extends AbstractSimiScreen { if (currentEntries.get(editingIndex).text.getString() .isEmpty() && currentEntries.size() > 1) { currentEntries.remove(editingIndex); - editingIndex -= 1; + editingIndex = Math.max(0, editingIndex - 1); editContext.setCursorToEnd(); return true; } else if (hasControlDown()) { diff --git a/src/main/java/com/simibubi/create/content/schematics/ItemRequirement.java b/src/main/java/com/simibubi/create/content/schematics/ItemRequirement.java index 67e1684f8..235ff5ae3 100644 --- a/src/main/java/com/simibubi/create/content/schematics/ItemRequirement.java +++ b/src/main/java/com/simibubi/create/content/schematics/ItemRequirement.java @@ -1,12 +1,13 @@ package com.simibubi.create.content.schematics; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.simibubi.create.foundation.utility.NBTProcessors; + import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.decoration.ItemFrame; @@ -50,7 +51,9 @@ public class ItemRequirement { } public ItemRequirement(ItemUseType usage, List requiredItems) { - this(requiredItems.stream().map(req -> new StackRequirement(req, usage)).collect(Collectors.toList())); + this(requiredItems.stream() + .map(req -> new StackRequirement(req, usage)) + .collect(Collectors.toList())); } public static ItemRequirement of(BlockState state, BlockEntity be) { @@ -79,14 +82,18 @@ public class ItemRequirement { return INVALID; // double slab needs two items - if (state.hasProperty(BlockStateProperties.SLAB_TYPE) && state.getValue(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE) + if (state.hasProperty(BlockStateProperties.SLAB_TYPE) + && state.getValue(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE) return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, 2)); if (block instanceof TurtleEggBlock) - return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(TurtleEggBlock.EGGS).intValue())); + return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(TurtleEggBlock.EGGS) + .intValue())); if (block instanceof SeaPickleBlock) - return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(SeaPickleBlock.PICKLES).intValue())); + return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(SeaPickleBlock.PICKLES) + .intValue())); if (block instanceof SnowLayerBlock) - return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(SnowLayerBlock.LAYERS).intValue())); + return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(SnowLayerBlock.LAYERS) + .intValue())); if (block instanceof FarmBlock || block instanceof DirtPathBlock) return new ItemRequirement(ItemUseType.CONSUME, Items.DIRT); if (block instanceof AbstractBannerBlock && be instanceof BannerBlockEntity bannerBE) @@ -101,22 +108,20 @@ public class ItemRequirement { if (entity instanceof ItemFrame itemFrame) { ItemStack frame = new ItemStack(Items.ITEM_FRAME); - ItemStack displayedItem = itemFrame.getItem(); + ItemStack displayedItem = NBTProcessors.withUnsafeNBTDiscarded(itemFrame.getItem()); if (displayedItem.isEmpty()) return new ItemRequirement(ItemUseType.CONSUME, Items.ITEM_FRAME); - return new ItemRequirement(ItemUseType.CONSUME, Arrays.asList(frame, displayedItem)); + return new ItemRequirement(List.of(new ItemRequirement.StackRequirement(frame, ItemUseType.CONSUME), + new ItemRequirement.StrictNbtStackRequirement(displayedItem, ItemUseType.CONSUME))); } if (entity instanceof ArmorStand armorStand) { - List requirements = new ArrayList<>(); - requirements.add(new ItemStack(Items.ARMOR_STAND)); - armorStand.getAllSlots().forEach(requirements::add); - return new ItemRequirement(ItemUseType.CONSUME, requirements); - } - - ItemStack pickedStack = entity.getPickResult(); - if (pickedStack != null) { - return new ItemRequirement(ItemUseType.CONSUME, pickedStack); + List requirements = new ArrayList<>(); + requirements.add(new StackRequirement(new ItemStack(Items.ARMOR_STAND), ItemUseType.CONSUME)); + armorStand.getAllSlots() + .forEach(s -> requirements + .add(new StrictNbtStackRequirement(NBTProcessors.withUnsafeNBTDiscarded(s), ItemUseType.CONSUME))); + return new ItemRequirement(requirements); } return INVALID; @@ -142,9 +147,8 @@ public class ItemRequirement { if (other.isEmpty()) return this; - return new ItemRequirement( - Stream.concat(requiredItems.stream(), other.requiredItems.stream()).collect(Collectors.toList()) - ); + return new ItemRequirement(Stream.concat(requiredItems.stream(), other.requiredItems.stream()) + .collect(Collectors.toList())); } public enum ItemUseType { diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/RollerScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/RollerScenes.java index f36863473..fa5596abe 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/content/RollerScenes.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/RollerScenes.java @@ -64,7 +64,7 @@ public class RollerScenes { scene.overlay.showText(60) .pointAt(util.vector.topOf(util.grid.at(6, 2, 4))) .attachKeyFrame() - .text("Mechanical rollers help to clean up long tracks or paths conveniently") + .text("Mechanical rollers help to clean up terrain around tracks or paths") .placeNearTarget(); scene.idle(70); diff --git a/src/main/java/com/simibubi/create/foundation/utility/NBTProcessors.java b/src/main/java/com/simibubi/create/foundation/utility/NBTProcessors.java index 81a9357a4..f2dc7a70d 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/NBTProcessors.java +++ b/src/main/java/com/simibubi/create/foundation/utility/NBTProcessors.java @@ -1,15 +1,20 @@ package com.simibubi.create.foundation.utility; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.function.UnaryOperator; import javax.annotation.Nullable; +import com.simibubi.create.AllBlockEntityTypes; + import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; +import net.minecraft.world.item.EnchantedBookItem; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; @@ -23,7 +28,8 @@ public final class NBTProcessors { processors.put(type, processor); } - public static synchronized void addSurvivalProcessor(BlockEntityType type, UnaryOperator processor) { + public static synchronized void addSurvivalProcessor(BlockEntityType type, + UnaryOperator processor) { survivalProcessors.put(type, processor); } @@ -54,15 +60,62 @@ public final class NBTProcessors { } return data; }); + addProcessor(AllBlockEntityTypes.CREATIVE_CRATE.get(), itemProcessor("Filter")); + addProcessor(AllBlockEntityTypes.PLACARD.get(), itemProcessor("Item")); + } + + public static UnaryOperator itemProcessor(String tagKey) { + return data -> { + CompoundTag compound = data.getCompound(tagKey); + if (!compound.contains("tag", 10)) + return data; + CompoundTag itemTag = compound.getCompound("tag"); + if (itemTag == null) + return data; + HashSet keys = new HashSet<>(itemTag.getAllKeys()); + for (String key : keys) + if (isUnsafeItemNBTKey(key)) + itemTag.remove(key); + if (itemTag.isEmpty()) + compound.remove("tag"); + return data; + }; + } + + public static ItemStack withUnsafeNBTDiscarded(ItemStack stack) { + if (stack.getTag() == null) + return stack; + ItemStack copy = stack.copy(); + stack.getTag() + .getAllKeys() + .stream() + .filter(NBTProcessors::isUnsafeItemNBTKey) + .forEach(copy::removeTagKey); + if (copy.getTag() + .isEmpty()) + copy.setTag(null); + return copy; + } + + public static boolean isUnsafeItemNBTKey(String name) { + if (name.equals(EnchantedBookItem.TAG_STORED_ENCHANTMENTS)) + return false; + if (name.equals("Enchantments")) + return false; + if (name.contains("Potion")) + return false; + if (name.contains("Damage")) + return false; + return true; } public static boolean textComponentHasClickEvent(String json) { Component component = Component.Serializer.fromJson(json.isEmpty() ? "\"\"" : json); - return component != null && component.getStyle() != null && component.getStyle().getClickEvent() != null; + return component != null && component.getStyle() != null && component.getStyle() + .getClickEvent() != null; } - private NBTProcessors() { - } + private NBTProcessors() {} @Nullable public static CompoundTag process(BlockEntity blockEntity, CompoundTag compound, boolean survival) { From beb61708a0f80ed808385cc3ebcbeef97b3bed90 Mon Sep 17 00:00:00 2001 From: TropheusJ <60247969+TropheusJ@users.noreply.github.com> Date: Thu, 11 May 2023 09:00:32 -0400 Subject: [PATCH 16/22] Add GameTests by TropheusJ (#4496) --- .github/workflows/gametest.yml | 23 + build.gradle | 12 + src/generated/resources/.cache/cache | 2 +- .../resources/assets/create/lang/en_us.json | 2 + .../fluids/actors/HosePulleyFluidHandler.java | 4 + .../itemAssembly/SequencedAssemblyRecipe.java | 5 +- .../block/depot/DepotTileEntity.java | 5 + .../block/redstone/NixieTubeTileEntity.java | 4 + .../display/FlapDisplaySection.java | 14 +- .../content/schematics/SchematicExport.java | 75 +++ .../schematics/ServerSchematicLoader.java | 88 ++-- .../client/SchematicAndQuillHandler.java | 83 +--- .../client/SchematicPromptScreen.java | 1 - .../foundation/command/AllCommands.java | 12 +- .../foundation/command/CreateTestCommand.java | 111 +++++ .../create/foundation/mixin/MainMixin.java | 53 ++ .../foundation/mixin/TestCommandMixin.java | 46 ++ .../accessor/GameTestHelperAccessor.java | 17 + .../foundation/utility/FilesHelper.java | 9 +- .../create/gametest/CreateGameTests.java | 39 ++ .../com/simibubi/create/gametest/TESTING.md | 15 + .../infrastructure/CreateGameTestHelper.java | 452 ++++++++++++++++++ .../infrastructure/CreateTestFunction.java | 122 +++++ .../infrastructure/GameTestGroup.java | 25 + .../gametest/tests/TestContraptions.java | 98 ++++ .../create/gametest/tests/TestFluids.java | 152 ++++++ .../create/gametest/tests/TestItems.java | 331 +++++++++++++ .../create/gametest/tests/TestMisc.java | 67 +++ .../create/gametest/tests/TestProcessing.java | 129 +++++ .../assets/create/lang/default/interface.json | 4 +- src/main/resources/create.mixins.json | 3 + .../gametest/contraptions/arrow_dispenser.nbt | Bin 0 -> 1054 bytes .../gametest/contraptions/crop_farming.nbt | Bin 0 -> 2276 bytes .../contraptions/mounted_fluid_drain.nbt | Bin 0 -> 1368 bytes .../contraptions/mounted_item_extract.nbt | Bin 0 -> 1436 bytes .../gametest/contraptions/ploughing.nbt | Bin 0 -> 855 bytes .../contraptions/redstone_contacts.nbt | Bin 0 -> 1501 bytes .../gametest/contraptions/train_observer.nbt | Bin 0 -> 3331 bytes .../gametest/fluids/3_pipe_combine.nbt | Bin 0 -> 1141 bytes .../gametest/fluids/3_pipe_split.nbt | Bin 0 -> 1128 bytes .../gametest/fluids/hose_pulley_transfer.nbt | Bin 0 -> 3467 bytes .../gametest/fluids/in_world_pumping_in.nbt | Bin 0 -> 971 bytes .../gametest/fluids/in_world_pumping_out.nbt | Bin 0 -> 853 bytes .../gametest/fluids/steam_engine.nbt | Bin 0 -> 1594 bytes .../gametest/items/andesite_tunnel_split.nbt | Bin 0 -> 1260 bytes .../gametest/items/arm_purgatory.nbt | Bin 0 -> 1132 bytes .../gametest/items/attribute_filters.nbt | Bin 0 -> 2151 bytes .../gametest/items/belt_coaster.nbt | Bin 0 -> 3459 bytes .../gametest/items/brass_tunnel_filtering.nbt | Bin 0 -> 1650 bytes .../items/brass_tunnel_prefer_nearest.nbt | Bin 0 -> 1371 bytes .../items/brass_tunnel_round_robin.nbt | Bin 0 -> 1556 bytes .../items/brass_tunnel_single_split.nbt | Bin 0 -> 1209 bytes .../gametest/items/brass_tunnel_split.nbt | Bin 0 -> 1564 bytes .../items/brass_tunnel_sync_input.nbt | Bin 0 -> 1715 bytes .../items/content_observer_counting.nbt | Bin 0 -> 933 bytes .../gametest/items/depot_display.nbt | Bin 0 -> 1526 bytes .../gametest/items/stockpile_switch.nbt | Bin 0 -> 504 bytes .../structures/gametest/items/storages.nbt | Bin 0 -> 1789 bytes .../items/vault_comparator_output.nbt | Bin 0 -> 1908 bytes .../gametest/misc/schematicannon.nbt | Bin 0 -> 1320 bytes .../structures/gametest/misc/shearing.nbt | Bin 0 -> 1078 bytes .../gametest/processing/brass_mixing.nbt | Bin 0 -> 2154 bytes .../gametest/processing/brass_mixing_2.nbt | Bin 0 -> 2846 bytes .../processing/crushing_wheel_crafting.nbt | Bin 0 -> 2715 bytes .../gametest/processing/iron_compacting.nbt | Bin 0 -> 1865 bytes .../precision_mechanism_crafting.nbt | Bin 0 -> 2413 bytes .../gametest/processing/sand_washing.nbt | Bin 0 -> 1370 bytes .../processing/stone_cobble_sand_crushing.nbt | Bin 0 -> 2508 bytes .../gametest/processing/track_crafting.nbt | Bin 0 -> 2098 bytes .../processing/water_filling_bottle.nbt | Bin 0 -> 1797 bytes .../gametest/processing/wheat_milling.nbt | Bin 0 -> 986 bytes 71 files changed, 1881 insertions(+), 122 deletions(-) create mode 100644 .github/workflows/gametest.yml create mode 100644 src/main/java/com/simibubi/create/content/schematics/SchematicExport.java create mode 100644 src/main/java/com/simibubi/create/foundation/command/CreateTestCommand.java create mode 100644 src/main/java/com/simibubi/create/foundation/mixin/MainMixin.java create mode 100644 src/main/java/com/simibubi/create/foundation/mixin/TestCommandMixin.java create mode 100644 src/main/java/com/simibubi/create/foundation/mixin/accessor/GameTestHelperAccessor.java create mode 100644 src/main/java/com/simibubi/create/gametest/CreateGameTests.java create mode 100644 src/main/java/com/simibubi/create/gametest/TESTING.md create mode 100644 src/main/java/com/simibubi/create/gametest/infrastructure/CreateGameTestHelper.java create mode 100644 src/main/java/com/simibubi/create/gametest/infrastructure/CreateTestFunction.java create mode 100644 src/main/java/com/simibubi/create/gametest/infrastructure/GameTestGroup.java create mode 100644 src/main/java/com/simibubi/create/gametest/tests/TestContraptions.java create mode 100644 src/main/java/com/simibubi/create/gametest/tests/TestFluids.java create mode 100644 src/main/java/com/simibubi/create/gametest/tests/TestItems.java create mode 100644 src/main/java/com/simibubi/create/gametest/tests/TestMisc.java create mode 100644 src/main/java/com/simibubi/create/gametest/tests/TestProcessing.java create mode 100644 src/main/resources/data/create/structures/gametest/contraptions/arrow_dispenser.nbt create mode 100644 src/main/resources/data/create/structures/gametest/contraptions/crop_farming.nbt create mode 100644 src/main/resources/data/create/structures/gametest/contraptions/mounted_fluid_drain.nbt create mode 100644 src/main/resources/data/create/structures/gametest/contraptions/mounted_item_extract.nbt create mode 100644 src/main/resources/data/create/structures/gametest/contraptions/ploughing.nbt create mode 100644 src/main/resources/data/create/structures/gametest/contraptions/redstone_contacts.nbt create mode 100644 src/main/resources/data/create/structures/gametest/contraptions/train_observer.nbt create mode 100644 src/main/resources/data/create/structures/gametest/fluids/3_pipe_combine.nbt create mode 100644 src/main/resources/data/create/structures/gametest/fluids/3_pipe_split.nbt create mode 100644 src/main/resources/data/create/structures/gametest/fluids/hose_pulley_transfer.nbt create mode 100644 src/main/resources/data/create/structures/gametest/fluids/in_world_pumping_in.nbt create mode 100644 src/main/resources/data/create/structures/gametest/fluids/in_world_pumping_out.nbt create mode 100644 src/main/resources/data/create/structures/gametest/fluids/steam_engine.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/andesite_tunnel_split.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/arm_purgatory.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/attribute_filters.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/belt_coaster.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/brass_tunnel_filtering.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/brass_tunnel_prefer_nearest.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/brass_tunnel_round_robin.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/brass_tunnel_single_split.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/brass_tunnel_split.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/brass_tunnel_sync_input.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/content_observer_counting.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/depot_display.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/stockpile_switch.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/storages.nbt create mode 100644 src/main/resources/data/create/structures/gametest/items/vault_comparator_output.nbt create mode 100644 src/main/resources/data/create/structures/gametest/misc/schematicannon.nbt create mode 100644 src/main/resources/data/create/structures/gametest/misc/shearing.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/brass_mixing.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/brass_mixing_2.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/crushing_wheel_crafting.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/iron_compacting.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/precision_mechanism_crafting.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/sand_washing.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/stone_cobble_sand_crushing.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/track_crafting.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/water_filling_bottle.nbt create mode 100644 src/main/resources/data/create/structures/gametest/processing/wheat_milling.nbt diff --git a/.github/workflows/gametest.yml b/.github/workflows/gametest.yml new file mode 100644 index 000000000..1ec05830a --- /dev/null +++ b/.github/workflows/gametest.yml @@ -0,0 +1,23 @@ +name: gametest +on: [ pull_request, push, workflow_dispatch ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + + - name: checkout repository + uses: actions/checkout@v3 + + - name: setup Java + uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 17 + cache: gradle + + - name: make gradle wrapper executable + run: chmod +x ./gradlew + + - name: run gametests + run: ./gradlew prepareRunGameTestServer runGameTestServer --no-daemon diff --git a/build.gradle b/build.gradle index d8e3a2d87..05c9bdb9a 100644 --- a/build.gradle +++ b/build.gradle @@ -90,6 +90,18 @@ minecraft { } } } + + gameTestServer { + workingDirectory project.file('run/gametest') + arg '-mixin.config=create.mixins.json' + property 'forge.logging.console.level', 'info' + mods { + create { + source sourceSets.main + } + } + setForceExit false + } } } diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index d50c09db9..e7c958a52 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -559,7 +559,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json f85edc574ee6de0de7693ffb031266643db6724a assets/create/lang/en_ud.json -eb624aafc91b284143c3a0cc7d9bbb8de66e8950 assets/create/lang/en_us.json +5ca6b7f3f7f515134269ff45496bb2be53d7e67c assets/create/lang/en_us.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 2603c07fc..3064a4f83 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1117,6 +1117,8 @@ "create.schematicAndQuill.convert": "Save and Upload Immediately", "create.schematicAndQuill.fallbackName": "My Schematic", "create.schematicAndQuill.saved": "Saved as %1$s", + "create.schematicAndQuill.failed": "Failed to save schematic, check logs for details", + "create.schematicAndQuill.instant_failed": "Schematic instant-upload failed, check logs for details", "create.schematic.invalid": "[!] Invalid Item - Use the Schematic Table instead", "create.schematic.error": "Schematic failed to Load - Check Game Logs", diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyFluidHandler.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyFluidHandler.java index 063a52eae..b5883e2d7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyFluidHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyFluidHandler.java @@ -125,4 +125,8 @@ public class HosePulleyFluidHandler implements IFluidHandler { return internalTank.isFluidValid(tank, stack); } + public SmartFluidTank getInternalTank() { + return internalTank; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipe.java index 980d506eb..e3e64cf4f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipe.java +++ b/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipe.java @@ -43,7 +43,8 @@ public class SequencedAssemblyRecipe implements Recipe { protected List> sequence; protected int loops; protected ProcessingOutput transitionalItem; - protected List resultPool; + + public final List resultPool; public SequencedAssemblyRecipe(ResourceLocation recipeId, SequencedAssemblyRecipeSerializer serializer) { this.id = recipeId; @@ -213,7 +214,7 @@ public class SequencedAssemblyRecipe implements Recipe { public boolean isSpecial() { return true; } - + @Override public RecipeType getType() { return AllRecipeTypes.SEQUENCED_ASSEMBLY.getType(); 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 308237dec..8203bebaa 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 @@ -7,6 +7,7 @@ import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.capabilities.Capability; @@ -33,4 +34,8 @@ public class DepotTileEntity extends SmartTileEntity { return depotBehaviour.getItemCapability(cap, side); return super.getCapability(cap, side); } + + public ItemStack getHeldItem() { + return depotBehaviour.getHeldItemStack(); + } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeTileEntity.java index 28afb42ed..adeb4ba96 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeTileEntity.java @@ -123,6 +123,10 @@ public class NixieTubeTileEntity extends SmartTileEntity { customText = Optional.empty(); } + public int getRedstoneStrength() { + return redstoneStrength; + } + // @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplaySection.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplaySection.java index 4481a80ca..51b5f5ef4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplaySection.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplaySection.java @@ -89,11 +89,11 @@ public class FlapDisplaySection { int max = Math.max(4, (int) (cyclingOptions.length * 1.75f)); if (spinningTicks > max) return 0; - + spinningTicks++; if (spinningTicks <= max && spinningTicks < 2) return spinningTicks == 1 ? 0 : spinning.length; - + int spinningFlaps = 0; for (int i = 0; i < spinning.length; i++) { int increasingChance = Mth.clamp(8 - spinningTicks, 1, 10); @@ -107,11 +107,11 @@ public class FlapDisplaySection { spinning[i + 1] &= continueSpin; if (spinningTicks > max) spinning[i] = false; - + if (spinning[i]) spinningFlaps++; } - + return spinningFlaps; } @@ -169,10 +169,14 @@ public class FlapDisplaySection { return !singleFlap; } + public Component getText() { + return component; + } + public static String[] getFlapCycle(String key) { return LOADED_FLAP_CYCLES.computeIfAbsent(key, k -> Lang.translateDirect("flap_display.cycles." + key) .getString() .split(";")); } -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/content/schematics/SchematicExport.java b/src/main/java/com/simibubi/create/content/schematics/SchematicExport.java new file mode 100644 index 000000000..6bad9f5a6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicExport.java @@ -0,0 +1,75 @@ +package com.simibubi.create.content.schematics; + +import com.simibubi.create.Create; +import com.simibubi.create.content.schematics.item.SchematicAndQuillItem; +import com.simibubi.create.foundation.utility.FilesHelper; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import net.minecraft.world.phys.AABB; +import net.minecraftforge.fml.loading.FMLEnvironment; +import net.minecraftforge.fml.loading.FMLPaths; + +import javax.annotation.Nullable; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; + +public class SchematicExport { + public static final Path SCHEMATICS = FMLPaths.GAMEDIR.get().resolve("schematics"); + + /** + * Save a schematic to a file from a world. + * @param dir the directory the schematic will be created in + * @param fileName the ideal name of the schematic, may not be the name of the created file + * @param overwrite whether overwriting an existing schematic is allowed + * @param level the level where the schematic structure is placed + * @param first the first corner of the schematic area + * @param second the second corner of the schematic area + * @return a SchematicExportResult, or null if an error occurred. + */ + @Nullable + public static SchematicExportResult saveSchematic(Path dir, String fileName, boolean overwrite, Level level, BlockPos first, BlockPos second) { + BoundingBox bb = BoundingBox.fromCorners(first, second); + BlockPos origin = new BlockPos(bb.minX(), bb.minY(), bb.minZ()); + BlockPos bounds = new BlockPos(bb.getXSpan(), bb.getYSpan(), bb.getZSpan()); + + StructureTemplate structure = new StructureTemplate(); + structure.fillFromWorld(level, origin, bounds, true, Blocks.AIR); + CompoundTag data = structure.save(new CompoundTag()); + SchematicAndQuillItem.replaceStructureVoidWithAir(data); + SchematicAndQuillItem.clampGlueBoxes(level, new AABB(origin, origin.offset(bounds)), data); + + if (fileName.isEmpty()) + fileName = Lang.translateDirect("schematicAndQuill.fallbackName").getString(); + if (!overwrite) + fileName = FilesHelper.findFirstValidFilename(fileName, dir, "nbt"); + if (!fileName.endsWith(".nbt")) + fileName += ".nbt"; + Path file = dir.resolve(fileName).toAbsolutePath(); + + try { + Files.createDirectories(dir); + boolean overwritten = Files.deleteIfExists(file); + try (OutputStream out = Files.newOutputStream(file, StandardOpenOption.CREATE)) { + NbtIo.writeCompressed(data, out); + } + return new SchematicExportResult(file, dir, fileName, overwritten, origin, bounds); + } catch (IOException e) { + Create.LOGGER.error("An error occurred while saving schematic [" + fileName + "]", e); + return null; + } + } + + public record SchematicExportResult(Path file, Path dir, String fileName, boolean overwritten, BlockPos origin, BlockPos bounds) { + } +} diff --git a/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java b/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java index ffee13229..ffe6b5df9 100644 --- a/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java +++ b/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java @@ -8,6 +8,7 @@ import java.nio.file.Paths; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -16,8 +17,8 @@ import java.util.stream.Stream; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.Create; +import com.simibubi.create.content.schematics.SchematicExport.SchematicExportResult; import com.simibubi.create.content.schematics.block.SchematicTableTileEntity; -import com.simibubi.create.content.schematics.item.SchematicAndQuillItem; import com.simibubi.create.content.schematics.item.SchematicItem; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.CSchematics; @@ -25,18 +26,14 @@ import com.simibubi.create.foundation.utility.Components; import com.simibubi.create.foundation.utility.FilesHelper; import com.simibubi.create.foundation.utility.Lang; +import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraft.world.phys.AABB; public class ServerSchematicLoader { @@ -164,7 +161,7 @@ public class ServerSchematicLoader { protected boolean validateSchematicSizeOnServer(ServerPlayer player, long size) { Integer maxFileSize = getConfig().maxTotalSchematicSize.get(); if (size > maxFileSize * 1000) { - + player.sendMessage(Lang.translateDirect("schematics.uploadTooLarge") .append(Components.literal(" (" + size / 1000 + " KB).")), Util.NIL_UUID); player.sendMessage(Lang.translateDirect("schematics.maxAllowedSize") @@ -284,10 +281,9 @@ public class ServerSchematicLoader { public void handleInstantSchematic(ServerPlayer player, String schematic, Level world, BlockPos pos, BlockPos bounds) { - String playerPath = getSchematicPath() + "/" + player.getGameProfile() - .getName(); - String playerSchematicId = player.getGameProfile() - .getName() + "/" + schematic; + String playerName = player.getGameProfile().getName(); + String playerPath = getSchematicPath() + "/" + playerName; + String playerSchematicId = playerName + "/" + schematic; FilesHelper.createFolderIfMissing(playerPath); // Unsupported Format @@ -310,43 +306,43 @@ public class ServerSchematicLoader { if (!AllItems.SCHEMATIC_AND_QUILL.isIn(player.getMainHandItem())) return; + // if there's too many schematics, delete oldest + Path playerSchematics = Paths.get(playerPath); + + if (!tryDeleteOldestSchematic(playerSchematics)) + return; + + SchematicExportResult result = SchematicExport.saveSchematic( + playerSchematics, schematic, true, + world, pos, pos.offset(bounds).offset(-1, -1, -1) + ); + if (result != null) + player.setItemInHand(InteractionHand.MAIN_HAND, SchematicItem.create(schematic, playerName)); + else Lang.translate("schematicAndQuill.instant_failed") + .style(ChatFormatting.RED) + .sendStatus(player); + } + + private boolean tryDeleteOldestSchematic(Path dir) { + try (Stream stream = Files.list(dir)) { + List files = stream.toList(); + if (files.size() < getConfig().maxSchematics.get()) + return true; + Optional oldest = files.stream().min(Comparator.comparingLong(this::getLastModifiedTime)); + Files.delete(oldest.orElseThrow()); + return true; + } catch (IOException | IllegalStateException e) { + Create.LOGGER.error("Error deleting oldest schematic", e); + return false; + } + } + + private long getLastModifiedTime(Path file) { try { - // Delete schematic with same name - Files.deleteIfExists(path); - - // Too many Schematics - long count; - try (Stream list = Files.list(Paths.get(playerPath))) { - count = list.count(); - } - - if (count >= getConfig().maxSchematics.get()) { - Stream list2 = Files.list(Paths.get(playerPath)); - Optional lastFilePath = list2.filter(f -> !Files.isDirectory(f)) - .min(Comparator.comparingLong(f -> f.toFile() - .lastModified())); - list2.close(); - if (lastFilePath.isPresent()) - Files.deleteIfExists(lastFilePath.get()); - } - - StructureTemplate t = new StructureTemplate(); - t.fillFromWorld(world, pos, bounds, true, Blocks.AIR); - - try (OutputStream outputStream = Files.newOutputStream(path)) { - CompoundTag nbttagcompound = t.save(new CompoundTag()); - SchematicAndQuillItem.replaceStructureVoidWithAir(nbttagcompound); - SchematicAndQuillItem.clampGlueBoxes(world, new AABB(pos, pos.offset(bounds)), nbttagcompound); - NbtIo.writeCompressed(nbttagcompound, outputStream); - player.setItemInHand(InteractionHand.MAIN_HAND, SchematicItem.create(schematic, player.getGameProfile() - .getName())); - - } catch (IOException e) { - e.printStackTrace(); - } + return Files.getLastModifiedTime(file).toMillis(); } catch (IOException e) { - Create.LOGGER.error("Exception Thrown in direct Schematic Upload: " + playerSchematicId); - e.printStackTrace(); + Create.LOGGER.error("Error getting modification time of file " + file.getFileName(), e); + throw new IllegalStateException(e); } } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java index ff5c0a3de..ee3912882 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java @@ -1,13 +1,14 @@ package com.simibubi.create.content.schematics.client; import java.io.IOException; -import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import org.apache.commons.io.IOUtils; +import com.simibubi.create.content.schematics.SchematicExport; + +import com.simibubi.create.content.schematics.SchematicExport.SchematicExportResult; + +import net.minecraft.ChatFormatting; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; @@ -15,12 +16,10 @@ import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.Create; import com.simibubi.create.CreateClient; import com.simibubi.create.content.schematics.ClientSchematicLoader; -import com.simibubi.create.content.schematics.item.SchematicAndQuillItem; import com.simibubi.create.content.schematics.packet.InstantSchematicPacket; import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.FilesHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; @@ -33,16 +32,10 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.AxisDirection; import net.minecraft.core.Vec3i; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.levelgen.structure.BoundingBox; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult.Type; @@ -52,8 +45,8 @@ public class SchematicAndQuillHandler { private Object outlineSlot = new Object(); - private BlockPos firstPos; - private BlockPos secondPos; + public BlockPos firstPos; + public BlockPos secondPos; private BlockPos selectedPos; private Direction selectedFace; private int range = 10; @@ -212,58 +205,30 @@ public class SchematicAndQuillHandler { } public void saveSchematic(String string, boolean convertImmediately) { - StructureTemplate t = new StructureTemplate(); - BoundingBox bb = BoundingBox.fromCorners(firstPos, secondPos); - BlockPos origin = new BlockPos(bb.minX(), bb.minY(), bb.minZ()); - BlockPos bounds = new BlockPos(bb.getXSpan(), bb.getYSpan(), bb.getZSpan()); - Level level = Minecraft.getInstance().level; - - t.fillFromWorld(level, origin, bounds, true, Blocks.AIR); - - if (string.isEmpty()) - string = Lang.translateDirect("schematicAndQuill.fallbackName") - .getString(); - - String folderPath = "schematics"; - FilesHelper.createFolderIfMissing(folderPath); - String filename = FilesHelper.findFirstValidFilename(string, folderPath, "nbt"); - String filepath = folderPath + "/" + filename; - - Path path = Paths.get(filepath); - OutputStream outputStream = null; - try { - outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE); - CompoundTag nbttagcompound = t.save(new CompoundTag()); - SchematicAndQuillItem.replaceStructureVoidWithAir(nbttagcompound); - SchematicAndQuillItem.clampGlueBoxes(level, new AABB(origin, origin.offset(bounds)), nbttagcompound); - NbtIo.writeCompressed(nbttagcompound, outputStream); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (outputStream != null) - IOUtils.closeQuietly(outputStream); + SchematicExportResult result = SchematicExport.saveSchematic( + SchematicExport.SCHEMATICS, string, false, + Minecraft.getInstance().level, firstPos, secondPos + ); + LocalPlayer player = Minecraft.getInstance().player; + if (result == null) { + Lang.translate("schematicAndQuill.failed") + .style(ChatFormatting.RED) + .sendStatus(player); + return; } + Path file = result.file(); + Lang.translate("schematicAndQuill.saved", file) + .sendStatus(player); firstPos = null; secondPos = null; - LocalPlayer player = Minecraft.getInstance().player; - Lang.translate("schematicAndQuill.saved", filepath) - .sendStatus(player); - if (!convertImmediately) return; - if (!Files.exists(path)) { - Create.LOGGER.error("Missing Schematic file: " + path.toString()); - return; - } try { - if (!ClientSchematicLoader.validateSizeLimitation(Files.size(path))) + if (!ClientSchematicLoader.validateSizeLimitation(Files.size(file))) return; - AllPackets.channel.sendToServer(new InstantSchematicPacket(filename, origin, bounds)); - + AllPackets.channel.sendToServer(new InstantSchematicPacket(result.fileName(), result.origin(), result.bounds())); } catch (IOException e) { - Create.LOGGER.error("Error finding Schematic file: " + path.toString()); - e.printStackTrace(); - return; + Create.LOGGER.error("Error instantly uploading Schematic file: " + file, e); } } @@ -271,4 +236,4 @@ public class SchematicAndQuillHandler { return CreateClient.OUTLINER; } -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java index 3fb353c40..4f9723252 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java @@ -109,5 +109,4 @@ public class SchematicPromptScreen extends AbstractSimiScreen { CreateClient.SCHEMATIC_AND_QUILL_HANDLER.saveSchematic(nameField.getValue(), convertImmediately); onClose(); } - } diff --git a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java index 8664b0a5e..6942b6e5e 100644 --- a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java +++ b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java @@ -11,6 +11,8 @@ import com.mojang.brigadier.tree.LiteralCommandNode; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.world.entity.player.Player; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.loading.FMLLoader; public class AllCommands { @@ -20,7 +22,7 @@ public class AllCommands { LiteralCommandNode util = buildUtilityCommands(); - LiteralCommandNode createRoot = dispatcher.register(Commands.literal("create") + LiteralArgumentBuilder root = Commands.literal("create") .requires(cs -> cs.hasPermission(0)) // general purpose .then(new ToggleDebugCommand().register()) @@ -38,8 +40,12 @@ public class AllCommands { .then(GlueCommand.register()) // utility - .then(util) - ); + .then(util); + + if (!FMLLoader.isProduction() && FMLLoader.getDist() == Dist.CLIENT) + root.then(CreateTestCommand.register()); + + LiteralCommandNode createRoot = dispatcher.register(root); createRoot.addChild(buildRedirect("u", util)); diff --git a/src/main/java/com/simibubi/create/foundation/command/CreateTestCommand.java b/src/main/java/com/simibubi/create/foundation/command/CreateTestCommand.java new file mode 100644 index 000000000..f42edbed2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/CreateTestCommand.java @@ -0,0 +1,111 @@ +package com.simibubi.create.foundation.command; + +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; + +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; + +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import com.simibubi.create.CreateClient; + +import com.simibubi.create.content.schematics.SchematicExport; +import com.simibubi.create.content.schematics.SchematicExport.SchematicExportResult; +import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler; + +import com.simibubi.create.foundation.utility.Components; + +import net.minecraft.ChatFormatting; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.server.level.ServerLevel; +import net.minecraftforge.fml.loading.FMLPaths; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + +import static net.minecraft.commands.Commands.argument; +import static net.minecraft.commands.Commands.literal; + +/** + * This command allows for quick exporting of GameTests. + * It is only registered in a client development environment. It is not safe in production or multiplayer. + */ +public class CreateTestCommand { + private static final Path gametests = FMLPaths.GAMEDIR.get() + .getParent() + .resolve("src/main/resources/data/create/structures/gametest") + .toAbsolutePath(); + + public static ArgumentBuilder register() { + return literal("test") + .then(literal("export") + .then(argument("path", StringArgumentType.greedyString()) + .suggests(CreateTestCommand::getSuggestions) + .executes(ctx -> handleExport( + ctx.getSource(), + ctx.getSource().getLevel(), + StringArgumentType.getString(ctx, "path") + )) + ) + ); + } + + private static int handleExport(CommandSourceStack source, ServerLevel level, String path) { + SchematicAndQuillHandler handler = CreateClient.SCHEMATIC_AND_QUILL_HANDLER; + if (handler.firstPos == null || handler.secondPos == null) { + source.sendFailure(Components.literal("You must select an area with the Schematic and Quill first.")); + return 0; + } + SchematicExportResult result = SchematicExport.saveSchematic( + gametests, path, true, + level, handler.firstPos, handler.secondPos + ); + if (result == null) + source.sendFailure(Components.literal("Failed to export, check logs").withStyle(ChatFormatting.RED)); + else { + sendSuccess(source, "Successfully exported test!", ChatFormatting.GREEN); + sendSuccess(source, "Overwritten: " + result.overwritten(), ChatFormatting.AQUA); + sendSuccess(source, "File: " + result.file(), ChatFormatting.GRAY); + } + return 0; + } + + private static void sendSuccess(CommandSourceStack source, String text, ChatFormatting color) { + source.sendSuccess(Components.literal(text).withStyle(color), true); + } + + // find existing tests and folders for autofill + private static CompletableFuture getSuggestions(CommandContext context, + SuggestionsBuilder builder) throws CommandSyntaxException { + String path = builder.getRemaining(); + if (!path.contains("/") || path.contains("..")) + return findInDir(gametests, builder); + int lastSlash = path.lastIndexOf("/"); + Path subDir = gametests.resolve(path.substring(0, lastSlash)); + if (Files.exists(subDir)) + findInDir(subDir, builder); + return builder.buildFuture(); + } + + private static CompletableFuture findInDir(Path dir, SuggestionsBuilder builder) { + try (Stream paths = Files.list(dir)) { + paths.filter(p -> Files.isDirectory(p) || p.toString().endsWith(".nbt")) + .forEach(path -> { + String file = path.toString() + .replaceAll("\\\\", "/") + .substring(gametests.toString().length() + 1); + if (Files.isDirectory(path)) + file += "/"; + builder.suggest(file); + }); + } catch (IOException e) { + throw new RuntimeException(e); + } + return builder.buildFuture(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/MainMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/MainMixin.java new file mode 100644 index 000000000..da309104b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/MainMixin.java @@ -0,0 +1,53 @@ +package com.simibubi.create.foundation.mixin; + +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTestRegistry; +import net.minecraft.gametest.framework.GameTestRunner; +import net.minecraft.gametest.framework.GameTestServer; +import net.minecraft.server.Main; + +import net.minecraft.server.MinecraftServer; + +import net.minecraft.server.packs.repository.PackRepository; +import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import java.util.Collection; + +@Mixin(Main.class) +public class MainMixin { + + /** + * Forge completely bypasses vanilla's + * {@link GameTestServer#create(Thread, LevelStorageAccess, PackRepository, Collection, BlockPos)}, + * which causes tests to generate at bedrock level in a regular world. This causes interference + * (ex. darkness, liquids, gravel) that makes tests fail and act inconsistently. Replacing the server Forge + * makes with one made by vanilla's factory causes tests to run on a superflat, as they should. + *

+ * The system property 'create.useOriginalGametestServer' may be set to true to avoid this behavior. + * This may be desirable for other mods which pull Create into their development environments. + */ + @ModifyVariable( + method = "lambda$main$5", + at = @At( + value = "STORE", + ordinal = 0 + ), + require = 0 // don't crash if this fails + ) + private static MinecraftServer create$correctlyInitializeGametestServer(MinecraftServer original) { + if (original instanceof GameTestServer && !Boolean.getBoolean("create.useOriginalGametestServer")) { + return GameTestServer.create( + original.getRunningThread(), + original.storageSource, + original.getPackRepository(), + GameTestRunner.groupTestsIntoBatches(GameTestRegistry.getAllTestFunctions()), + BlockPos.ZERO + ); + } + return original; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/TestCommandMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/TestCommandMixin.java new file mode 100644 index 000000000..f78936a54 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/TestCommandMixin.java @@ -0,0 +1,46 @@ +package com.simibubi.create.foundation.mixin; + +import com.simibubi.create.gametest.infrastructure.CreateTestFunction; + +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTestRegistry; +import net.minecraft.gametest.framework.MultipleTestTracker; +import net.minecraft.gametest.framework.TestCommand; + +import net.minecraft.gametest.framework.TestFunction; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.ServerLevel; + +import net.minecraft.world.level.block.entity.StructureBlockEntity; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import javax.annotation.Nullable; + +@Mixin(TestCommand.class) +public class TestCommandMixin { + @Redirect( + method = "runTest(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;Lnet/minecraft/gametest/framework/MultipleTestTracker;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/gametest/framework/GameTestRegistry;getTestFunction(Ljava/lang/String;)Lnet/minecraft/gametest/framework/TestFunction;" + ), + require = 0 // don't crash if this fails. non-critical + ) + private static TestFunction create$getCorrectTestFunction(String testName, + ServerLevel level, BlockPos pos, @Nullable MultipleTestTracker tracker) { + StructureBlockEntity be = (StructureBlockEntity) level.getBlockEntity(pos); + CompoundTag data = be.getTileData(); + if (!data.contains("CreateTestFunction", Tag.TAG_STRING)) + return GameTestRegistry.getTestFunction(testName); + String name = data.getString("CreateTestFunction"); + CreateTestFunction function = CreateTestFunction.NAMES_TO_FUNCTIONS.get(name); + if (function == null) + throw new IllegalStateException("Structure block has CreateTestFunction attached, but test [" + name + "] doesn't exist"); + return function; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/accessor/GameTestHelperAccessor.java b/src/main/java/com/simibubi/create/foundation/mixin/accessor/GameTestHelperAccessor.java new file mode 100644 index 000000000..3c3c280d6 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/accessor/GameTestHelperAccessor.java @@ -0,0 +1,17 @@ +package com.simibubi.create.foundation.mixin.accessor; + +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.gametest.framework.GameTestInfo; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(GameTestHelper.class) +public interface GameTestHelperAccessor { + @Accessor + GameTestInfo getTestInfo(); + @Accessor + boolean getFinalCheckAdded(); + @Accessor + void setFinalCheckAdded(boolean value); +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/FilesHelper.java b/src/main/java/com/simibubi/create/foundation/utility/FilesHelper.java index a4b3c8b78..536ffa943 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/FilesHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/FilesHelper.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; @@ -27,15 +28,15 @@ public class FilesHelper { } } - public static String findFirstValidFilename(String name, String folderPath, String extension) { + public static String findFirstValidFilename(String name, Path folderPath, String extension) { int index = 0; String filename; - String filepath; + Path filepath; do { filename = slug(name) + ((index == 0) ? "" : "_" + index) + "." + extension; index++; - filepath = folderPath + "/" + filename; - } while (Files.exists(Paths.get(filepath))); + filepath = folderPath.resolve(filename); + } while (Files.exists(filepath)); return filename; } diff --git a/src/main/java/com/simibubi/create/gametest/CreateGameTests.java b/src/main/java/com/simibubi/create/gametest/CreateGameTests.java new file mode 100644 index 000000000..f50450caa --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/CreateGameTests.java @@ -0,0 +1,39 @@ +package com.simibubi.create.gametest; + +import java.util.Collection; + +import com.simibubi.create.gametest.infrastructure.CreateTestFunction; + +import com.simibubi.create.gametest.tests.TestContraptions; +import com.simibubi.create.gametest.tests.TestFluids; +import com.simibubi.create.gametest.tests.TestItems; +import com.simibubi.create.gametest.tests.TestMisc; +import com.simibubi.create.gametest.tests.TestProcessing; + +import net.minecraft.gametest.framework.GameTestGenerator; +import net.minecraft.gametest.framework.TestFunction; +import net.minecraftforge.event.RegisterGameTestsEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; + +@EventBusSubscriber(bus = Bus.MOD) +public class CreateGameTests { + private static final Class[] testHolders = { + TestContraptions.class, + TestFluids.class, + TestItems.class, + TestMisc.class, + TestProcessing.class + }; + + @SubscribeEvent + public static void registerTests(RegisterGameTestsEvent event) { + event.register(CreateGameTests.class); + } + + @GameTestGenerator + public static Collection generateTests() { + return CreateTestFunction.getTestsFrom(testHolders); + } +} diff --git a/src/main/java/com/simibubi/create/gametest/TESTING.md b/src/main/java/com/simibubi/create/gametest/TESTING.md new file mode 100644 index 000000000..3dec254c9 --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/TESTING.md @@ -0,0 +1,15 @@ +# Adding to GameTests + +#### Adding Tests +All tests must be static, take a `CreateGameTestHelper`, return void, and be annotated with `@GameTest`. +Non-annotated methods will be ignored. The annotation must also specify a structure template. +Classes holding registered tests must be annotated with `GameTestGroup`. + +#### Adding Groups/Classes +Added test classes must be added to the list in `CreateGameTests`. They must be annotated with +`@GameTestGroup` and given a structure path. + +#### Exporting Structures +Structures can be quickly exported using the `/create test export` command (or `/c test export`). +Select an area with the Schematic and Quill, and run it to quickly export a test structure +directly to the correct directory. diff --git a/src/main/java/com/simibubi/create/gametest/infrastructure/CreateGameTestHelper.java b/src/main/java/com/simibubi/create/gametest/infrastructure/CreateGameTestHelper.java new file mode 100644 index 000000000..51b86f548 --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/infrastructure/CreateGameTestHelper.java @@ -0,0 +1,452 @@ +package com.simibubi.create.gametest.infrastructure; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import com.simibubi.create.foundation.mixin.accessor.GameTestHelperAccessor; + +import it.unimi.dsi.fastutil.objects.Object2LongArrayMap; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LeverBlock; +import net.minecraftforge.fluids.FluidStack; + +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +import org.jetbrains.annotations.Contract; + +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity.SelectionMode; +import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.RegisteredObjects; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Registry; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.gametest.framework.GameTestInfo; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.phys.Vec3; + +import org.jetbrains.annotations.NotNull; + +/** + * A helper class expanding the functionality of {@link GameTestHelper}. + * This class may replace the default helper parameter if a test is registered through {@link CreateTestFunction}. + */ +public class CreateGameTestHelper extends GameTestHelper { + public static final int TICKS_PER_SECOND = 20; + public static final int TEN_SECONDS = 10 * TICKS_PER_SECOND; + public static final int FIFTEEN_SECONDS = 15 * TICKS_PER_SECOND; + public static final int TWENTY_SECONDS = 20 * TICKS_PER_SECOND; + + private CreateGameTestHelper(GameTestInfo testInfo) { + super(testInfo); + } + + public static CreateGameTestHelper of(GameTestHelper original) { + GameTestHelperAccessor access = (GameTestHelperAccessor) original; + CreateGameTestHelper helper = new CreateGameTestHelper(access.getTestInfo()); + //noinspection DataFlowIssue // accessor applied at runtime + GameTestHelperAccessor newAccess = (GameTestHelperAccessor) helper; + newAccess.setFinalCheckAdded(access.getFinalCheckAdded()); + return helper; + } + + // blocks + + /** + * Flip the direction of any block with the {@link BlockStateProperties#FACING} property. + */ + public void flipBlock(BlockPos pos) { + BlockState original = getBlockState(pos); + if (!original.hasProperty(BlockStateProperties.FACING)) + fail("FACING property not in block: " + Registry.BLOCK.getId(original.getBlock())); + Direction facing = original.getValue(BlockStateProperties.FACING); + BlockState reversed = original.setValue(BlockStateProperties.FACING, facing.getOpposite()); + setBlock(pos, reversed); + } + + public void assertNixiePower(BlockPos pos, int strength) { + NixieTubeTileEntity nixie = getBlockEntity(AllTileEntities.NIXIE_TUBE.get(), pos); + int actualStrength = nixie.getRedstoneStrength(); + if (actualStrength != strength) + fail("Expected nixie tube at %s to have power of %s, got %s".formatted(pos, strength, actualStrength)); + } + + /** + * Turn off a lever. + */ + public void powerLever(BlockPos pos) { + assertBlockPresent(Blocks.LEVER, pos); + if (!getBlockState(pos).getValue(LeverBlock.POWERED)) { + pullLever(pos); + } + } + + /** + * Turn on a lever. + */ + public void unpowerLever(BlockPos pos) { + assertBlockPresent(Blocks.LEVER, pos); + if (getBlockState(pos).getValue(LeverBlock.POWERED)) { + pullLever(pos); + } + } + + /** + * Set the {@link SelectionMode} of a belt tunnel at the given position. + * @param pos + * @param mode + */ + public void setTunnelMode(BlockPos pos, SelectionMode mode) { + ScrollValueBehaviour behavior = getBehavior(pos, ScrollOptionBehaviour.TYPE); + behavior.setValue(mode.ordinal()); + } + + // block entities + + /** + * Get the block entity of the expected type. If the type does not match, this fails the test. + */ + public T getBlockEntity(BlockEntityType type, BlockPos pos) { + BlockEntity be = getBlockEntity(pos); + BlockEntityType actualType = be == null ? null : be.getType(); + if (actualType != type) { + String actualId = actualType == null ? "null" : RegisteredObjects.getKeyOrThrow(actualType).toString(); + String error = "Expected block entity at pos [%s] with type [%s], got [%s]".formatted( + pos, RegisteredObjects.getKeyOrThrow(type), actualId + ); + fail(error); + } + return (T) be; + } + + /** + * Given any segment of an {@link IMultiTileContainer}, get the controller for it. + */ + public T getControllerBlockEntity(BlockEntityType type, BlockPos anySegment) { + T be = getBlockEntity(type, anySegment).getControllerTE(); + if (be == null) + fail("Could not get block entity controller with type [%s] from pos [%s]".formatted(RegisteredObjects.getKeyOrThrow(type), anySegment)); + return be; + } + + /** + * Get the expected {@link TileEntityBehaviour} from the given position, failing if not present. + */ + public T getBehavior(BlockPos pos, BehaviourType type) { + T behavior = TileEntityBehaviour.get(getLevel(), absolutePos(pos), type); + if (behavior == null) + fail("Behavior at " + pos + " missing, expected " + type.getName()); + return behavior; + } + + // entities + + /** + * Spawn an item entity at the given position with no velocity. + */ + public ItemEntity spawnItem(BlockPos pos, ItemStack stack) { + Vec3 spawn = Vec3.atCenterOf(absolutePos(pos)); + ServerLevel level = getLevel(); + ItemEntity item = new ItemEntity(level, spawn.x, spawn.y, spawn.z, stack, 0, 0, 0); + level.addFreshEntity(item); + return item; + } + + /** + * Spawn item entities given an item and amount. The amount will be split into multiple entities if + * larger than the item's max stack size. + */ + public void spawnItems(BlockPos pos, Item item, int amount) { + while (amount > 0) { + int toSpawn = Math.min(amount, item.getMaxStackSize()); + amount -= toSpawn; + ItemStack stack = new ItemStack(item, toSpawn); + spawnItem(pos, stack); + } + } + + /** + * Get the first entity found at the given position. + */ + public T getFirstEntity(EntityType type, BlockPos pos) { + List list = getEntitiesBetween(type, pos.north().east().above(), pos.south().west().below()); + if (list.isEmpty()) + fail("No entities at pos: " + pos); + return list.get(0); + } + + /** + * Get a list of all entities between two positions, inclusive. + */ + public List getEntitiesBetween(EntityType type, BlockPos pos1, BlockPos pos2) { + BoundingBox box = BoundingBox.fromCorners(absolutePos(pos1), absolutePos(pos2)); + List entities = getLevel().getEntities(type, e -> box.isInside(e.blockPosition())); + return (List) entities; + } + + + // transfer - fluids + + public IFluidHandler fluidStorageAt(BlockPos pos) { + BlockEntity be = getBlockEntity(pos); + if (be == null) + fail("BlockEntity not present"); + Optional handler = be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY).resolve(); + if (handler.isEmpty()) + fail("handler not present"); + return handler.get(); + } + + /** + * Get the content of the tank at the pos. + * content is determined by what the tank allows to be extracted. + */ + public FluidStack getTankContents(BlockPos tank) { + IFluidHandler handler = fluidStorageAt(tank); + return handler.drain(Integer.MAX_VALUE, FluidAction.SIMULATE); + } + + /** + * Get the total capacity of a tank at the given position. + */ + public long getTankCapacity(BlockPos pos) { + IFluidHandler handler = fluidStorageAt(pos); + long total = 0; + for (int i = 0; i < handler.getTanks(); i++) { + total += handler.getTankCapacity(i); + } + return total; + } + + /** + * Get the total fluid amount across all fluid tanks at the given positions. + */ + public long getFluidInTanks(BlockPos... tanks) { + long total = 0; + for (BlockPos tank : tanks) { + total += getTankContents(tank).getAmount(); + } + return total; + } + + /** + * Assert that the given fluid stack is present in the given tank. The tank might also hold more than the fluid. + */ + public void assertFluidPresent(FluidStack fluid, BlockPos pos) { + FluidStack contained = getTankContents(pos); + if (!fluid.isFluidEqual(contained)) + fail("Different fluids"); + if (fluid.getAmount() != contained.getAmount()) + fail("Different amounts"); + } + + /** + * Assert that the given tank holds no fluid. + */ + public void assertTankEmpty(BlockPos pos) { + assertFluidPresent(FluidStack.EMPTY, pos); + } + + public void assertTanksEmpty(BlockPos... tanks) { + for (BlockPos tank : tanks) { + assertTankEmpty(tank); + } + } + + // transfer - items + + public IItemHandler itemStorageAt(BlockPos pos) { + BlockEntity be = getBlockEntity(pos); + if (be == null) + fail("BlockEntity not present"); + Optional handler = be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).resolve(); + if (handler.isEmpty()) + fail("handler not present"); + return handler.get(); + } + + /** + * Get a map of contained items to their amounts. This is not safe for NBT! + */ + public Object2LongMap getItemContent(BlockPos pos) { + IItemHandler handler = itemStorageAt(pos); + Object2LongMap map = new Object2LongArrayMap<>(); + for (int i = 0; i < handler.getSlots(); i++) { + ItemStack stack = handler.getStackInSlot(i); + if (stack.isEmpty()) + continue; + Item item = stack.getItem(); + long amount = map.getLong(item); + amount += stack.getCount(); + map.put(item, amount); + } + return map; + } + + /** + * Get the combined total of all ItemStacks inside the inventory. + */ + public long getTotalItems(BlockPos pos) { + IItemHandler storage = itemStorageAt(pos); + long total = 0; + for (int i = 0; i < storage.getSlots(); i++) { + total += storage.getStackInSlot(i).getCount(); + } + return total; + } + + /** + * Of the provided items, assert that at least one is present in the given inventory. + */ + public void assertAnyContained(BlockPos pos, Item... items) { + IItemHandler handler = itemStorageAt(pos); + boolean noneFound = true; + for (int i = 0; i < handler.getSlots(); i++) { + for (Item item : items) { + if (handler.getStackInSlot(i).is(item)) { + noneFound = false; + break; + } + } + } + if (noneFound) + fail("No matching items " + Arrays.toString(items) + " found in handler at pos: " + pos); + } + + /** + * Assert that the inventory contains all the provided content. + */ + public void assertContentPresent(Object2LongMap content, BlockPos pos) { + IItemHandler handler = itemStorageAt(pos); + Object2LongMap map = new Object2LongArrayMap<>(content); + for (int i = 0; i < handler.getSlots(); i++) { + ItemStack stack = handler.getStackInSlot(i); + if (stack.isEmpty()) + continue; + Item item = stack.getItem(); + long amount = map.getLong(item); + amount -= stack.getCount(); + if (amount == 0) + map.removeLong(item); + else map.put(item, amount); + } + if (!map.isEmpty()) + fail("Storage missing content: " + map); + } + + /** + * Assert that all the given inventories hold no items. + */ + public void assertContainersEmpty(List positions) { + for (BlockPos pos : positions) { + assertContainerEmpty(pos); + } + } + + /** + * Assert that the given inventory holds no items. + */ + @Override + public void assertContainerEmpty(@NotNull BlockPos pos) { + IItemHandler storage = itemStorageAt(pos); + for (int i = 0; i < storage.getSlots(); i++) { + if (!storage.getStackInSlot(i).isEmpty()) + fail("Storage not empty"); + } + } + + /** @see CreateGameTestHelper#assertContainerContains(BlockPos, ItemStack) */ + public void assertContainerContains(BlockPos pos, ItemLike item) { + assertContainerContains(pos, item.asItem()); + } + + /** @see CreateGameTestHelper#assertContainerContains(BlockPos, ItemStack) */ + @Override + public void assertContainerContains(@NotNull BlockPos pos, @NotNull Item item) { + assertContainerContains(pos, new ItemStack(item)); + } + + /** + * Assert that the inventory holds at least the given ItemStack. It may also hold more than the stack. + */ + public void assertContainerContains(BlockPos pos, ItemStack item) { + IItemHandler storage = itemStorageAt(pos); + ItemStack extracted = ItemHelper.extract(storage, stack -> ItemHandlerHelper.canItemStacksStack(stack, item), item.getCount(), true); + if (extracted.isEmpty()) + fail("item not present: " + item); + } + + // time + + /** + * Fail unless the desired number seconds have passed since test start. + */ + public void assertSecondsPassed(int seconds) { + if (getTick() < (long) seconds * TICKS_PER_SECOND) + fail("Waiting for %s seconds to pass".formatted(seconds)); + } + + /** + * Get the total number of seconds that have passed since test start. + */ + public long secondsPassed() { + return getTick() % 20; + } + + /** + * Run an action later, once enough time has passed. + */ + public void whenSecondsPassed(int seconds, Runnable run) { + runAfterDelay((long) seconds * TICKS_PER_SECOND, run); + } + + // numbers + + /** + * Assert that a number is <1 away from its expected value + */ + public void assertCloseEnoughTo(double value, double expected) { + assertInRange(value, expected - 1, expected + 1); + } + + public void assertInRange(double value, double min, double max) { + if (value < min) + fail("Value %s below expected min of %s".formatted(value, min)); + if (value > max) + fail("Value %s greater than expected max of %s".formatted(value, max)); + } + + // misc + + @Contract("_->fail") // make IDEA happier + @Override + public void fail(@NotNull String exceptionMessage) { + super.fail(exceptionMessage); + } +} diff --git a/src/main/java/com/simibubi/create/gametest/infrastructure/CreateTestFunction.java b/src/main/java/com/simibubi/create/gametest/infrastructure/CreateTestFunction.java new file mode 100644 index 000000000..16cfcd163 --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/infrastructure/CreateTestFunction.java @@ -0,0 +1,122 @@ +package com.simibubi.create.gametest.infrastructure; + +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestGenerator; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.gametest.framework.StructureUtils; +import net.minecraft.gametest.framework.TestFunction; +import net.minecraft.world.level.block.Rotation; + +import net.minecraft.world.level.block.entity.StructureBlockEntity; + +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.stream.Stream; + +/** + * An extension to game tests implementing functionality for {@link CreateGameTestHelper} and {@link GameTestGroup}. + * To use, create a {@link GameTestGenerator} that provides tests using {@link #getTestsFrom(Class[])}. + */ +public class CreateTestFunction extends TestFunction { + // for structure blocks and /test runthis + public static final Map NAMES_TO_FUNCTIONS = new HashMap<>(); + + public final String fullName; + public final String simpleName; + + protected CreateTestFunction(String fullName, String simpleName, String pBatchName, String pTestName, + String pStructureName, Rotation pRotation, int pMaxTicks, long pSetupTicks, + boolean pRequired, int pRequiredSuccesses, int pMaxAttempts, Consumer pFunction) { + super(pBatchName, pTestName, pStructureName, pRotation, pMaxTicks, pSetupTicks, pRequired, pRequiredSuccesses, pMaxAttempts, pFunction); + this.fullName = fullName; + this.simpleName = simpleName; + NAMES_TO_FUNCTIONS.put(fullName, this); + } + + @Override + public String getTestName() { + return simpleName; + } + + /** + * Get all Create test functions from the given classes. This enables functionality + * of {@link CreateGameTestHelper} and {@link GameTestGroup}. + */ + public static Collection getTestsFrom(Class... classes) { + return Stream.of(classes) + .map(Class::getDeclaredMethods) + .flatMap(Stream::of) + .map(CreateTestFunction::of) + .filter(Objects::nonNull) + .sorted(Comparator.comparing(TestFunction::getTestName)) + .toList(); + } + + @Nullable + public static TestFunction of(Method method) { + GameTest gt = method.getAnnotation(GameTest.class); + if (gt == null) // skip non-test methods + return null; + Class owner = method.getDeclaringClass(); + GameTestGroup group = owner.getAnnotation(GameTestGroup.class); + String simpleName = owner.getSimpleName() + '.' + method.getName(); + validateTestMethod(method, gt, owner, group, simpleName); + + String structure = "%s:gametest/%s/%s".formatted(group.namespace(), group.path(), gt.template()); + Rotation rotation = StructureUtils.getRotationForRotationSteps(gt.rotationSteps()); + + String fullName = owner.getName() + "." + method.getName(); + return new CreateTestFunction( + // use structure for test name since that's what MC fills structure blocks with for some reason + fullName, simpleName, gt.batch(), structure, structure, rotation, gt.timeoutTicks(), gt.setupTicks(), + gt.required(), gt.requiredSuccesses(), gt.attempts(), asConsumer(method) + ); + } + + private static void validateTestMethod(Method method, GameTest gt, Class owner, GameTestGroup group, String simpleName) { + if (gt.template().isEmpty()) + throw new IllegalArgumentException(simpleName + " must provide a template structure"); + + if (!Modifier.isStatic(method.getModifiers())) + throw new IllegalArgumentException(simpleName + " must be static"); + + if (method.getReturnType() != void.class) + throw new IllegalArgumentException(simpleName + " must return void"); + + if (method.getParameterCount() != 1 || method.getParameterTypes()[0] != CreateGameTestHelper.class) + throw new IllegalArgumentException(simpleName + " must take 1 parameter of type CreateGameTestHelper"); + + if (group == null) + throw new IllegalArgumentException(owner.getName() + " must be annotated with @GameTestGroup"); + } + + private static Consumer asConsumer(Method method) { + return (helper) -> { + try { + method.invoke(null, helper); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + }; + } + + @Override + public void run(@NotNull GameTestHelper helper) { + // give structure block test info + StructureBlockEntity be = (StructureBlockEntity) helper.getBlockEntity(BlockPos.ZERO); + be.getTileData().putString("CreateTestFunction", fullName); + super.run(CreateGameTestHelper.of(helper)); + } +} diff --git a/src/main/java/com/simibubi/create/gametest/infrastructure/GameTestGroup.java b/src/main/java/com/simibubi/create/gametest/infrastructure/GameTestGroup.java new file mode 100644 index 000000000..cb24dc5ce --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/infrastructure/GameTestGroup.java @@ -0,0 +1,25 @@ +package com.simibubi.create.gametest.infrastructure; + +import com.simibubi.create.Create; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Allows for test method declarations to be concise by moving subdirectories and namespaces to the class level. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface GameTestGroup { + /** + * The subdirectory to search for test structures in. + */ + String path(); + + /** + * The namespace to search for test structures in. + */ + String namespace() default Create.ID; +} diff --git a/src/main/java/com/simibubi/create/gametest/tests/TestContraptions.java b/src/main/java/com/simibubi/create/gametest/tests/TestContraptions.java new file mode 100644 index 000000000..524475898 --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/tests/TestContraptions.java @@ -0,0 +1,98 @@ +package com.simibubi.create.gametest.tests; + +import java.util.List; + +import com.simibubi.create.gametest.infrastructure.CreateGameTestHelper; +import com.simibubi.create.gametest.infrastructure.GameTestGroup; + +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.projectile.Arrow; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Blocks; +import net.minecraftforge.fluids.FluidStack; + +@GameTestGroup(path = "contraptions") +public class TestContraptions { + @GameTest(template = "arrow_dispenser", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void arrowDispenser(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(2, 3, 1); + helper.pullLever(lever); + BlockPos pos1 = new BlockPos(0, 5, 0); + BlockPos pos2 = new BlockPos(4, 5, 4); + helper.succeedWhen(() -> { + helper.assertSecondsPassed(7); + List arrows = helper.getEntitiesBetween(EntityType.ARROW, pos1, pos2); + if (arrows.size() != 4) + helper.fail("Expected 4 arrows"); + helper.powerLever(lever); // disassemble contraption + BlockPos dispenser = new BlockPos(2, 5, 2); + // there should be 1 left over + helper.assertContainerContains(dispenser, Items.ARROW); + }); + } + + @GameTest(template = "crop_farming", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void cropFarming(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(4, 3, 1); + helper.pullLever(lever); + BlockPos output = new BlockPos(1, 3, 12); + helper.succeedWhen(() -> helper.assertAnyContained(output, Items.WHEAT, Items.POTATO, Items.CARROT)); + } + + @GameTest(template = "mounted_item_extract", timeoutTicks = CreateGameTestHelper.TWENTY_SECONDS) + public static void mountedItemExtract(CreateGameTestHelper helper) { + BlockPos barrel = new BlockPos(1, 3, 2); + Object2LongMap content = helper.getItemContent(barrel); + BlockPos lever = new BlockPos(1, 5, 1); + helper.pullLever(lever); + BlockPos outputPos = new BlockPos(4, 2, 1); + helper.succeedWhen(() -> { + helper.assertContentPresent(content, outputPos); // verify all extracted + helper.powerLever(lever); + helper.assertContainerEmpty(barrel); // verify nothing left + }); + } + + @GameTest(template = "mounted_fluid_drain", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void mountedFluidDrain(CreateGameTestHelper helper) { + BlockPos tank = new BlockPos(1, 3, 2); + FluidStack fluid = helper.getTankContents(tank); + if (fluid.isEmpty()) + helper.fail("Tank empty"); + BlockPos lever = new BlockPos(1, 5, 1); + helper.pullLever(lever); + BlockPos output = new BlockPos(4, 2, 1); + helper.succeedWhen(() -> { + helper.assertFluidPresent(fluid, output); // verify all extracted + helper.powerLever(lever); // disassemble contraption + helper.assertTankEmpty(tank); // verify nothing left + }); + } + + @GameTest(template = "ploughing") + public static void ploughing(CreateGameTestHelper helper) { + BlockPos dirt = new BlockPos(4, 2, 1); + BlockPos lever = new BlockPos(3, 3, 2); + helper.pullLever(lever); + helper.succeedWhen(() -> helper.assertBlockPresent(Blocks.FARMLAND, dirt)); + } + + @GameTest(template = "redstone_contacts") + public static void redstoneContacts(CreateGameTestHelper helper) { + BlockPos end = new BlockPos(5, 10, 1); + BlockPos lever = new BlockPos(1, 3, 2); + helper.pullLever(lever); + helper.succeedWhen(() -> helper.assertBlockPresent(Blocks.DIAMOND_BLOCK, end)); + } + + // FIXME: trains do not enjoy being loaded in structures + // https://gist.github.com/TropheusJ/f2d0a7df48360d2e078d0987c115c6ef +// @GameTest(template = "train_observer") +// public static void trainObserver(CreateGameTestHelper helper) { +// helper.fail("NYI"); +// } +} diff --git a/src/main/java/com/simibubi/create/gametest/tests/TestFluids.java b/src/main/java/com/simibubi/create/gametest/tests/TestFluids.java new file mode 100644 index 000000000..0624e29d5 --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/tests/TestFluids.java @@ -0,0 +1,152 @@ +package com.simibubi.create.gametest.tests; + +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyFluidHandler; +import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; +import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; + +import com.simibubi.create.gametest.infrastructure.CreateGameTestHelper; + +import com.simibubi.create.gametest.infrastructure.GameTestGroup; + +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.RedStoneWireBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.RedstoneSide; +import net.minecraft.world.level.material.Fluids; +import net.minecraftforge.fluids.FluidAttributes; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; + +@GameTestGroup(path = "fluids") +public class TestFluids { + @GameTest(template = "hose_pulley_transfer", timeoutTicks = CreateGameTestHelper.TWENTY_SECONDS) + public static void hosePulleyTransfer(CreateGameTestHelper helper) { + // there was supposed to be redstone here built in, but it kept popping off, so put it there manually + BlockPos brokenRedstone = new BlockPos(4, 8, 3); + BlockState redstone = Blocks.REDSTONE_WIRE.defaultBlockState() + .setValue(RedStoneWireBlock.NORTH, RedstoneSide.NONE) + .setValue(RedStoneWireBlock.SOUTH, RedstoneSide.NONE) + .setValue(RedStoneWireBlock.EAST, RedstoneSide.UP) + .setValue(RedStoneWireBlock.WEST, RedstoneSide.SIDE) + .setValue(RedStoneWireBlock.POWER, 14); + helper.setBlock(brokenRedstone, redstone); + // pump + BlockPos lever = new BlockPos(6, 9, 3); + helper.pullLever(lever); + helper.succeedWhen(() -> { + helper.assertSecondsPassed(15); + // check filled + BlockPos filledLowerCorner = new BlockPos(8, 3, 2); + BlockPos filledUpperCorner = new BlockPos(10, 5, 4); + BlockPos.betweenClosed(filledLowerCorner, filledUpperCorner) + .forEach(pos -> helper.assertBlockPresent(Blocks.WATER, pos)); + // check emptied + BlockPos emptiedLowerCorner = new BlockPos(2, 3, 2); + BlockPos emptiedUpperCorner = new BlockPos(4, 5, 4); + BlockPos.betweenClosed(emptiedLowerCorner, emptiedUpperCorner) + .forEach(pos -> helper.assertBlockPresent(Blocks.AIR, pos)); + // check nothing left in pulley + BlockPos pulleyPos = new BlockPos(8, 7, 4); + IFluidHandler storage = helper.fluidStorageAt(pulleyPos); + if (storage instanceof HosePulleyFluidHandler hose) { + IFluidHandler internalTank = hose.getInternalTank(); + if (!internalTank.drain(1, FluidAction.SIMULATE).isEmpty()) + helper.fail("Pulley not empty"); + } else { + helper.fail("Not a pulley"); + } + }); + } + + @GameTest(template = "in_world_pumping_out") + public static void inWorldPumpingOutput(CreateGameTestHelper helper) { + BlockPos pumpPos = new BlockPos(3, 2, 2); + BlockPos waterPos = pumpPos.west(); + BlockPos basinPos = pumpPos.east(); + helper.flipBlock(pumpPos); + helper.succeedWhen(() -> { + helper.assertBlockPresent(Blocks.WATER, waterPos); + helper.assertTankEmpty(basinPos); + }); + } + + @GameTest(template = "in_world_pumping_in") + public static void inWorldPumpingPickup(CreateGameTestHelper helper) { + BlockPos pumpPos = new BlockPos(3, 2, 2); + BlockPos basinPos = pumpPos.east(); + BlockPos waterPos = pumpPos.west(); + FluidStack expectedResult = new FluidStack(Fluids.WATER, FluidAttributes.BUCKET_VOLUME); + helper.flipBlock(pumpPos); + helper.succeedWhen(() -> { + helper.assertBlockPresent(Blocks.AIR, waterPos); + helper.assertFluidPresent(expectedResult, basinPos); + }); + } + + @GameTest(template = "steam_engine") + public static void steamEngine(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(4, 3, 3); + helper.pullLever(lever); + BlockPos stressometer = new BlockPos(5, 2, 5); + BlockPos speedometer = new BlockPos(4, 2, 5); + helper.succeedWhen(() -> { + StressGaugeTileEntity stress = helper.getBlockEntity(AllTileEntities.STRESSOMETER.get(), stressometer); + SpeedGaugeTileEntity speed = helper.getBlockEntity(AllTileEntities.SPEEDOMETER.get(), speedometer); + float capacity = stress.getNetworkCapacity(); + helper.assertCloseEnoughTo(capacity, 2048); + float rotationSpeed = Mth.abs(speed.getSpeed()); + helper.assertCloseEnoughTo(rotationSpeed, 16); + }); + } + + @GameTest(template = "3_pipe_combine", timeoutTicks = CreateGameTestHelper.TWENTY_SECONDS) + public static void threePipeCombine(CreateGameTestHelper helper) { + BlockPos tank1Pos = new BlockPos(5, 2, 1); + BlockPos tank2Pos = tank1Pos.south(); + BlockPos tank3Pos = tank2Pos.south(); + long initialContents = helper.getFluidInTanks(tank1Pos, tank2Pos, tank3Pos); + + BlockPos pumpPos = new BlockPos(2, 2, 2); + helper.flipBlock(pumpPos); + helper.succeedWhen(() -> { + helper.assertSecondsPassed(13); + // make sure fully drained + helper.assertTanksEmpty(tank1Pos, tank2Pos, tank3Pos); + // and fully moved + BlockPos outputTankPos = new BlockPos(1, 2, 2); + long moved = helper.getFluidInTanks(outputTankPos); + if (moved != initialContents) + helper.fail("Wrong amount of fluid amount. expected [%s], got [%s]".formatted(initialContents, moved)); + // verify nothing was duped or deleted + }); + } + + @GameTest(template = "3_pipe_split", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void threePipeSplit(CreateGameTestHelper helper) { + BlockPos pumpPos = new BlockPos(2, 2, 2); + BlockPos tank1Pos = new BlockPos(5, 2, 1); + BlockPos tank2Pos = tank1Pos.south(); + BlockPos tank3Pos = tank2Pos.south(); + BlockPos outputTankPos = new BlockPos(1, 2, 2); + + long totalContents = helper.getFluidInTanks(tank1Pos, tank2Pos, tank3Pos, outputTankPos); + helper.flipBlock(pumpPos); + + helper.succeedWhen(() -> { + helper.assertSecondsPassed(7); + FluidStack contents = helper.getTankContents(outputTankPos); + if (!contents.isEmpty()) { + helper.fail("Tank not empty: " + contents.getAmount()); + } + long newTotalContents = helper.getFluidInTanks(tank1Pos, tank2Pos, tank3Pos); + if (newTotalContents != totalContents) { + helper.fail("Wrong total fluid amount. expected [%s], got [%s]".formatted(totalContents, newTotalContents)); + } + }); + } +} diff --git a/src/main/java/com/simibubi/create/gametest/tests/TestItems.java b/src/main/java/com/simibubi/create/gametest/tests/TestItems.java new file mode 100644 index 000000000..43dc317e3 --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/tests/TestItems.java @@ -0,0 +1,331 @@ +package com.simibubi.create.gametest.tests; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Stream; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity.SelectionMode; +import com.simibubi.create.content.logistics.block.depot.DepotTileEntity; +import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; +import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayLayout; +import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; +import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; +import com.simibubi.create.gametest.infrastructure.CreateGameTestHelper; +import com.simibubi.create.gametest.infrastructure.GameTestGroup; +import com.simibubi.create.foundation.utility.Components; + +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.EnchantedBookItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.RedstoneLampBlock; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +@GameTestGroup(path = "items") +public class TestItems { + @GameTest(template = "andesite_tunnel_split") + public static void andesiteTunnelSplit(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(2, 6, 2); + helper.pullLever(lever); + Map outputs = Map.of( + new BlockPos(2, 2, 1), new ItemStack(AllItems.BRASS_INGOT.get(), 1), + new BlockPos(3, 2, 1), new ItemStack(AllItems.BRASS_INGOT.get(), 1), + new BlockPos(4, 2, 2), new ItemStack(AllItems.BRASS_INGOT.get(), 3) + ); + helper.succeedWhen(() -> outputs.forEach(helper::assertContainerContains)); + } + + @GameTest(template = "arm_purgatory", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void armPurgatory(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(2, 3, 2); + BlockPos depot1Pos = new BlockPos(3, 2, 1); + DepotTileEntity depot1 = helper.getBlockEntity(AllTileEntities.DEPOT.get(), depot1Pos); + BlockPos depot2Pos = new BlockPos(1, 2, 1); + DepotTileEntity depot2 = helper.getBlockEntity(AllTileEntities.DEPOT.get(), depot2Pos); + helper.pullLever(lever); + helper.succeedWhen(() -> { + helper.assertSecondsPassed(5); + ItemStack held1 = depot1.getHeldItem(); + boolean held1Empty = held1.isEmpty(); + int held1Count = held1.getCount(); + ItemStack held2 = depot2.getHeldItem(); + boolean held2Empty = held2.isEmpty(); + int held2Count = held2.getCount(); + if (held1Empty && held2Empty) + helper.fail("No item present"); + if (!held1Empty && held1Count != 1) + helper.fail("Unexpected count on depot 1: " + held1Count); + if (!held2Empty && held2Count != 1) + helper.fail("Unexpected count on depot 2: " + held2Count); + }); + } + + @GameTest(template = "attribute_filters", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void attributeFilters(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(2, 3, 1); + BlockPos end = new BlockPos(11, 2, 2); + Map outputs = Map.of( + new BlockPos(3, 2, 1), new ItemStack(AllBlocks.BRASS_BLOCK.get()), + new BlockPos(4, 2, 1), new ItemStack(Items.APPLE), + new BlockPos(5, 2, 1), new ItemStack(Items.WATER_BUCKET), + new BlockPos(6, 2, 1), EnchantedBookItem.createForEnchantment( + new EnchantmentInstance(Enchantments.ALL_DAMAGE_PROTECTION, 1) + ), + new BlockPos(7, 2, 1), Util.make( + new ItemStack(Items.NETHERITE_SWORD), + s -> s.setDamageValue(1) + ), + new BlockPos(8, 2, 1), new ItemStack(Items.IRON_HELMET), + new BlockPos(9, 2, 1), new ItemStack(Items.COAL), + new BlockPos(10, 2, 1), new ItemStack(Items.POTATO) + ); + helper.pullLever(lever); + helper.succeedWhen(() -> { + outputs.forEach(helper::assertContainerContains); + helper.assertContainerEmpty(end); + }); + } + + @GameTest(template = "belt_coaster", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void beltCoaster(CreateGameTestHelper helper) { + BlockPos input = new BlockPos(1, 5, 6); + BlockPos output = new BlockPos(3, 8, 6); + BlockPos lever = new BlockPos(1, 5, 5); + helper.pullLever(lever); + helper.succeedWhen(() -> { + long outputItems = helper.getTotalItems(output); + if (outputItems != 27) + helper.fail("Expected 27 items, got " + outputItems); + long remainingItems = helper.getTotalItems(input); + if (remainingItems != 2) + helper.fail("Expected 2 items remaining, got " + remainingItems); + }); + } + + @GameTest(template = "brass_tunnel_filtering") + public static void brassTunnelFiltering(CreateGameTestHelper helper) { + Map outputs = Map.of( + new BlockPos(3, 2, 2), new ItemStack(Items.COPPER_INGOT, 13), + new BlockPos(4, 2, 3), new ItemStack(AllItems.ZINC_INGOT.get(), 4), + new BlockPos(4, 2, 4), new ItemStack(Items.IRON_INGOT, 2), + new BlockPos(4, 2, 5), new ItemStack(Items.GOLD_INGOT, 24), + new BlockPos(3, 2, 6), new ItemStack(Items.DIAMOND, 17) + ); + BlockPos lever = new BlockPos(2, 3, 2); + helper.pullLever(lever); + helper.succeedWhen(() -> outputs.forEach(helper::assertContainerContains)); + } + + @GameTest(template = "brass_tunnel_prefer_nearest", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void brassTunnelPreferNearest(CreateGameTestHelper helper) { + List tunnels = List.of( + new BlockPos(3, 3, 1), + new BlockPos(3, 3, 2), + new BlockPos(3, 3, 3) + ); + List out = List.of( + new BlockPos(5, 2, 1), + new BlockPos(5, 2, 2), + new BlockPos(5, 2, 3) + ); + BlockPos lever = new BlockPos(2, 3, 2); + helper.pullLever(lever); + // tunnels reconnect and lose their modes + tunnels.forEach(tunnel -> helper.setTunnelMode(tunnel, SelectionMode.PREFER_NEAREST)); + helper.succeedWhen(() -> + out.forEach(pos -> + helper.assertContainerContains(pos, AllBlocks.BRASS_CASING.get()) + ) + ); + } + + @GameTest(template = "brass_tunnel_round_robin", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void brassTunnelRoundRobin(CreateGameTestHelper helper) { + List outputs = List.of( + new BlockPos(7, 3, 1), + new BlockPos(7, 3, 2), + new BlockPos(7, 3, 3) + ); + brassTunnelModeTest(helper, SelectionMode.ROUND_ROBIN, outputs); + } + + @GameTest(template = "brass_tunnel_split") + public static void brassTunnelSplit(CreateGameTestHelper helper) { + List outputs = List.of( + new BlockPos(7, 2, 1), + new BlockPos(7, 2, 2), + new BlockPos(7, 2, 3) + ); + brassTunnelModeTest(helper, SelectionMode.SPLIT, outputs); + } + + private static void brassTunnelModeTest(CreateGameTestHelper helper, SelectionMode mode, List outputs) { + BlockPos lever = new BlockPos(2, 3, 2); + List tunnels = List.of( + new BlockPos(3, 3, 1), + new BlockPos(3, 3, 2), + new BlockPos(3, 3, 3) + ); + helper.pullLever(lever); + tunnels.forEach(tunnel -> helper.setTunnelMode(tunnel, mode)); + helper.succeedWhen(() -> { + long items = 0; + for (BlockPos out : outputs) { + helper.assertContainerContains(out, AllBlocks.BRASS_CASING.get()); + items += helper.getTotalItems(out); + } + if (items != 10) + helper.fail("expected 10 items, got " + items); + }); + } + + @GameTest(template = "brass_tunnel_sync_input", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void brassTunnelSyncInput(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(1, 3, 2); + List redstoneBlocks = List.of( + new BlockPos(3, 4, 1), + new BlockPos(3, 4, 2), + new BlockPos(3, 4, 3) + ); + List tunnels = List.of( + new BlockPos(5, 3, 1), + new BlockPos(5, 3, 2), + new BlockPos(5, 3, 3) + ); + List outputs = List.of( + new BlockPos(7, 2, 1), + new BlockPos(7, 2, 2), + new BlockPos(7, 2, 3) + ); + helper.pullLever(lever); + tunnels.forEach(tunnel -> helper.setTunnelMode(tunnel, SelectionMode.SYNCHRONIZE)); + helper.succeedWhen(() -> { + if (helper.secondsPassed() < 9) { + helper.setBlock(redstoneBlocks.get(0), Blocks.AIR); + helper.assertSecondsPassed(3); + outputs.forEach(helper::assertContainerEmpty); + helper.setBlock(redstoneBlocks.get(1), Blocks.AIR); + helper.assertSecondsPassed(6); + outputs.forEach(helper::assertContainerEmpty); + helper.setBlock(redstoneBlocks.get(2), Blocks.AIR); + helper.assertSecondsPassed(9); + } else { + outputs.forEach(out -> helper.assertContainerContains(out, AllBlocks.BRASS_CASING.get())); + } + }); + } + + @GameTest(template = "content_observer_counting") + public static void contentObserverCounting(CreateGameTestHelper helper) { + BlockPos chest = new BlockPos(3, 2, 1); + long totalChestItems = helper.getTotalItems(chest); + BlockPos chestNixiePos = new BlockPos(2, 3, 1); + NixieTubeTileEntity chestNixie = helper.getBlockEntity(AllTileEntities.NIXIE_TUBE.get(), chestNixiePos); + + BlockPos doubleChest = new BlockPos(2, 2, 3); + long totalDoubleChestItems = helper.getTotalItems(doubleChest); + BlockPos doubleChestNixiePos = new BlockPos(1, 3, 3); + NixieTubeTileEntity doubleChestNixie = helper.getBlockEntity(AllTileEntities.NIXIE_TUBE.get(), doubleChestNixiePos); + + helper.succeedWhen(() -> { + String chestNixieText = chestNixie.getFullText().getString(); + long chestNixieReading = Long.parseLong(chestNixieText); + if (chestNixieReading != totalChestItems) + helper.fail("Chest nixie detected %s, expected %s".formatted(chestNixieReading, totalChestItems)); + String doubleChestNixieText = doubleChestNixie.getFullText().getString(); + long doubleChestNixieReading = Long.parseLong(doubleChestNixieText); + if (doubleChestNixieReading != totalDoubleChestItems) + helper.fail("Double chest nixie detected %s, expected %s".formatted(doubleChestNixieReading, totalDoubleChestItems)); + }); + } + + @GameTest(template = "depot_display", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void depotDisplay(CreateGameTestHelper helper) { + BlockPos displayPos = new BlockPos(5, 3, 1); + List depots = Stream.of( + new BlockPos(2, 2, 1), + new BlockPos(1, 2, 1) + ).map(pos -> helper.getBlockEntity(AllTileEntities.DEPOT.get(), pos)).toList(); + List levers = List.of( + new BlockPos(2, 5, 0), + new BlockPos(1, 5, 0) + ); + levers.forEach(helper::pullLever); + FlapDisplayTileEntity display = helper.getBlockEntity(AllTileEntities.FLAP_DISPLAY.get(), displayPos).getController(); + helper.succeedWhen(() -> { + for (int i = 0; i < 2; i++) { + FlapDisplayLayout line = display.getLines().get(i); + MutableComponent textComponent = Components.empty(); + line.getSections().stream().map(FlapDisplaySection::getText).forEach(textComponent::append); + String text = textComponent.getString().toLowerCase(Locale.ROOT).trim(); + + DepotTileEntity depot = depots.get(i); + ItemStack item = depot.getHeldItem(); + String name = Registry.ITEM.getKey(item.getItem()).getPath(); + + if (!name.equals(text)) + helper.fail("Text mismatch: wanted [" + name + "], got: " + text); + } + }); + } + + @GameTest(template = "stockpile_switch") + public static void stockpileSwitch(CreateGameTestHelper helper) { + BlockPos chest = new BlockPos(1, 2, 1); + BlockPos lamp = new BlockPos(2, 3, 1); + helper.assertBlockProperty(lamp, RedstoneLampBlock.LIT, false); + IItemHandler chestStorage = helper.itemStorageAt(chest); + for (int i = 0; i < 18; i++) { // insert 18 stacks + ItemHandlerHelper.insertItem(chestStorage, new ItemStack(Items.DIAMOND, 64), false); + } + helper.succeedWhen(() -> helper.assertBlockProperty(lamp, RedstoneLampBlock.LIT, true)); + } + + @GameTest(template = "storages", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void storages(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(12, 3, 2); + BlockPos startChest = new BlockPos(13, 3, 1); + Object2LongMap originalContent = helper.getItemContent(startChest); + BlockPos endShulker = new BlockPos(1, 3, 1); + helper.pullLever(lever); + helper.succeedWhen(() -> helper.assertContentPresent(originalContent, endShulker)); + } + + @GameTest(template = "vault_comparator_output") + public static void vaultComparatorOutput(CreateGameTestHelper helper) { + BlockPos smallInput = new BlockPos(1, 4, 1); + BlockPos smallNixie = new BlockPos(3, 2, 1); + helper.assertNixiePower(smallNixie, 0); + helper.whenSecondsPassed(1, () -> helper.spawnItems(smallInput, Items.BREAD, 64 * 9)); + + BlockPos medInput = new BlockPos(1, 5, 4); + BlockPos medNixie = new BlockPos(4, 2, 4); + helper.assertNixiePower(medNixie, 0); + helper.whenSecondsPassed(2, () -> helper.spawnItems(medInput, Items.BREAD, 64 * 77)); + + BlockPos bigInput = new BlockPos(1, 6, 8); + BlockPos bigNixie = new BlockPos(5, 2, 7); + helper.assertNixiePower(bigNixie, 0); + helper.whenSecondsPassed(3, () -> helper.spawnItems(bigInput, Items.BREAD, 64 * 240)); + + helper.succeedWhen(() -> { + helper.assertNixiePower(smallNixie, 7); + helper.assertNixiePower(medNixie, 7); + helper.assertNixiePower(bigNixie, 7); + }); + } +} diff --git a/src/main/java/com/simibubi/create/gametest/tests/TestMisc.java b/src/main/java/com/simibubi/create/gametest/tests/TestMisc.java new file mode 100644 index 000000000..829bd3d4b --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/tests/TestMisc.java @@ -0,0 +1,67 @@ +package com.simibubi.create.gametest.tests; + +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.schematics.SchematicExport; +import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; +import com.simibubi.create.content.schematics.block.SchematicannonTileEntity.State; +import com.simibubi.create.content.schematics.item.SchematicItem; + +import com.simibubi.create.gametest.infrastructure.CreateGameTestHelper; +import com.simibubi.create.gametest.infrastructure.GameTestGroup; + +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.animal.Sheep; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Blocks; + +import static com.simibubi.create.gametest.infrastructure.CreateGameTestHelper.FIFTEEN_SECONDS; + +@GameTestGroup(path = "misc") +public class TestMisc { + @GameTest(template = "schematicannon", timeoutTicks = FIFTEEN_SECONDS) + public static void schematicannon(CreateGameTestHelper helper) { + // load the structure + BlockPos whiteEndBottom = helper.absolutePos(new BlockPos(5, 2, 1)); + BlockPos redEndTop = helper.absolutePos(new BlockPos(5, 4, 7)); + ServerLevel level = helper.getLevel(); + SchematicExport.saveSchematic( + SchematicExport.SCHEMATICS.resolve("uploaded/Deployer"), "schematicannon_gametest", true, + level, whiteEndBottom, redEndTop + ); + ItemStack schematic = SchematicItem.create("schematicannon_gametest.nbt", "Deployer"); + // deploy to pos + BlockPos anchor = helper.absolutePos(new BlockPos(1, 2, 1)); + schematic.getOrCreateTag().putBoolean("Deployed", true); + schematic.getOrCreateTag().put("Anchor", NbtUtils.writeBlockPos(anchor)); + // setup cannon + BlockPos cannonPos = new BlockPos(3, 2, 6); + SchematicannonTileEntity cannon = helper.getBlockEntity(AllTileEntities.SCHEMATICANNON.get(), cannonPos); + cannon.inventory.setStackInSlot(0, schematic); + // run + cannon.state = State.RUNNING; + cannon.statusMsg = "running"; + helper.succeedWhen(() -> { + if (cannon.state != State.STOPPED) { + helper.fail("Schematicannon not done"); + } + BlockPos lastBlock = new BlockPos(1, 4, 7); + helper.assertBlockPresent(Blocks.RED_WOOL, lastBlock); + }); + } + + @GameTest(template = "shearing") + public static void shearing(CreateGameTestHelper helper) { + BlockPos sheepPos = new BlockPos(2, 1, 2); + Sheep sheep = helper.getFirstEntity(EntityType.SHEEP, sheepPos); + sheep.shear(SoundSource.NEUTRAL); + helper.succeedWhen(() -> { + helper.assertItemEntityPresent(Items.WHITE_WOOL, sheepPos, 2); + }); + } +} diff --git a/src/main/java/com/simibubi/create/gametest/tests/TestProcessing.java b/src/main/java/com/simibubi/create/gametest/tests/TestProcessing.java new file mode 100644 index 000000000..ca2767c7d --- /dev/null +++ b/src/main/java/com/simibubi/create/gametest/tests/TestProcessing.java @@ -0,0 +1,129 @@ +package com.simibubi.create.gametest.tests; + +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; + +import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipe; +import com.simibubi.create.content.contraptions.processing.ProcessingOutput; +import com.simibubi.create.gametest.infrastructure.CreateGameTestHelper; +import com.simibubi.create.gametest.infrastructure.GameTestGroup; +import com.simibubi.create.foundation.item.ItemHelper; + +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestAssertException; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.alchemy.PotionUtils; +import net.minecraft.world.item.alchemy.Potions; +import net.minecraftforge.items.IItemHandler; + +@GameTestGroup(path = "processing") +public class TestProcessing { + @GameTest(template = "brass_mixing", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void brassMixing(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(2, 3, 2); + BlockPos chest = new BlockPos(7, 3, 1); + helper.pullLever(lever); + helper.succeedWhen(() -> helper.assertContainerContains(chest, AllItems.BRASS_INGOT.get())); + } + + @GameTest(template = "brass_mixing_2", timeoutTicks = CreateGameTestHelper.TWENTY_SECONDS) + public static void brassMixing2(CreateGameTestHelper helper) { + BlockPos basinLever = new BlockPos(3, 3, 1); + BlockPos armLever = new BlockPos(3, 3, 5); + BlockPos output = new BlockPos(1, 2, 3); + helper.pullLever(armLever); + helper.whenSecondsPassed(7, () -> helper.pullLever(armLever)); + helper.whenSecondsPassed(10, () -> helper.pullLever(basinLever)); + helper.succeedWhen(() -> helper.assertContainerContains(output, AllItems.BRASS_INGOT.get())); + } + + @GameTest(template = "crushing_wheel_crafting", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void crushingWheelCrafting(CreateGameTestHelper helper) { + BlockPos chest = new BlockPos(1, 4, 3); + List levers = List.of( + new BlockPos(2, 3, 2), + new BlockPos(6, 3, 2), + new BlockPos(3, 7, 3) + ); + levers.forEach(helper::pullLever); + ItemStack expected = new ItemStack(AllBlocks.CRUSHING_WHEEL.get(), 2); + helper.succeedWhen(() -> helper.assertContainerContains(chest, expected)); + } + + @GameTest(template = "precision_mechanism_crafting", timeoutTicks = CreateGameTestHelper.TWENTY_SECONDS) + public static void precisionMechanismCrafting(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(6, 3, 6); + BlockPos output = new BlockPos(11, 3, 1); + helper.pullLever(lever); + + SequencedAssemblyRecipe recipe = (SequencedAssemblyRecipe) helper.getLevel().getRecipeManager() + .byKey(Create.asResource("sequenced_assembly/precision_mechanism")) + .orElseThrow(() -> new GameTestAssertException("Precision Mechanism recipe not found")); + Item result = recipe.getResultItem().getItem(); + Item[] possibleResults = recipe.resultPool.stream() + .map(ProcessingOutput::getStack) + .map(ItemStack::getItem) + .filter(item -> item != result) + .toArray(Item[]::new); + + helper.succeedWhen(() -> { + helper.assertContainerContains(output, result); + helper.assertAnyContained(output, possibleResults); + }); + } + + @GameTest(template = "sand_washing", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void sandWashing(CreateGameTestHelper helper) { + BlockPos leverPos = new BlockPos(5, 3, 1); + helper.pullLever(leverPos); + BlockPos chestPos = new BlockPos(8, 3, 2); + helper.succeedWhen(() -> helper.assertContainerContains(chestPos, Items.CLAY_BALL)); + } + + @GameTest(template = "stone_cobble_sand_crushing", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void stoneCobbleSandCrushing(CreateGameTestHelper helper) { + BlockPos chest = new BlockPos(1, 6, 2); + BlockPos lever = new BlockPos(2, 3, 1); + helper.pullLever(lever); + ItemStack expected = new ItemStack(Items.SAND, 5); + helper.succeedWhen(() -> helper.assertContainerContains(chest, expected)); + } + + @GameTest(template = "track_crafting", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) + public static void trackCrafting(CreateGameTestHelper helper) { + BlockPos output = new BlockPos(7, 3, 2); + BlockPos lever = new BlockPos(2, 3, 1); + helper.pullLever(lever); + ItemStack expected = new ItemStack(AllBlocks.TRACK.get(), 6); + helper.succeedWhen(() -> { + helper.assertContainerContains(output, expected); + IItemHandler handler = helper.itemStorageAt(output); + ItemHelper.extract(handler, stack -> stack.sameItem(expected), 6, false); + helper.assertContainerEmpty(output); + }); + } + + @GameTest(template = "water_filling_bottle") + public static void waterFillingBottle(CreateGameTestHelper helper) { + BlockPos lever = new BlockPos(3, 3, 3); + BlockPos output = new BlockPos(2, 2, 4); + ItemStack expected = PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER); + helper.pullLever(lever); + helper.succeedWhen(() -> helper.assertContainerContains(output, expected)); + } + + @GameTest(template = "wheat_milling") + public static void wheatMilling(CreateGameTestHelper helper) { + BlockPos output = new BlockPos(1, 2, 1); + BlockPos lever = new BlockPos(1, 7, 1); + helper.pullLever(lever); + ItemStack expected = new ItemStack(AllItems.WHEAT_FLOUR.get(), 3); + helper.succeedWhen(() -> helper.assertContainerContains(output, expected)); + } +} diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index 86e0d8237..af689e00f 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -269,6 +269,8 @@ "create.schematicAndQuill.convert": "Save and Upload Immediately", "create.schematicAndQuill.fallbackName": "My Schematic", "create.schematicAndQuill.saved": "Saved as %1$s", + "create.schematicAndQuill.failed": "Failed to save schematic, check logs for details", + "create.schematicAndQuill.instant_failed": "Schematic instant-upload failed, check logs for details", "create.schematic.invalid": "[!] Invalid Item - Use the Schematic Table instead", "create.schematic.error": "Schematic failed to Load - Check Game Logs", @@ -920,7 +922,7 @@ "create.contraption.minecart_contraption_too_big": "This Cart Contraption seems too big to pick up", "create.contraption.minecart_contraption_illegal_pickup": "A mystical force is binding this Cart Contraption to the world", - + "enchantment.create.capacity.desc": "Increases Backtank air capacity.", "enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused." diff --git a/src/main/resources/create.mixins.json b/src/main/resources/create.mixins.json index dc5b8e9a8..c316ea3bd 100644 --- a/src/main/resources/create.mixins.json +++ b/src/main/resources/create.mixins.json @@ -8,10 +8,13 @@ "ClientboundMapItemDataPacketMixin", "ContraptionDriverInteractMixin", "CustomItemUseEffectsMixin", + "MainMixin", "MapItemSavedDataMixin", + "TestCommandMixin", "accessor.AbstractProjectileDispenseBehaviorAccessor", "accessor.DispenserBlockAccessor", "accessor.FallingBlockEntityAccessor", + "accessor.GameTestHelperAccessor", "accessor.LivingEntityAccessor", "accessor.NbtAccounterAccessor", "accessor.ServerLevelAccessor" diff --git a/src/main/resources/data/create/structures/gametest/contraptions/arrow_dispenser.nbt b/src/main/resources/data/create/structures/gametest/contraptions/arrow_dispenser.nbt new file mode 100644 index 0000000000000000000000000000000000000000..62320b6d4b0a0299c227279e39f56425a6fbc8e2 GIT binary patch literal 1054 zcmV+(1mXK1iwFP!00000|HYV1Z__Xs$Di2F)^-e#5C=X0CxpZap-DSTyl7ltV$uX$ zCNK56Xjxnwcilip`zCw@&U`11NL+E+y35St7X}iQsy4~b@o!J^f8uoj&fgmI*mqCgg0Hkn{3-BrqXo%Y>XQ6LPjp$eATLTPEae znUJ$(Le7>6InP`iXX0VH&eX$@1coLsU1x^e^R9F5VY<#M9)=_^G=X6OACllqQ0D>A z`atK9?~a8SZe4)cv-(QtsZ_@~^q%rDFG_vBebJtT?V6_Co+^j+t>I7%?co;}Z5_$W zp*d*2?ri3;va6M7=53n7+HRp_RqgR=(w^XU4@fzL8-)@^WaC6?sXV&f@(nypsCr--wU2|3dQXNEYhdYDkO7~LeXM~a}S9hah$PsKqAhTiM0a~akfmX z9k|X|J8+$`7`x6sCe{vIXDsS5XM#BQuh|X)(Vqu>eG&Acn&{$aUT&JXZq38QdO@sq%Oykt6YB-B>rE4!X@WCDoUvXI%N0YMeN3zuxXxHF zppG-v3uwgIGO=DjBhHqI^#a!!>jkbemSNY~$HaPp>x|_*=1frMtG%E-#Tw+Vr?pV+ zls_Lly#M9-<8NO-eBb`@j_w1uz6i2)+3tsIX z2(H>8xLdbYH#|%%`>|Rr?}Y>=mi^fEr3ub7!I>e>SoUK%Vu-VkiDln)#GqGgHoN0nH zOK@h0vyTa-gdxs8#&upD^Gawf+Pmat57;YyBH-?#zbjr=Q+~c*@TTqU0~qWmITot@ z39kqFSWeA-kv#%C?)K$s))@Q2nnl?;$rk*_2mR&m^pkiJ5Y7(iL;CP19m3d)`hfuEeSMt%i0O znT)~B>FlFC75nqwVw{n#0OMz61KIiI#k=wkUdqIQ1)wv!uT^OZt~w?66aanbm=)+V YuKAu&O(|=$i2VY;0P~qV=wcWE0HKW#$^ZZW literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/contraptions/crop_farming.nbt b/src/main/resources/data/create/structures/gametest/contraptions/crop_farming.nbt new file mode 100644 index 0000000000000000000000000000000000000000..45e0887b89e925ed64f98c0499d84fddcde4b0d0 GIT binary patch literal 2276 zcmaJ?eK-?p8}AKCanvQuu4dq7p;cWZ4qJk*qWdjcsY6 z`COCcqnhQ?T4?aa(MzhCah=ckc6z$@Gjmu=+vb zO4ZQ1og$S@Ia$dqg(#O5#51B~UrGW6H&`eemzrZ9Zr=fx^mrYE3FPeE2x-RjVTDgN z*uvwNpO4LaxZ3USEZCiv9&n-xJ2xK^$o$=;+gsvBO@C2}h%#&fqU(xoc8XfyNgE6W zJ{9CAw(PE>eWp)iPdWUujmDU23=^FKwzr89eGZ2z__D|wZMow={@n1C_-Xd#hzNt) zr5e4F_O9^CAQ2*twz6IOASOFRzCU7qoN*34O%Cj2STrf4un{z*MU{B0s_b!6D5ZC% z3?azaHp&aTN~#pJf0W3mPv87Dhl}XjrzT}L&ReSET@oj|267pa85urno+Y0iV9oE} z#VWBkcHy4R5UdsFc1rWI{?Ht(Zv-gtIP-hL{d+PC;9YO}3q8x^H5Pb*EiOK_21du0 ze3&U~O$1S+$bu;cyCTZk2S&Yk7`?kyG+^LgLXLMVAR9P3q=izdMw>_{o2Fm6)ZoU1 zO6jaz(1iO`1!*-MBJB9j?zRy#|Y7Tx_rVpvJ_j*<9Hp;tZ z8)worb)7iN+v@xYqyxyK8$S|nnWP=^wpr7eWd7J@MZ9H)BS37dDgS{Gug+oNQT@%9 zQY0z%+ptBfgZ96TFQqAm*>As>zcju)Ejw}F*#E4u#8M9H+*{UiJ4N&Q_eCwyzfStF zV$**^{;B(0%GW9_*y2u{F2#>y<3ysU^T&`YwYQBUUxPf_@gwIgowX^_W=$v3ZS`s} zi9lQyytqByihdgE3-RxQMvP43PoIxl7W}m=5>0uFuuP-(>&J8)O(ll5d0_UMnH7-R z+YqG_e&r2~Qyy6+%9+NEx@1*iSNf#Q0VdP>I!OcjP$>_J*A$e220_xYWG#eibnphN{Ti>W8pV0yuLS~aB6n!Tox;^o58MX{ zYtaBbVO%b;)fPa#yx^lohF@b~kswAs-Iryz`-NW!#VwV_GluDim_W*nbrRq=r{-$r zoCwlb|9R^{x%J^of$ka?V#>F*NPvW`2jAzcL-vGd6Cx&%w8}mzYSA{XeRO|N4}f{I zl4F}-d8%4{vHP>qFvI6~4y)FA=^gZ>JN>`Mf$3PqVQoLg=82jQ4d+qb8ZV@Vt?B<) zNB5~CfXe#u%T4+zutcAcU(4<0dPj76itjnA-6o=a-cV6ANLR%o&=-M$Dix(~&_$Mt zxQg=fd;Q_zMRBx|TR^MWZ~)cHBvtb(lDt4x?=PfklCm$V0BUlQQJYm@jo08>d}3&`WJI)d*=c%po}tLaNu23X>jF+U}R~q zOab6bUGypmgN(Mm{FvwMxP7lUVM75#45fQ@{B(FM)&5m5|0o$h{upi@c9G^k8-1FW zNxv|CUdx2cyz@xyANWB<$-e~A-6d26(biA7YMB_ny|Y?v5fSS$qLcGeG`^3=XCK{7 zklq~Wu@AlMBK{18sbwi%?%+Q4b(5uH_W~_0U-_&s9A?B=?eZJyn38ta2-%|>d&WC@ zL|Lv4G)GVQx&&W0gYguM; zJm8)EbAQ@g7`jA1Occ#x`7u~`!~H#~yQdE1TX=IoB@lv6n9Plw|nuDyg$ylJNw zgQ5Dbk5s8)k|JOO$zwNSxm$7#{d;+%O(|I_BpLNcape^^n45XgiQ~L_mTM z#2dMjW*Uy@mN+|y-xLIgzUoHx$_q%-hw3&RVK>;{y?!60(F}K#b8Ik?Ke#MHv0L?y(>;M1& literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/contraptions/mounted_fluid_drain.nbt b/src/main/resources/data/create/structures/gametest/contraptions/mounted_fluid_drain.nbt new file mode 100644 index 0000000000000000000000000000000000000000..85f7e96666344db1dca7a3a1f94b83d325dde982 GIT binary patch literal 1368 zcmV-e1*iHSiwFP!00000|HW9%ZyQAvfBR*x*9jCs3kW2*Ac4dYBvjERuG2JWOJe1t zEeOe)tS9y;>z&o^Y}|0l1*t+p91v$N`~mz24dNf*fP}aK5?9nC7gXNt?riL}cjHtM zShB{u``(-1`})0EI{*zZBla0J06>0g+1G4`nhx$YZ}J_gxM7FtPLaw@LlSPtw(Z=Q=zT#A|cz z_4vq_Hxbwt7es=v@KRSw7A&k1&s$-UAihge9E~>dcY_`gRBM3I;Zd^R^83e$%JOEa zy8KeQ>WGPj^yyO@bk>6x+>oN?)hG^V*zJ2UZGgVR6BA1r zVE_cpG-kP9%~LfN~Q{rlBvR@WX`H*v#^&2DJfcDZ3mS0+Q;(V zr49TUB{wqWaiG3I#fXOo7T9eP5SNLg+sD$dxsBW_x3FNb)$5^+?D6Wc+)rQcA-ogh zfNK`iwna#zXyrJ8)ZBJM?s@kJ(vsXZrL2XFvW8sna7Gzu1sC+p1qW(3IP+*|fYWjX zJEUu9Cyl>-e}J6o(Fl@Q)wbgx@Q#weL$gDoNJ(o@OFc%V`c1#j{8UFixX*kfaIFc} z<_O1vjOJ@!w*Gqaj}O+rdv9@cTR6WvuyB_|;*O6*pHQUs0L5Ox^@ zC(hk?$b24Q$WpYmHOl$}30<3H@qI65y)Mp%0|%NrxU{)1aKzcrSe1`9$dJPGXpFic z*%w#oFc3#*uQkMZC7`5^ivcyVfa0wkHcTANQu9WJBajmfr(!n+#1KTdPh6@&y~9T| zq&*C>JwC=}l%ihP*8Csy`17rw^snGU?~8Z7{{HP>jd*q*FK2nYp5@W{uktuTrEn~d zFFq;@s6Hc)7tz}leVn>>SsgUkFu=k%KqJ0L!DiPsI{ zVc>u%4~0c#sn7e= z*!P*=pPC)YpI4`&yhlkWRi^vJDB!g-yw${DMLZURscgeUwkI1sU;(X4bO|pTg)}zi z!{=izr|{+boD*N}R|&rH_&J4q|8O3@S)0u_%K)8L-fcHd`DQWm!1ZF`4vKA}n7WlS zb;((19DnoT@at7)p-G>T;7--^rL)gMTI$z?3kxVy4~R#Fpz;lC(FQXaCW@Xz!n_eV z>bfM7O@S%vgdATD+Q~ZK6k$wlsNqAYlNJ~#%VT58lMGw5snn1n zp@=3~aAbE={|cH`G#~+m+9;XVHW-2jIhZ{z1RtiCx!vjcT85_J#92I8G}BBbvd8;< z$&CBNix87Z9xT{x{_hYpCpK?QZAY7+41C;DWDAAMdK;<)l}I`Qrmp#Dd{NW al@%h$Jv{g@?jyy03;zPIr8f956953px~}yA literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/contraptions/mounted_item_extract.nbt b/src/main/resources/data/create/structures/gametest/contraptions/mounted_item_extract.nbt new file mode 100644 index 0000000000000000000000000000000000000000..dead6de25da871b2abf64d47d2a6be6e8fdf137e GIT binary patch literal 1436 zcmYk+c{tR090%~^2?u{1F3}5>3*5{W=5Ni^!(ezRC?t$q=f!Sq3O~ift<$oGl25!m*kh_ zu0cyvn)%%hx9rAhFJa0EOkDGF-rsKtiQ{|6=G_c^KG!PC>M+WRmVUMxrw-4t_^(a| zuap0Jxv`@4&;d)}3_%`;(K6?6I0Pcc%<|#J2dP3& zvAGrfxD*+*jTC=k!`I)$i9g(H;Keh9_TU)9h}cFKgwGinDwz$C|XeF;GnP9tlgS-5k(K^+H5EMX1)bHWl!YC9bC zUjdV!*=c>Bz`*}2sIe41Y7GVoGFK}{7?;TQKtWO306}V|7l7^g1_FRd%$IM~A6A^2uA~ z`u|!T#M|?D|07>4uB3%|1%SCdBN`NjC9nf++cP9lF2-5jxSP2d(<1{OD_f$0V=wle z=AE)|th0>O1*bClD8lo0H8C{5zLbh^hlXfyfLhxLrxxYBsSA~=i0C8C2(8IG))`YZ zr^tRvr_Ab-Z6PDYmZ$xCL`s;lOEx#JBtg$WbF79BJ99mYhBmKei&CA(p3@sWB7ayb zONut=*Udi=UaNODlyBU8W-{DopHW}z>NX+AxVWv;G)E0$IwS=1l);vUP56v825;m? z6_1W=V$j{L{Ot!^HH1cArTV)vFs{ZjQ8XB6%S7absP&u%P*UFkp_&U8$6-RA#ycI- zpl&Cmgs3Eo%jMu1m!XCd2-thi1bsIt$FIw^u!02x?lcucM8QXnT{#}RjGwkBNLP(LTM#0Fyi&nP_mV?dg?~}GOfMrp5lA<_P^981N*kSq zhrHOX-FT8|j`aehd}wpJx^?u%xeLorSfBIai)jWO7o|orb@pA4f|ru-dZl3+D?4sQ Z7J7=Ei_C{#{wCU3@=n*T1Cg`<;2)&xug?Gg literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/contraptions/ploughing.nbt b/src/main/resources/data/create/structures/gametest/contraptions/ploughing.nbt new file mode 100644 index 0000000000000000000000000000000000000000..64329baa3259f70a483a3eb1996c476336de0db0 GIT binary patch literal 855 zcmV-d1E~BTiwFP!00000|D~7RZrU&u$4@>Cfv)Q=R%x0h?K#@3PW#X*P2Du4?&BtM zlLJ^yDgul=EoqvuGFa#JtSh70|0HAvI>NOld zgt=srVF}e^0KJQhCzs_=y?H-?px~w6w0;CYN=YTwJK8j!gT{Bz1Qw0wz@s%b9<8zQ zXpN1>ci_<)8;{o5c(lgGv-Z(JW8={p8;{o5ctQsrt+DZFjg3cZY&^t)M{8_6T4UqU z8XM0tPlLxdXgmjv@1O}R8qa~pbKvnDcsvIl-+{+(;Q<&zkY7jwWKpJX$cOovLrXChHw5#Cp&IaKR6wH~SU z`(m;9-FD)ezVr-aq<6VE445h^Cufbjf;TgR`IINpQP?pW6cnLNmO^ zol?VsDqAX_g;ek84J*OBiQq}~DyA9FC-ImG6>*tn9rtBD5JE>2?|jl!7J_)3!QS_j{e_Wu2&$EV;amcSc{kp#kRU hy3#v`G&VogIDSJVJx5V>mTLZ=@E5WN-FH(D008NZsiFV? literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/contraptions/redstone_contacts.nbt b/src/main/resources/data/create/structures/gametest/contraptions/redstone_contacts.nbt new file mode 100644 index 0000000000000000000000000000000000000000..60b165139b62885e7b7da2e2357fe042de86572b GIT binary patch literal 1501 zcma))dsLEl7{|d|Wr^J|HPociF3u1orORx`GMi}~ttL~CfVWg+p%E-~VDn7NvdAtV zHXE8($P|^Cq)yF=yxGhSiYV%0v?4WgsOgZsFkS!d{o^^`^LyU+`+R?&=XJ_m2{AtU z2ZK_w!r#_>bZlswlyZ|NI`GAaGxQ2Cs26#NWr12-H@q@Bk-zq*0IE;k9`40{*FQ_S z$c&rKhl@&gM7)r7)gJKFS0o=giEx0m6qQ)lk7m_4xHP>5EIS9@+iR;S`jGu3(&ng- z-4{r6a>D$5vQ#vjRr9+9wn5skdb5CG7JAQH`LH1;)^baG=2Zw9oxc;3+NA=V^F6bV z_aM+%&lR7vp`n?E#-ylkNH~5j@i0yy&g7HE#-zlVv;RE@wV{E*gYPV9u+dyc;+#f? zLhN8MW;a-zkjfp+!p4*<%v=FyzhM_L zH&k@lx;?qgOL;H2$y@!KtIZJNoHt93ICrZ{W#PtzVtq#4Lr0vvWmZz%bfiutoGsGN zEar~1=(OJ#>BaVo#oYEiRi%mC4&~l5#*MC%@W7zwnQxAqpQp$5MQlT#dKv;I1Y@mB zs`2{2=I=c&`qyqjUBT|Q23HL-mJ zu~4-h8(WvU%MZRaR=s?2BY{=y*bZQWU8SwT-x5`og9GP!gn$$^wjWjx8sa00`9TRyT+c0+<*CRCtvgJ!14X z=0~c-jQ()EjEOr6RDhPZaHeq$1=n`@A7T6buv9x0>NJ~IGt3%diGk&6{2^H3Mn{h_ zV>%ePH)H(&7FhEQ=wcGL%CI~T7dXy9DXEpeRecJy?B+u~!~ZBJzBFubsfv@E<2}gM zw!8fk{|6+*LTAA8F9P?F9yXdnK=k{TZf%dU_TAcs0Q2RoOzk@P)CUP1d71v4IOO=A zfCRx~@X$3~nfYx?fdJ?-AOorOC}|FM<{AqfXaHsc>{>E4UI7YDu}5jLzOD1B*D8bO zN1U#4(i3d%WQgBd$5+k|6b1+Ooqi^+=1O+=y9+iuZgH69HvB5nJ}HI;4a+_HvP%&u zFA92uj|R#J9{V-vih%_AUga&vsEGk3q45#M_v<|Qz>jnVAj_@(DotE&AO5)6spzvR z!V`@yf`P6Ac*${n()if^%qJRV#n8+I?Rr{CmEvQ1G;&O_Jzwcy)#p&B6y?58qSOY% z<28&gQ$whHpU6osuZ6aYp(kG7=E}pH?&wqvQ9N?Eh!WQRUGY(EuNGCGu?aVAnNq97 zFJ#ufltheE>veK%Z`0Jqu(zs;QtG0WqS<}VNG0vUMQsPXe)0ij@k1qTv6D*Clq-LZ zatXM*X_kG^(W0Q>ak9Fvy<3}|qUoMjsS6%Z9->oo30hvkv&1x7ayqV8Z}sA_S`e= zH(|f5KH8P`Y_`Z=TRR~9c*yZ!_1$lF$+?c}HKJZlS`YO1vjQ6rf=h9@T~hyuQl3aM3hPs_WMhRN=mnOtWvcH7`fr zr6!96*PKG6MpI$ziSVpAgQFAo%1fh1!@tJSE@(yF8gUIXG1c|bG)P2)+sz*c8;%5Z z9+HwP;n#=GqB9zvI_47CL76gZMW-iM-! zN=_~3dl4GF_$hAi#G2@kr?0QC?X4%LnySWI@^uJMm@B>@p1(KycEea_$XAx9N;{D# zkPh4TF(8@H3_3Feb{7fdi`?UmAL;SOI5~=sc`1*SMhOatMJrbylsMv}gUgs=A!XFt zO1j5e8v>v`mqId>{k5^x`|=Dx<#A+0*u24@BqhC)J5fKf?wCKym`{QEn)fUXgPNE# zD=Sn-DC5q7bgYOKUnFXv_^ER1W{U(xqesstEd%tt7k9z**bkkB2FDe=m29J{p@S8N zXy>bhb)Ee_!Mnb)mhvDo?<$3>#%Z+-p4Dg-`8Au|CNXbkN6kt?u~I zH|sQ7-8H9bmz@KL_VzU?rsI<`bnVj9YAPO9$uSon`dxfz$sT(zgQ<~bbm$opMr2W5 zavjY#v}pU+)G|~Sp0#D;G>K_W?x~pTQKJRC486Cs@`F=xIwZ1%7}PNot9&^z*zC#g zJjAGjgDYJiK?n8ARbLoVgAPkXdMxgJi!PAACU#EuS5t`7!!-FB3M`-hi zG>MABJXJ+KVYLo;XI<^Nwl0Z^p&4x{<0i@F@oZDOQa zt@mC3+y1w_77u6HC$9_;lGo>1-3wIfu2GTh&eySSGDu4cd2V(j#wBQ(*!`i#y-HAn z6*i^io1&g;^)1bansgq$fjm=uM4$Ca9YG!7KG|!u?(B72f3m~7ZDZM62s=Ay|G1Sj zvTToGw{ z&%%uUYw@CsrJ%Wsff~hXeZ_}8-^>Qv!QuVp+=@#y@%+im(8WKfAJ^u1;K;Sf`?Tw! zm(A2pv5aRZ1G25{suH9)6=SQFvd%NA>qnFQ$7J5#l|$!>_qKAyW)*D|jw!c{S?ho1v8I6U$i$@FG2<=W0PzluhxcB0u6b}#h2~V10m5cRs z(gWLc(wP>|cWc^FxyM~WrpA0@dtIfBX9fa72zh0^ewpT)u>Me9wsF1?tM{ILKO~V| zUkuk;oz9LY`nMb^DQRY$8svJ`Wsy0Pj=4>oz)K(TB|R7qVs>A#)3_9j>T-F_hR`%0B?tks7o?PrYi$P!i zZQSFmTbDTuU)Q`r5#I+HGOA};6J8s$c(9Wg*?Jbk$R=}xOJ@=D_U3eGN`vN)Y_^|^ zMfXPY{oR5sF6rjX^YchJwa?=q6i3Udbj*uWUino`z6?3cHI9cVw!c*)(yq!SA+*Yj zuTWUYGWnm_tP$!OW?hjnH>O)vHl4fv<>e2mOWSdON zZXGXa{+B3?$Y5^lv7R62Am5^FD~a#KNXXO%MgvzfuYxq9!659BcJzk##_WXVw>Sg_ z#nd12Wx~fD#U^hZ;FN624oz8w?C)X&b-S8J1Hjs=ZYx%=$mE6i6}LG z={E>|A6d)rd|7(*)(9Q7QP~_D>DM0gGGilh=tn zfh4(cavLt<1|oQH)!PYDs%{J)z&0y!g7v!rrg!Sepa2qZU$FxKdo!BK0P{<6?mis+ zUMzqQI05+1%0887_}^ID0Au`xn;7vjAPy>;Jg6XW7X_q?#J&EPyR2pD@OPM1>&s7f z{{z0MqzW-UF+DdESH9_95Rzq|BLCuy6H43cl1)zrO|({*#; zWAMZl#)Sl)$78aC6)Ot4q{`;U@p7K=7gCk_D*{D}@g38nkBJFN`sHQ;hcQcg<>;*) z?Hf)UvKtm5{L;zpEG}%b1GQ&&{g?uWh!4s@e>6v_*_>Ph8h~8q1ORrM9TF>?0BQl2 zf3yR-6vgS%U(Q=yO5W_!U(TE^ZR@wd1^*vhe0&e^kTp99bBfCmsFc@nv} zpRW}h=wW@IX~%rrlEVkNjq81sg||Sc5^$BJ^6#9$RVTvd1WEW*JD29>lhS=)3 zZ6W7b{!vK>mib>soHyC>3}<`VV*%Fnu28C6fUazVY$9_WB1Rv#e<&FI{DMC39kOjfI`6Vol9^I*zuiTfFD8W6pKnxp zb~Daj?tSQW;$^aK+C2r0^}@#XlUB|mVHFeiZs?E3GylPH&F4_eqU-knQt&V8g!la4;$>*@jvxFy(s_y literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/fluids/3_pipe_combine.nbt b/src/main/resources/data/create/structures/gametest/fluids/3_pipe_combine.nbt new file mode 100644 index 0000000000000000000000000000000000000000..b7a9d2b54f87abfcfe51fb84266e230661efedd9 GIT binary patch literal 1141 zcmV-*1d96~iwFP!00000|J9gHkK05T#~;7OaTYBgUL-yOHzZCKEo`<_1*&C5XbW7z ztUa5I*6~=Lant1#@c}q;7j8A8mkAh)|i;J#>A{OCT6WMG21{kYA*H znVu?a>l>8a!Rxnpy^YuJN&pAk3D)$=weUf)U?~?&URJdJeadEYg>DC6vl!lpa)hI| z&Xa=0Q%TZ`5Jq3)<(Q`u7l8nV_tZ}(WI^E&JEKuf&gCt-$mAvVceLO|Dxt+ttA1|| zj8z-zfj7x0jgMFAyVpYf{&tiZ>{P_KCH5f9dLfl=INTW%V^CWphl7gzoRt6l@1}wPbc}EDFd1E(1_^UGn zm*RNgQhKTwikx~-S4|Z)n8q5}zM@ZPE@<4-icx7r749cyBM@v!cfm?1^{Q-nN83W9 zIZ0VWl4({fGMot$UgQz2^Y7zE{`qaoL^BJVJ!XL+&?=C(>p%osWC@*KUJt1_aUVN;Ou z+$dK z*v|;^(j0MGL0;A6d)z2H?sYBSOKg;HEZ?KQ+xBqH6tixeq1Uz_Y8v|HKV62l?T2oT zq5l76=)uD-L!FmyC^QUx{(btLjl67l*KJp*tWsN76;8*tzh&oYHz6h zyRkGo_0RE~gwHBBU+Z@I7*t+xFs9Xcx6yV~R^5cpW;DJ6(H*MY+PcGz17fcpUGkI( zu%50vJ6yXpTh1v>n!Qx9lumSXS)E|Cq}uLZJ+CC!cXn}QvWvc_^<9U@Nxa-G4hr(#(~jYBFQ6~3&vBdJ-@(zjgqb^ H4jBLd3e7JB literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/fluids/3_pipe_split.nbt b/src/main/resources/data/create/structures/gametest/fluids/3_pipe_split.nbt new file mode 100644 index 0000000000000000000000000000000000000000..88f648db6b679ee8e855201a36e9601f52e5d188 GIT binary patch literal 1128 zcmV-u1eg0CiwFP!00000|J9hwZrer_h7Yfzs1!+yUVuJAb_Kc$nj*H-AW0L~sM@6M zMjex5X<&*&aE4Kwm5>L>GTW}(F8T;v^o6?YvS&z+q)_C9Nfg5-V9+Fg9)9PaGdG0* zLvRIqMjZf9e}nq$4I!YZWRg(<>KKB5obc#Wgn04g5S)w){nF}iz!Q>4TEEezv3h9i z9vY{I#x-cH9?V)}V%8cHv(}iHwZ_D3_h8l<6SLNsn6<{ltTiU)ReSW%n3%Q3#H=+Y zX00(XyFHk-#>A{OCT6WMF>8&9+3UfqH6~`QF)?e6iCJq*%zh7MtuZlcjfq)nOw3yI zDsu=w?m)N~N%n-^r9@Wn!Q&YdGO0#N5BzbFWyx7d4WlC>gjQSN|Cq%X z7_%9ClTKM$kFNOOF-v2Hes2H%#q#Bgzr^0>|1Lwg@_-2WZORwv zk;1lqLfJh$|BUCGc>bjXaKIhom|nRSJ}Bla<$}qxiq^kN*>tAR?Eq{R!-r9haP-DW zQm}X;NqQQ>=m$I<@KoX?5Ww(`dUQzU6s}@08s+3f-dNyEXotTy=S7O~uK(9Is9BAM zv1&s-@WvUX@xfBvyLO2GitS-jTv)-Pny3{^?A? zrPy9Ll^!XEBB!cX*ec`lFts(ZeNUgzT+q0u6{FIMD&1RVBM@vsx4{%s30K+jskVhi zGm^51B$KR|XV??QyvQS3*Wdj{{rPRvM6(K<9ae!M(JGNo>O=&aX9=C0Vg*YUHS=ip zqs}}wOTk?Y53NnTfBla?U)$6nhU0~twKYc>pskx`ETb(`o7EU9z1Q&RQtV>b6r?;i z3OZ|Qf87+llh`a4e>Wz#^1rRgn?*3_ZE_!rKC2O?3CXIi)X0w z-VKF@p>MxV|9Yb?8{T!>6)LOL(p9C?vFvYIx!R3l8(vUv9yYvj-_4utF}0;`?8eA; zS-g42y4fBcJG{A!b>r{Wo2@N?_QrX|n;{G`l29qB`f)T2z%56zkLzznJj-Z4iHKn7 z6pajza*j9DPpbijnGsyc_=|FM4#1H-1Mh?+f(GCpb1C^8T$$s3Rma`Vr5V&e!F>{b zt6Y4o-qYKl@`Q~ssrI{#cSq&6KH<|Tjn^Qp0XsH`y&}5gDHC8lT?M!K?ytY6)|sm-yI7m-qVH*a)!}iu*xU_IeO2Mq7w1W{x@^JOp*yVz u4oPHp0d%hN`}CMP58Yvmyk(DZV04>E@`&bw@f63N-{60~0sz$x82|vk9z3!D literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/fluids/hose_pulley_transfer.nbt b/src/main/resources/data/create/structures/gametest/fluids/hose_pulley_transfer.nbt new file mode 100644 index 0000000000000000000000000000000000000000..f42e51fe69c5b98e3404ae8c7c137e096db2b8c7 GIT binary patch literal 3467 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/fluids/in_world_pumping_out.nbt b/src/main/resources/data/create/structures/gametest/fluids/in_world_pumping_out.nbt new file mode 100644 index 0000000000000000000000000000000000000000..cfa909345d2c68f3f4ddd38ee3bf207e3030ea50 GIT binary patch literal 853 zcmV-b1FHNViwFP!00000|Gkz$Pt-sZ$6vQQ%WfAU2Q~4cC%*&j+6K78zJeYXUlOMtp@uu-(cdBjf>f8T+CME zVzwF=bF&7s)wr0g#>H$kE@rE7F|!)XR^wu}8W*$GxR|Zxx*GH*e0f)#F>iu-n#Lc~ z1mLH8ngQF&5Th?=W^R6+eyU>PX%>;v3!sTyX=-ThKS&Hm?MR;kYISgQxWob zHyb2bK&Ip%52>$v&q#ci#^*FH()fbLJ6Dy(p~v6#OcV0J<9koelJw#zbAfbvnR`sWPzv1Z!yxRjVgrjd_Vbmk@B6 z^L@R*MeYGxk%Lqly7^V1_+CuAp2@;{Ri(4#@<&N2G}6-VHc!i2wh;h(Oy?`M8?bb0 z>Z-NP^FHbarzTR?law8g6gxZ~pqV7JuCcKqQ%zTR8#=vsAfk1iAl$gX98z*}A6gc` z|7lh_92T8p(qWa0Iu0?(^vNZMWz5x<)C~GxF#LCi<%yZC4*VWhBBd(dphmJE%VCw5 zxx(DoW1>W%m*ND15JV1;mt&9*NIZQ{Z#tz5SC1cdKffj=} f!re0Av@NS#^BuaSgiPr^`vAWIBT%)Z_6q<2sZpW3 literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/fluids/steam_engine.nbt b/src/main/resources/data/create/structures/gametest/fluids/steam_engine.nbt new file mode 100644 index 0000000000000000000000000000000000000000..4edf9e7bd5db6f09a2baf4f2a9a99aca3835199e GIT binary patch literal 1594 zcmZw9c{mdc0LO7hBr7eVWsg{6bIdY^wD5WfHPnzoZZVM#mfUC3R@(NyntKQ9*nXBib&?GV8+49m!gRMV40y5Oe{t2WGL&f;d&ja@r@iC3`HnK-ax=YI#e!Vi$y=w8we1T+l6L5TFFTZxRfum9ei+LFxPVDuSwIDodZ^RhdxxE)A6aN*3;l z!)+oa(Ea0{`%`siK4pVcV>%!F`~5bescQ6}^hftt=BM-rRIB*I`U$$^{y%tcSn=?U zICR4c1-}Nhvm5(&dR_=9nUFn5@!R3aEJ^HE zkANR8Nm!cEK-`cC{uk!h2{F<>Cd_3QOfi<= zA^%ugF9Mn6Xo7_h-JJr$iF!?+UV5}*+pddNa0}yu!Rr0vQEu{}TZf`Xd!VDz=iPV8 zy6Vag)Pd~YIo`3&Ux#F_8E2vmeDhrqHMxVry}KUdfKFLIdC_r0)%t+vEXicTfBjtE zJBo2=dp%Vv@FslY-IB@X$11=r-{K)VlJPy57i>6~40ouo1N)S5?5bc#oeE2AjXQKW zYHUJjAQOR~Q(qYjfceC2ayE`y-Og(I#%gFDpy*msqA|zm;LeoyO3ARfAS}Dd0qiw$ zl&A#F@h_+PR=T37e9pu4$P;O28R=_sCuk3x$L4>%SXqdS5GGTR^)B%Xj$*55LU7#(Fj9t(LQQeAae zqD{1|$O`LBNGJ4#e3wi_C>lxDu0x_K;SvrQ%!aexd%iw4%T z3wIYxy{xDA<#m~T;Dvk8g>fvM@Ckv+xI0D=2ccs^`LkCTlkrYtv?Web&Wh7q4lPBv zQ2wP+y*+>q^o!^^A$GAVG3`~Gz)X_QbmP&H4T3ad`*hamm1?52RYiL6f<{)lIpjsb zCFiaoTyi4NG(g9)by|d8s({`zDn;<(``ota5CBKkm1eTf?E}B|izsq%o(JezcpH4x zI8@Ua{nf(pKvL8fQPT0-nXK$6Mk%V8dic$F ScvEt^L`u0MR>2=7CG|I3tP`#P literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/andesite_tunnel_split.nbt b/src/main/resources/data/create/structures/gametest/items/andesite_tunnel_split.nbt new file mode 100644 index 0000000000000000000000000000000000000000..ab4e2beafd62635ec547bc180917ea8cb46c5b36 GIT binary patch literal 1260 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 AI{*Lx literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/belt_coaster.nbt b/src/main/resources/data/create/structures/gametest/items/belt_coaster.nbt new file mode 100644 index 0000000000000000000000000000000000000000..df3cb2642aea36757daca5824b4cdf0ef1fa6859 GIT binary patch literal 3459 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 UwN7R0hZfLV!@k|X1@iIz2apVvIRF3v literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/brass_tunnel_filtering.nbt b/src/main/resources/data/create/structures/gametest/items/brass_tunnel_filtering.nbt new file mode 100644 index 0000000000000000000000000000000000000000..c877ddd0aa2ae5c48689090ddbb76b45d01afff8 GIT binary patch literal 1650 zcmZ{idr%UH7KgEXP?)*bLTFVQe6T9I7(TKTHIWS^+fvJSv_4pTl_sl^s6nfhMk=Og zEo4@T`K+`8Wo1)P#5QGpgqWEkH?f<#KCn%_&EAFCQ1AOsi@^%od9^uPRHS@Qx7`ak=heb(QFaXbGujGYkxtI1DALPqEdNXP_z87;vki^d?QhaU}-){C$TTUp&6fF8WEM$;rO3tLUtqUSD6E%rZiLc;1X9WeNyr*(3F z70ILEqH@ck4;~ZBI>!;;j7I>@+?2iEI_Oe-s;wt)>yb)zUXRKBELb%{J}~ac}9_w6ZH6wJisM1a>XEOz^vHEC8fpq;529`wa%~z znO!V19X#f}Mwn!uOgBw+N;|ckQcpGC%4)UVTSLLJlepZ1=m9!~r!tn71GG09L9I4{QBg^coJUcQJJj z9@W}4t>%1B{(_FL05 z=st@@3(YH_=JfpBLJCAMF-D@@@<>V<*{FFo%AqG?T*va?Tj(dka-DvPVJi%X1U2No zxfyEI$Ouy3u|+?z>9YW^m$o67bj0afh=T?Y`LRx60vD}zek2)r9^Jj~0S^80k?D&iBZ^P84)MRVnE_+w2Dt?5S!%UX7 zX=|^z%`Q$omp8zX2=id{C2MyQLUlB#A%6^`U80njs1rP^u1&B~3ZssAu?L(-u7Axd z`Z4cNqv!9?{voaprw-AZDe_C}M&sqw(iv#tx=IWUpXhm$;nXa7s2zUZra#L6HUleF zpSx!yYZ^WVP7zJ(SFTT{@UBm I3jqN98|nihcK`qY literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/brass_tunnel_prefer_nearest.nbt b/src/main/resources/data/create/structures/gametest/items/brass_tunnel_prefer_nearest.nbt new file mode 100644 index 0000000000000000000000000000000000000000..bdbbacd9e4e2262b3f8a723117bdd57e9314e991 GIT binary patch literal 1371 zcmV-h1*G~PiwFP!00000|LvLWZre5#hL2=Pu@$@Bunz06J1J0LZQ1|~)y%t~WoRvHtt(wLZC3udJ;F)NLUS!qnnN@HSPKMxCyiCJk(%t~WoRvHttXThvA zCT68EF)NLUS!qnnz6G<=n3$Eu#H=(XW~DJP2NujqV`5es6SLBon3cxFT(Y#79gW7Z z(6|r7V!KG19~7WLyj$YOde`>CjQYpQdaiXjAh zBu}zAc!x)a??VXh`>8RfEzBQvm`x}78jZ)qAhq>gZ%X1H!6Trh>}zdd;~op!~0 zvh`R(7#(DnSYblUK?(tDf&}|XD&)pqC8b{IC-;$)L~aY?O7>JPo>#CmJ|%okMYUe|@Ioqi za$bmpWyhS&Reg@z%k&0&h^uv{E8G$6G&^(P8Ezw(B0=MmWWEp%3aU1x+1zr~ip$#f z@i~V3Uc7(N3(kW5l&o@t<4_;xBtbaBeonWE<5EU9qYT&JsiOq*vl z$<#F&Md>QUmr2;dKj!o@VMV^){57^|PMOJ9+x(Ah<9tfnxL>es;Hz!ERND+TY}2jj zJ7D$|14?5m29(BB%6T2kI!)hUrH|RSVD>GTeG6vaf;q5Y4lI}h3+BLrInXfgtVl|Q zpmLr+8{#3BEUB($t!{2jnh;l?73K1Of~c91h=M;$8RJ9jon6VL3p~LKif3iKTfS+@ zS%If()n%g)PU$7x>QvM0d-cLoUhv3#R=t94HEuI_&|Pd!AiOyW4D zPaTFaQBM-Z<_KGvdRP?d$BlOc?U8q{@D@+me2zX+!>?VLF)kL^kGR1B1BsZ@E^k+d zydHb{`GR0KBTfY;a*JtYZ{6`vH88;)BToc9li{4zC#BXPb*Dqz2Z`Jt*R$Xny61eg dS;;#39TDUs76Mph;PLZM_y-{=f~*}N003Ejo*V!G literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/brass_tunnel_round_robin.nbt b/src/main/resources/data/create/structures/gametest/items/brass_tunnel_round_robin.nbt new file mode 100644 index 0000000000000000000000000000000000000000..310e8b882a89b2e74f572f201557e2801898b526 GIT binary patch literal 1556 zcmY+Cdpr{g6vtIqT!ci%bV>Ti!aNosQC_ztv=*A@9>|#Drm09MVYa3*73z~BuP~4D z+H^JZSk$B!Ml0F_X@o7;O?^JMPv`SF=X1{Y{LcC3oNd_~<$l=e^bKC@JE#`RG~hIP zXY5`a$WrX}w$&);qMREL>{d5z5^DTbyCPH3ZRcV9jaDaCa2UQe>>+n%OFk%YZx-%q z%6q#*0Gs`Pc1b<|J-g)V=<$q9UZ<2b?>__Oexmqs<}dAcq`&v~@kJ2L7ZvVKysB$!f*qpKn)QFLw*%Jb|B^|CK4p5@^RsF| zo(ngAP+pNZwYHx=#T5T-nOI~B#WL~;o=M9ORJ_hQqQJ|dEauJ=S75<$b5P^w21U>9 zs0D!I6+v+-O7b@ERC_)VD7EtV*^mbj1u0}EfBc^XXNI$?*Q&oVLW`=`OhR?i#j2c1 zu~aG@$XtqYJrmw3_u-9h0Wvb~=7gyFYV>|H7xyimw>TI_(4|WQZYqx{i<={hnF|q* z_GO4H_OI57&LV?Yp&5-0FQ2*8b;myl@04$tW}uf3dQSvzjM?-hz5Qs+p^E7&;dP9a z(TY=G>2kXKm4|96TPYKVowrOTn$c23mN&hXZGm}tLNIH*G*^(s5hxM`l*aqAnCN4d z(Q)LG16F-cKgzWfh^xw*B%d;M$nT5k$BoueYLHY{qC#L%w*Fv_pd) z)w7$(LidC^9nu_KpQKk`sz?{mKXpQ!1(qugp->K=M47%p=R|JB7`k2cI zlq7M1C0L)7;!fO!EaNJ<5u?Bp_AS7$A{HX|Ep0nsvOF!I3_|tt1<<`w;RxrB3|-r% z(?iYQ{{)dM)y58_uGI}3}Q(w9FUgH~H3l>Kyk_jxz;aKui&8M`SkUAvwDDN=EK&D=6K~ zqgZrYh~!Cuys!D^-&NPOQ|mF?%OPw2k>av;nsd70C^Zo60AO-3)jlC~Ceg|n*)%+x zIWQB!allgx3oBoZUeEC_Voccakp~AI7(M}tN~JV<=KMsB z&@LK5(lHZ z+LrjPTi(={r&lw+K1XX^u;Mg3uGdXkJVn7SY~?J5w`h>@kc)xFhI$7qTLgyEh$spg z$L0E~!OxM2ur4UusUMB$nGFM0+cLP|CX4Z0_7ZyiSa+(h=z6?i*&wkky+)>Nf(nw= zop%pxg8Rcv6Rg!?$`zVys@+RaO30ia8;}jJ->i`A2MRJvgBQ7zKl)Kuh8-3`f@JTW pXR#*{Dyd2cg%MTldcF?)#U3Bn{s#xyU-2J8Hq3df%1q_t{sXYT0tEm7 literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/brass_tunnel_single_split.nbt b/src/main/resources/data/create/structures/gametest/items/brass_tunnel_single_split.nbt new file mode 100644 index 0000000000000000000000000000000000000000..ec6eaf4e38066244c32acca40039a44207f153c9 GIT binary patch literal 1209 zcmV;q1V;NGiwFP!00000|E-v7ZsRr($43wPq1fF%fnK18*!@yuvkhuskp$~t(e9Uk zk!V|pEE*)0*Qeg3cj-y?1VvBKbSR1PBN9cVYakG8{W<*2Lo-w&fH8zJePjUu=)XaI zC1V(|T%{^y67**bgX@gPH!{L6pT-buxHOBJPXI(Js#v|EP2)LedTKav(ea?eFtWvu`wHsjoD~y%tm8lZt~%vu`wHsjoD~y%tm8l4jq_{#>Q+k zHfE!-F&mAInK&>Tjg8r8Y|KVuV>TKabIEeR>~&~72aWHb2^=(`MdLXz8;y(iel0N?)n^zY}_1O{^@n3Q!j9?fIHv+N_y3ikB$^mzn+n!qF$3_;$kx#FS& zcQ<^&3vn%I709#(iL*k*s|Xdm5HZd}?>E%^ir3%q`WmmFkpAzs7I>J(@PM@{tI15B z@LcIwFoCWO-m`qER`uFhp0N8Z)lp4#%`!ED!3mXVzJ&1X{Op$qqOF|{%zuzzJj-u! zf^+dOM)QiTWnJIX3odc4-?DR&AW4@;yG2JjG`6B^hMI%MYbnhAI!V}us|Y6Nh1wMA zZLwHr=S`YNdoH%M{KFg#`f~(bIr3~dB5yw&&*yGQ>fqds{IEk~i+t!1d84tlsIVn& zUp_lwi`Rn=jm>M~;5BjZnzVY|uCWah;=l~`v(z^L{T^nc=^KE453|wq4ZuETqv;!f z&zY<0G6kdGH9QXsDdTGD0XgACu70X&?>qDO2`c4PTs?i&tyk+bXR)9Q^(J01sXBJv zjl`%!(>GT8BH=qk!f%O$Uq>Qpr%uyM>GoX(rS3`7t>-k= z9c)s`j@McQa5(iAMV_;)gJ(BB;|@*V1n7%T;1HjnB|csgpUJxvf6Qa{o-Ilb$MC9h znkAQ1ESakM4uS8rQl!^~N_l=E_|hB&u<_3y&_Yu6uePv_VYq9|gRii^W2hBNKBUW) zF0o;?rYzc^?0!i(J71nF*jfp{h!y{TSixuVG^3ln3ebI-1TZxzs6tWJ=Qndj7ZH4c*2UXTNx}XEm>cWL!w<#}Va}et&!rg}=>d^EJ=e~!+ zX!?e8U&{|$n7cH6qqUEjI4~0jX5zq1I+%wWnlYuAegcn1cwDAy)-@-po6m|c!oIL! zLjT(fH47RuAd8H1F+%J7PB#?@l_(gV`0#Fd;*-3A#a3w@5F49Ll z%+jpcW%uaY{J3`*?AqCImm3ExPhPz3!3IZnct>P>xy0xg|C(6mT&NYAQ4eT(ph+^; zma*!%&=YhbR}{^R1yh3RMs(mqWBA9t($mye^}s#Yp|&_wS3-BtCa?F)R@YFflmr|0za{qw!g^S$r){qy}a(4k`RF-TKu{{ngD=0sR-d`8^Xkb>(MrbA1Bf=bcTTZ=EZlMll0XSPwL_1Z3ER z>VKc(MH`r%>_$?QF)M>EI)@{|QM0|_* z+FX1#aOE|jH+FTp-IvPiQl?=a3Rf5;L%yB;GSsgvJVfEtoia2n>KPh^S{LNxKS4q= z)sGVMrFDX&QE{I!YOm!(xAa}wCSMx4%Mk#((R#Dcos!7Zn*O5ZT|oPExo~5o(b8SB z*d@RK*%VJ$NO$1YPs_i=7{!5|T^_u%W_9Uv7NS^J!$M9)_q)uRqOIszNZP&PH^qKp ziflo{6RhjwH4?Cax39(4#{9fnx13Yh$uT|B9Bvrl+BVOJ#}_-hbXYX?%GW&(h!JI0 z{|yKHp@7%wv%5Zzk=-k_x-b|R{fe(fLA`*5xK3U1+!)_YFXtYCv;J@2p0e#3Gnzy5303}zVNp6y zR={l1TUP^#6@`nhWFL6+ff!SE-CoXY43-!K&7ASDOfQ4N4eku=HAW6a<&RSBXkg`S z)PQ}w*^?i~v&Ky55d_$(bxHjLderg5>l*tihEJpg!tktxMKB*U#G;|JSQca2J(Vfk zCFnrxOPY&D!3l%hTGP-3EQma*v<*wJUDMGt>XYDwiw?XQE4p{dty;-&)%iC>#1VLE zpHm58I!|=m*AD*N#=F|Wkt^fzh@I1|@fa*-QxdzTm*a4E%hmgXG^8MqnWjXVAM7Pe z3SMK68G)o_hA-jY9Dc8@5;LeJ!`4os0jDxtmGj#btM0sxI&7mi4u*F%#X8KPQ&C?V ze^+7B+^&$f7A60wEwt6<2*dd3ddIka=z4J8M*YQV@_98@A6PJn&1KK~Vy$`LtjZ%c|yLT1MS63X?1CU^dK5 zCqQIg+1y9wK_A)T9u$4k(O-y|F2Kd%N_0TNav=$mLyU73LR3xMA! ze{{XoO4_AXVQh}Ov%vhsj5*rko&w}Tx{C;le)II#cb0`Jb4=E5lJ!YVj8Zn{cHphd z$az!Qc|%{$yTIDAD#OzUh&aDRFOtDvB5h&hqfYBIIvp+4%c$D!^x5!fPIN-v^Ox|* zrtyJ~li>tTn@}HD7r(6EF&kkxL*M{>r9OCocA2y)=19G8ySYp)YL@J4ku22AbS;&G zvSTC{ps8f2ONn7rjb|Mj8e@%yjEC4*Rci>~>D}$o&SzEH-FmIa29P7!EdyBzIyA}& u&Hgf2woBF1wOfabd~7ckGZKufcXcGS?WhdYwb=0A5G_ZKtdey_ME(UvJsSD| literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/brass_tunnel_sync_input.nbt b/src/main/resources/data/create/structures/gametest/items/brass_tunnel_sync_input.nbt new file mode 100644 index 0000000000000000000000000000000000000000..284d4e143faeaa380bc47b0f6ed718998f2dc4f5 GIT binary patch literal 1715 zcmYL|dpz6s9>xvFr4_A9N8)ZOQ`%P|k*;;Cp?c72sj<2wii8BMTS?P!ET>{3%czo| zSdo=nG!0s5X&mhcKXTl9q#A42RXT!_ik*cz>Dt%X_pkTsd40am^T+e~IM9rA{(L*j zbxT=uD9fSt`^ras-1~X6^_H)xsDu)oVDsrMNOV zZEU;lx=JfR%p1WD_a0l1`s-~7W`@A9Ca7nXnbg`n z>mE+Pd@x$N*yL{roGUZg6weTf zgjsnU#0o=__aa>blFg8)oA9G7DiAu}I@qxGjp~iVhWvYCNPJ@X+Z%&h6pUH8GciB5 zS~!GN6c(k z zW^j3z-;y{X3=M3_Pu2MXk$c!r4-iQWd?5f%eaUah?)tJl=Va3c20|aglYr&p!329T zw;oprQe`Nzc|;wH`qpC<)=+Pfs=4JCpW^KdpZO7A@z({?d4Bl3w7q-J#V5ctSx06?!Ytd}JxiKVFosgnGFLh>xuuyRFVUc-To(k%C@}!_9J_A^kRb`@ z`N?V{?Rm>SgOT*HO=4|bWL;qdMr{n3@b&43+PaZI^F&)$O{vWBeS4FOOpxyT%8UWm z5}6CEULSi+oMFb~nJ%dLl10qQRIK(Fcmh86r@iM*n(!p%k`Z89B6EUy>tm^6r8zS} zR~Ux5WDFeo7|ReV&6vI)WBp2GP?*LSn0GGgt@ioZ+i#skwro)KBih#&UT&C%W#%E= z%!|%FxE1Gy>cIzgD-zxyi@Rge*#rMX;2^sz|L7oRvo0`M2dDOLvN$WBK1@wL@1}^p z-raJWiGD*5C6$x)R&`$0zW%1E=EDB&U3bCC=j3Ym%Rx~fJ?2}~)5O0GvkbCptkC-H z9yc3CyjWwD@a?4(!2wBWZsl=@AZN-weA~OY-8|5y&#pn{YL6KWn#8*rR-}^0dc0(! z<(Ifwtxyar;X5juZdY-F02IJ%Z5Ts}4c-2XEzc)e#MMZ7XfnLM9cNS5i7gLm&EYRr z#&iT64yhpi=Sq})AAxNGtvBqb3m8d-{3^k^Uygq4&;5tqb#H9t*{B~E$A4RFxH~i4 w5s6NH6wv4vgP0;c@r|lY=hP`S6ZJg{N2ff@jgv{mw|8{XpF24f!gX~12a2de3jhEB literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/content_observer_counting.nbt b/src/main/resources/data/create/structures/gametest/items/content_observer_counting.nbt new file mode 100644 index 0000000000000000000000000000000000000000..61719d37359cf244bc72255ae2c6f715fd681dd9 GIT binary patch literal 933 zcmV;W16uqaiwFP!00000|J|5RZ__Xoz+YmgP1B8m#+b&jN5o;1IPHSa5YoiN5StKi zsod1LjMW5W7W9QJyg3Ix`> zG@A83eZu-Mp_||wjw8wvovn+@uUAi=e*bd$@Y|2@=VJt38si{{CUtee4!W@JGb#t$ z?FM`plJj;LM5i9qj^YvXsSC~l>CkWj?|0!*2K#X&b5$Nsy-tpv(vq1vQa@efULQp>*u}Bt8 zqO}U4d~Z<&qwB3*+S@;vm=dz)5;LAiSMvIsCz47pKap^jUIU!{zO#(=T{G+S=Gtsp`zMr(iq7R%oKwN*R^0RyQL^IlGXVd`wVduwxf&EV z0#ve6%If6)n{~?Q_2sNLmayJj#(L`(x|?4q^$JF}Qn10f1DDLCDn@r!!X?gCjLsRd zU0~7q&R*cGm__G1dx5iJ7M<@FIV(ozY?V5vD;B}p-iV8Ma7@p{zMR}=$$&0+vu|Pb zb4$q2)^6*`cI(20)i-3Uxt+|!d)YLNg0q0O#i&CooboktE0{&+r0X@hNp3s(+;+@! zvrBqX%*`(CNjamNN47zYP-%_I8QnZW2F}R985uZZ17~dDj18Qzfitdft`A8_g`mkB zui*lIMFzBd_g6Oyr*sdz*DRJBfAX&)SH_FSl+i9YJrZ(x!mag)pFHkFF%u_H93p=% zu8f5R8|6Y_O60piMXLI1z}!rpu9q}xjwQjuxZkhLRE87hLkc*gy_xK_H{8tw*OIP; z^fp2}Ea;#7rgXC#k2)c3%K>D-UKqzL*TFH(b+BYZLeP9p1bIst58?=5WgC70DfN8- HtrP$NQ47_{ literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/depot_display.nbt b/src/main/resources/data/create/structures/gametest/items/depot_display.nbt new file mode 100644 index 0000000000000000000000000000000000000000..f266d3e7eb5fa6be6a29bdee7bb88c75a2cfe5dc GIT binary patch literal 1526 zcmYk5dpr{g6vt(Yx!r7QWmz?uydT9T$>#mIc~ugwJH)&rA#AgYP#U+El()H4UUv(T zOWu#nb8eE?NFFhd)E0UmyDFc1JD>CUem>`X&hK;1AHO4$1QPicLQcj%v{BQ&?YT?R zdRYOCjiMLJv1Bpox%|!HrN4^u9;*hPch+#9vJQWkL+l~e%}dFyvXfzOjR0MN_~l8i zFh);&Q^NM(g*U`I0fR^br(%e5h(|P!!>iX>_Ewk&1c-E|@US8=?_Z*W{Kq{3Wb6Rd zmMA%M5zvx+TX1$<$IVvfaEIrm1M03jp5f7)MJXEum?3~>HZcScti$xwBLti_P)(!& zzmmmnBWP>T%??7pceiSjAE%UJ+x_v|s?#?nwzXSRFxhP_k{K+p|H2Xw)&E{muaVrM*4q@$s@qrfHzFo)w5l3oUd9%UkvYv6?U z&~xH=gKX=N5&)mxlTlx|EH%!H&Vc_Mqo19Rzh@(?J6hrzNt&)rt7;H_%BpJE(2Us} zV}CjF5SxC#kgR{@337*D-A&{}!kAc2%G%?>%KrI0`k z4oolid(wib{W}xH%?p-qiB_lbg~6zeUGk!?ZYYZB*NkPGVlLv*7~cuM{%Rs9HUY!` zq>g}tjreDPV6*RtzeP2<`qn3#=9Uxt1csX+D-1xdjUP&VbfQo3qiuJ1_}epfyA7*1 zL^notilqN^7Ett4W&xiqamSZEGbQw~S|)ai0uQC3Q13!ITBl2wQ1VXaA%0OHA(Tg7 zvl^Y&lo@T0aJx$iSe1)uj$%E4&@z-P0g*n;ZhQY?=gW@g_Eq}gixVLxivA#*EVlL) z6cB7!FJb0eBSmP8Yxl2_n$|#qo2O-oSRjoyA%J4_W7{qGKoDJ|8FrW`3IzMT*44Wi zVcYFDHkwmPkx8#u(5Ho=`WLP&NRRk*I>}rTx~A?Y^NvUzBwKqXc%OPP>%f;VxaymB z+DZ1xNM8zhD$Z- zLIqxj@i#Tnl3HCy}do#u{@Ex`y4Pxi!%(Mv7SUg+e)wQ@MlthYrdUq-> zfAl! zEj!`>`eG;DQM}peVlOdMW(!5qVu0NlwMtjFA75^>XrasN5*5pAF*BLeNuxaW27bu1 zrAP9Qo^%LqIxRccYkxr1to!^v`W7?`ZQi%jztHq$ChH;nB z@FN+BD)SP{?!3U(!Qmx_pD!|paH8=f@Yt|dCT>=x)K(=1l!(Z`f{5$Y literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/stockpile_switch.nbt b/src/main/resources/data/create/structures/gametest/items/stockpile_switch.nbt new file mode 100644 index 0000000000000000000000000000000000000000..65d268da8af1359dae76671dc6e51a73e606f4f3 GIT binary patch literal 504 zcmVK*7rrnLqO_D5*{jsG%P~HCp0XA)oZ3$EP}-&SUiHoBUmDWB_dcN zf(8BiztZp#4U5q52@M-$6(G!-a!Bt9>-~Ubz|{uc)yiP$WJNdS4n2*yz3xhkXr{X2 z6I~TB`>r&hW02n3Cqr!C+S^lWQn^r`-J550gqz^VI(JmO#OM@`$TGA)-fBVas ub*{`tm6B`-_~(;p(stTo`y(+9i?_IwB!8mw${K*hANU6j@^JTK2LJ$9i}8y9 literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/items/storages.nbt b/src/main/resources/data/create/structures/gametest/items/storages.nbt new file mode 100644 index 0000000000000000000000000000000000000000..f42e7a870fa3acc0859ac3992c23e34cd912d8cf GIT binary patch literal 1789 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 F0{{zrfiwUB literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/misc/shearing.nbt b/src/main/resources/data/create/structures/gametest/misc/shearing.nbt new file mode 100644 index 0000000000000000000000000000000000000000..2656d5a5bb6af8c5bde319507d74cb6bdad0e2f4 GIT binary patch literal 1078 zcmV-61j+j!iwFP!00000|HYWUZzDw%fZxu{I<|91!W{*oKmpMp0lFFq5+_zjM2=Vi zgZLqtu|2j|+1=Tj9iMffxq^;@KY;>@tDpc0DA1jtLxPqHiH3#(@gE#-c0EowyyKCO z4oj=`c)xk`y|=T{J~sgx!1Cx!PyjGTXwMC(i&RHC5_uEHK@(`&*G&j_6_3&;)Dw|N zg;x!~aWGYS_tqOxB67`>3@2dVW=m@o^{2WFL2AHuc`kOY0hB=Fx*SHMNT_m&8q`{e zoThsF#&=Ku`q9sCQ)nD#LUA3*)Bx+iy4}Mzer2~`e&?yj&vt(N_Rfdje4T85Q3v)K zPXt^!;ptE&TY1K3=~iE+(;V!zCzB`@1I0)B#j!|*iUu!?WE{&`Pw{jtVD7j5Q}*d^ zxQ3m!_3vqkyeSeaPcP4e7(xKeeICdA@vSHwV>uf8QVqngg)xmbTsll|PGg+P`?0_h zZ?^imRGCSuOc;u)Khlv(^LS6ncqnHkV`MLx$n6Nrnhr$C)eh4m6fgq@q5qOaR{{o!DBsX71ap$ zWGs~_+L0J(BP@mi!I+T>o(rIUoW7#4D8m4^;EB}5-7oUk{p0uHeB+o|hgu}%#xg%` zwiNEi2U2G?b$c{`c4S`I-n(|Yu-kd-UU}}m4|d<0P>b-aEHvB4YTdsdz~w!jcA~*) zH#?G2V;*a-PXsrWBv3aGLU}VVP`w|^!6`0ipDt1q0MF==%{_KlS*7j2%CjAt;uiA@ ziC4=RHqhcjA;hhr#eBvxCh%a02SYs==3oL3XUn*pE#q>wjLX?FE@$H5Y#EocWn9jd zaXDMY<-E8b9*oP`GA?J!xSTEHa<+TkZ8sfRQ5aHby4%)^;^I5Q7t=HbjLoYyiQ3$2BDHLcr5 z>4|~DUPNI3z_EYnVVfc1-hk((DYDGv^EQJ=3YyUD;48aOrq4u1@LU7aYAWimKEq%t zmg6zLT8ASZ=lElo%c-7NBuuemnk+7|8MdGE(PG7`=POEn+8dePXZgA|jQ_&((SKam wBj3gF|6TW=g)ZhllsZ4WbzOz_SeL?jn`{22X|v6L7VDqD-^u(jmt+wD09Gj#`2YX_ literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/processing/brass_mixing.nbt b/src/main/resources/data/create/structures/gametest/processing/brass_mixing.nbt new file mode 100644 index 0000000000000000000000000000000000000000..a10e5e46876093a671575928b528a5390ebc32d5 GIT binary patch literal 2154 zcma)+e>fA`AIG;At1H~Pm15ETQhHo8Z73?#(~2mRX`z-e8>5i&d*t!0?CVD~W~(OT zrthL{EI;Q**N}y<`8izL_RPrdRc7^_?yY<8f8X=R>zwC&&htL!bI$vGj7S>*U)z@% znkeiYXIpEjt|yiGkiZ=pUD6n$jqE+u!4!DJMsPq zr~Sle0d96E;faQCFd_&6GtMRw32cpEG_+QD`CXh%|7e(C~ny9)@nJV8}|uXB(rRZ`m_!zXCTbm?Xw?5^ z_J;11iskN=FJ<+7obW+Cc;?*8%Q|t})9=1Ot8+pXKrPO%S(Vh_;fH$!slq#1pTHPi z;^GHd{}{13|DY$C5%NPviof|~Rt(|eAZ4bQ+-FWV?C@=Ioi>d^K48tw$$sxYZsU7p zJztr_m6fk3yH=DxsZ@D18jUCeZqiAM^lQ2=5IfqIze9;uuFcl6gi&v*<1eN!J64>B zklAMBPz-T6n2%5X zZGS^eW}dBq@@0EK6E#n1&DqE?e;;PsG+;nQkEXamm5f1_G{R|WAbBiQxS>Y>{>LTTWcS_xZ}!8>t<9bs4Z#uq16OY6k7hEcbwcF+C&{*vF6}^ zyjYU_xpPW|4T$A(j8#bps;PGb9RImq_OD=;fyY~e3w^hQCmK|uH*&gRtcUVS$Y>); ze|SNH#rTYxg4jJ4QpzD4_BlmFk)zV=pusKSc3~m%X+IO>cMpMyUz|`PW`Jl%_9!JkD_3I5N za3Zq@?K+S4sP6F;RS5lI;`NdenDzcoNPO%Iq(<=kTmj&GmKS*XtvBi+L>dtf zw~*GeHAZtQ!J!RZ+5X(kgZFo=`ovg9K6B<)g)Ok7bI<=8kx1e?iq9Rd=p7l_`a?~X zK-|7q{5tzs|CUt~I=P%lT9TcS-X!wGsnIp3Ta8nAoa-QJxY@~0u-B*64s;XZT|Gi<#;Pj=eyIUEabn1HAQh<1>r~Hst|g> zB2x05^f-!}en0y*N&R{|6F}taV2YpJE~){H3QAcbV-1Gita zptjijHYpcW-=eJ*8SY5I0P*lFbS1@do_1tI<_u)YQtoi3RhwUk{JbZ$ukCvFRuuJJ z5qtUx!*!TL&sXqq6@K!D2CE_BQ62)fvulOaYiCcBL@XWaSDKx6(!@z?zdT;vCdx^vjG(2q(kezL-UUh^7WUX433u(-t1E685r_jec8YG)KZ+) zVwPB4v;u%NLMwpZpaYNq(BJSQS|=`lHg}RB1;s6l3Y|!qBCy4VmmyqTZGG?9$ox!@ z#5nzz`fA_K|MMs|(38C;c`of(pQ$2B>h1P?-(3rg>>9%-q{+kA!zV+PS=tT%eO=0+ zIym=Hb4|e)78$~J_k!(&JubHioiAkc1q=pA#Zi`BVq{U_iE&fsOLA;8 z-m~=6L9@zW_Rz5T^0fzM3F8&$~X)&&Jx0skvT(H->h!l%u_+RN!XXQ46C-0H)ru+`>HUd+H&~u&DFW?Sa u%OV8YEvI5)t?q4qHDnyJxu>RX#mu8U5+y*Ppd6)@Qa6RR@m$PN0N{TlEk(xw literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/processing/brass_mixing_2.nbt b/src/main/resources/data/create/structures/gametest/processing/brass_mixing_2.nbt new file mode 100644 index 0000000000000000000000000000000000000000..44de42dfea2bf58181979644850faef5d3bc52fc GIT binary patch literal 2846 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 GIr1;~(w`3i literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/processing/crushing_wheel_crafting.nbt b/src/main/resources/data/create/structures/gametest/processing/crushing_wheel_crafting.nbt new file mode 100644 index 0000000000000000000000000000000000000000..099e093a93f170665dd3b83372af89ffbaad555c GIT binary patch literal 2715 zcmY*ac|6ox8@DywEJazuaP3TEU$Yb!x2On3lWpRf#+qvxy~aMF49zRsFo+UaVwe}% zjb)I*B*`?QY+ZYeeSd#+@9o~-AJ6Z6p6_#>^Zh>OIp;`Xxmb?AgT?Ie05JPyY1kbKEVL`!A={ zArh?j*q0u7{hF?%<^ zWlvlFw-PtO-k8d7v7c@{4#r`H+^r&$>e|bqg!`JEW`rTO0ow`kNv1Ua7>XRy5KEC# z!%!$ZqGFmzA8KBudLY}MgYVuIpYvRQV}NUcA8+FB4oXToqosqOjo`!o9Uf>5|A7I4 zd_NuL{INhx>yMQHuOXsX-2n7&GKh$5N9t8qr6*fErb=jBi}Ha&n94hgbjh773uf&v z#7f_;*Lui|HIEV3uwyIq8B~P=+JCDD20MGNp(uWHVnTU`c8A>j+QVjHFCuJbZO<=P zu1DBL10uHh5^lIundGOU-Tlm@uxd2Q5qv(#}xT=!2`~AGYRpo;_JWHK2M`7 zF3)KutUMpyzjUx$y}y;ezeT`ev60%o&(~&octjaNOv-HbYIwv{XaK%gh;dKdwmmu2 zP~R|h%cHAPbcJEbmr$IPwQQ?xhNSspJ)0Xo!ZvG*U29-0Nxnje_-Ao2r24naE1}b$ z^r_=LzZM6`=ZuIW7yKl^B^Pb7y?gz_bDPrH!wVLt=r;68>wZfGYl`2+19Z-os+DbK zhTcJVdgI1d0&ah^Pa!gNJAS8S2MdoVk`#RGyR__k5b%YBSzqa|a9L{bnfFMQw0PGu zalQI&?ye=S!+a9DyIZEuojWkxbvZ<1`$-kO&3R|Ob1PD!Z^mPz%=7b{RQ?A(p5*16HlqC z4E(*|(Kt3EhOyi!H1-230X|gRjKoIBm*#MNn0z zGJ7RTE7IbttC<6Zrk+h8E=-(mIRZr{HefMeRvA}3& zda5zT=y==2d8AJhpBVaM8Cl}kZJgpSY=M{HLL7)Utv-Vz_+!zqllWfMM`{=l`g8|B zf(FOM=(R0qX;|BH;KQ6o#eMf>?FdA>(3CaiUT=;D_R)zri&P2Wwp&3g^^oTB%}gBB6tPp6pG7%7@3nmB*V zwkNbFkJ$;ZTL*{f@MO(x`p>y&&(4q9H-0E3HqCXVez6EP7~X);-~%Z{FAcPgIn7BI z=h`bBqA|KVl-{L|jRN&f7A909C29?y72Q7`|9RjK*4nw@s~Ch*t^ILPZ&WD>g1m|F zN}RwunqbU-FUyOj*wc&yKZeynkk}bbcN2^fnRy10+-ghno8$r+-Y^)`M3$g}go%@c zcl-;5lESU2BMV%jP(4+_N7-jtUtEJhJnOiYyn4;^$WQgsvA?t_KA_kjhv7Ej?m#_F z;E1m&0P+e8)Dk>JJ-O{Q*{3edHKg+s*n0wz$tN z@8Vt;t5kez3XB0=Zp51-(q)kLXC@9j_%AhHAj!ETsf3FFYJ^-4ClVLsRL z;%;Il-rN||c?AH-ZZj_(r>t%yZ&X6q?A%CPNFx3r5UhiZLeLfX@7mujPt926LHS3 z263g4HP!lwG~0@AnYv~7=U$I$Ac;fRmse=;;*iWV*nv?6S-Q0S!5it}AuPcA=3FO~ zO%%GO;>)k7S_-K$o71-E#|sbuz0VH|LAG5EF6rJXNq}aCUa0!hrFtl-ctc<4KY^!& z>g;Yzv6m$PJ9w1H4bYt)TKU^49W}yX_J1g*2lcoWzrTn#0a8oe1_5E}z#%9Wc1Lkh z`JyvV;m`eToY_d1;V7|8VJdqdEZ|0=XS~s*6`x(qG%HnFf(+1Nwgy9)>+;ZmB0ltq z%5JXj(D}chfaVfuU1xK+CDAYnCj0YEK&V8kPFG$uy@1U3LIgOLzzZi8eNI-5n~n7I zUq+MA&xtbTJqfVl9AW_&qKrEMw%}{(i1=2Z$A0iT7fqK_Yv4d+v@YnVp@BfRHoOrV z>3ug3Bi~_9krlD2$XcOk`B)%!Gh_Zd`m3HDM9imaD@E3Tp0t+qwmf^4^3`E+xh?(< z&r>IG(2k5;SBT2?bIKhtIZuVN6HIoN^AYPCks{kL@Wu|1o`*~UYmKOLtR##BcL{t) znj(G@&&~!s+k9N#b;NVb{I^wH;2-5a7M*!@CvFid)y5<0?$S<#%Y7_J~WYIw!|WRO{cw{w(kjF(?-`ruDnwp?+4gEU>L|@?JhZV}t`e z4!>Lf%4OQdMm*@5v=vUosVqmwvFu$BDWBSV;`;ln_DfH+_S$881M(f8L@YfnVkV!4 z(j0ng49^I94ZC^N$ybFzNKOO=CWWzz^(ok%`juA|t+s>jrj*-U-zL+_b*ngYeS5_#wy@b`ypqch+c+9V4$euDv-h}66VZi} z>zN6Q#*}NWF_)ALYh4Vzxl{4d>GN^U^T+r3T|UqEd7kh0^E|rga#G*M)?A*D^!i^1 zI!0IK#aG`D4`PZK!JDa`M#Zl3X_(BkpZCSw$Y1pBD-&7Ia-p_8P5Fg70GaO_0W zfQu*$tEmwQgdz$hsl9DG!HIFn--6w0oBVG3dsQB=+y2g=Kno-Irnf_g@yP~y zL<@U}7MT7gJ1hSBck*2HB%n7`YsKroI>eUNdCc?oo2A1QB(WxJnCYy{WL6iXnp^V^ zAsq`V!_QgcULI;`(40bOwQU4Q_*Fcrt4iIK$hRbio0SvRw3di{BQJ-UJ?Y@f41qIb z{r<`O-Cr#HQ``(PjOsxF_Zll|4!)(tb*`=St*9l8*q(;?3F?FR(Tke}vCV;kW?LkZ z79sURV<;mdpp@eVi(sTR=Pi&YsP^gYV&s6IrS75+c2O>`ew-TJKiNbRV8UjaL~AxN zTZ1;NbFWebo^h8OusH=wJxdpK#DO-NHtvrepL_Z(7kVozjS z{v+F7o;zzIbX39%Ri zxi*AASm|)&*rhC=uz3muR|J1LXguI&te$fcidkW_Nz|-f=mcDzrQP_3< z>5%?N_5IGYjmzf`kN=X=hqfox_T}LP&hlkJX$>Sb>dp4fa;0f2E2n@*NUQ?n`I#$w z*f`^6wUV}p2bP`FcdZ!m`Cs}`;lSD1Uzo1sQ=UxxBWUqOX(V6AF>267IYujpLiDHK zpqP7Sn8qT8p(W=Y4xXWaNoWg6zPAi-Ywz*6$!FA8Lji4}v{*m*k95V;bJ@rab4_Td zZ^R|4c$MMtDBp0@8!@IPRe{^1xB`@tVC_UR*cfTtZCMG^%-DWXS&|m!-DO$%&Be53G=?d=R*T&hrN$@VZF_#bq4^MAk>F`rmY?{9X4Os#Uci zx11`AxwOZFf$>PI%vos;rSqwkP*z@MwQQE;6mW#&)q;Y5D><3QdQuByB13RLl#U&vcjFhw=PWI m4gX(RSNQNyowm|HwQU$)I_3OFfM#~0RLV6gFIq=zyChZ_xJsNf6q@HD=zfk*_tCVLO9lPDK-Zy zt5jb!K(55NM-OQM(}gT#p25cUM+uvDKYe@#>q8KS@0>8rq;zT2jYRj+PAbHu(43u$ zbgms<>|MGIRq4`jN>M%O7_>>m^SaSY+$)$lrY=p59a?EEF5$`hPU0b|;BEtcV9J$~ zZ6|_R$cRQkRnbc{zY1QLsL*1ysGgy?&17Fj^()qZCMZfGL#w#&5GVyxexUfu!GePA z>b+h!P9`mGlcMhcDgJ;8{nnrO2c*Sm6}R#e#JD0#IO)rV$BX`ftY2D;H2-b?Z?lxd z5C2bL4lXx;;vdkT{qg^s|0mWR`c;kUFKZCLsxbll`vY9+wkqY9-rfRPML6krAyW~S zE{v%v{iQ>J=69@56ix5${@q8+==_dcH+1uFXh^+^E=r$wtg|@&vGraA-=@{^>qyHu z;@cQl&GA}NaLQb?ZA3CzwFm8YdobI~a0AR~+S32x>iKjuWwWs&XPs>IN>sq$K%`hm zzvEKEHEijJuNV&YoT!Dlxw?26?E~Kf1lCG|ecbJWjw<+&56F%05L}m#g{m8V_&I?3)e{54xKY#M0GlL#s=m<-T2#`zCf|)2rVj!0JF*xq_vw zKTN}9`*QzA;`=4)WciS;yTxfRg2&c;JW9-7R+wN9RQPV@hK{ptd-Xd9Y`P>5p2({a z6s(pnO;`%Sxb+pj-%$;(gW<3E2EN0Z8Kd~@MF&Q0-@}J%&m+4LJ^uEY@CZv9>cWJw zSI!dr+8LUeMyGY*?a+4OnKdyQ$#slStwNw;8z`DC3lai#IaqF}aV z>@DS4byWf0+57jT-PwK?H_AcG90Z>HHH`&$BI9TA?X?c<7)tL^b%N0a3w!y1v}_X@ zb?uJBcMkcSXxUqFIL|Tck<}?f`x#t&r>q`08Jqh`E3dLe3t!o9uCX|MS`QpwUaqG_ zy^l4*SB6;&ug~BHkH)=SWXB@|ir6ukRwEuYFd#QW7sUyA;D+=4&7FF7gVw+dS%O?? zF`h3RN){-T2#%2XY{-b${q?hI3mu&B*EP>T^TWGJ1rL(eHh0+(G!ph)_6^Z|L6MgN zD)rp}eO(S7BH1$~Y9_Al)lrcqg3r!FKFEFo)C%wIo%gS!?r#WQkl~JHD(mk!y%i{E z_7uFWKE~&MHb8IiD4q-Tw*-#^oJ!*AV;~yLMnGOY==$lNP9FP1iQvPB4=03slEocH zIqWgDh=i$NHFB-FWXakR^BZ?EFVuI%QEYlwC@#x+W#t8*%3tH0j*Zl@{}h`P_n=Q) z*F3Co#IU;{t5J2v1YgvSAa?pd6*53I^=@<_Y`W5o4Pc$R(p#btuHj8E;Jmw7VDElF7-8m-n>Y;;)@p-0i8^@>Ah9+rdw~{?&I3=j6F(b0WA> zCw4pR4K(S9NHSan;Kt7Es8`C*AJ+Gu76k%u;pxLmZMGZ(?jT)qU_!lXV8Z8)R(GjW zYDXFa+6WSfLaG30tBTbnB>ccrq{(@t#^VS6aJ%D<|JA zZhvMvLOq-ah;{tyDvxkh9u$C^NRRNQZ$<@Shg;<<-~}T6#kjtjR4kF7-eAQwak)y{ zx4lU)g+ru9s;zxUSRX@AzsZ~RFO=~aS%fm{%x+mfHbE1pwn=Dns3KMN&-uh?+0J;C z^#TW6ufN7j7ZP$mp}s`gu28CTmU5afAj!|N{`ge~7SPX|tN)W>2bc$-a^cm|8P5mf zrBi0tf?UECE-A`Rm(}{Y-#z8pDpTPK8D(#)Y)Uh*SM^idvD&No&_a@`nmYebc#kMe z8Jmn|8_gGK?Ll=3r_OHwqI8`TWJ24%qV*E8abzxonSnFekhT4M?zO4h&G}th?bo0l zUXPz?7-d9J8H5l_QuyWb9m=Yay0(T%2Ca>FsslcBWuLrRhm>a~{p$0*QbE?SV=b|L z!*3exy}lp~cI=GCdyMaG6RFT6EBf2@L_)8X)`x5~_BkzVT*i7D*SsBqa17Pb0ax literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/processing/sand_washing.nbt b/src/main/resources/data/create/structures/gametest/processing/sand_washing.nbt new file mode 100644 index 0000000000000000000000000000000000000000..75ade7053ccdf27359f701f6bc19068a02178478 GIT binary patch literal 1370 zcmY+>dpOez9LMo4L$a1qC!VH~Yns_w#_Acxd0kFNXFFMRzgY?xkPMdi*qoM z4$Z>R#HR4H_@SLl?qOz3x#XB+PS1IsQ%~RL_2>Ja&-2}zwrSmex7NZK4DUzpNG$hv ziM}6%SCen4edD|9BBwbl1#IWN&yF)=M1&b_dz`9jZ;Y>+-@zNKkawT(K2j@BO))-R ztzrTa@19#I&y_F;G4q=Eb3vy?O)2>fVU!Nz}hlTaWJ^s2aUM6 zsKqJi_DKtWrKzP!&*I}iMknZrBVh2vchK#u8-gFsEbc?lQU9a5MyRS%zawk{_{1L$ z2z0dDzoX%PYJs0y%+IZ?S^~AAC-QHBjP@gt%^*-PF|Jb(7QAch8srPhE{Wu_hEo^92j_#48o zJ1-nvYqnVLT2L<*VJ*1>b#DaA1XXunV#Ofi^#l~kEP zpFT)k75Ow-YB**}Y&&oc&;dOtZBiU4|F-6;zpuNkZ{qs~OC=>ry`T&pqwcWhOBBOO zTdv#+KApeq4>*5-3m0g;OU8Qp&cFO3Y>+rd7WT76P zwd``lrBk$g(^H+X`ge0sew1OWrRTe)pBxN=@VzGER)c)|;~{l#Ok#Af=yJ zR`gUvW|i?0rfnloep7Zd6Y4sQp&}X!2Ba*om2|M@UayjJSKPrk>2aXK)=wOb=GG16 zKS1A8bt%1aYPyot{{j|@^!V!9G|rxZ#CXd)*vaku)r{%d>GwsI_L5ndG`MNuvdYjo zweVP9FzzEnSm!$~X^GS^4$8WNAa`{tEg`L9+DdgHMiAy4BOHbduW#`C%1oqS~x?QLKp7-dDF>aV4~vv6P$X3?x@41fkMLj6QKr zYh-g?*D&n8=D+&vfMLeG0+gtb@#Y3Xl%u;#ptT@>uEy-#O32PRqAtg?+8QHyOp6$J z*M^R;9JR^h)sILN*IMwVmjg2>vtyS$DGTNnxAA%(?Odn{qLkL_EaAz~^XEp_Ph-bW zq=_dbo(zotytj!KmuX=!+$Z`wd5=kfnf&1>dr;43X8`aZD7!3eG1rB}D-)&%jA@h$ ztEzh%yzOOc&u{#q_X3tywB2p@tD&si_-EQ#A8LO?j1!vPHi9v#bxbL;71D5$ymeqm z--#;dXm(hzr;>~!;WFO6{%0L6PD`FK3^V2?>Ek{KU|45;*oEgB*B!KSXJ$)m0#8s} vUw;Ahs1bSGgLlmo8A(>1Xkrl1z literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/processing/stone_cobble_sand_crushing.nbt b/src/main/resources/data/create/structures/gametest/processing/stone_cobble_sand_crushing.nbt new file mode 100644 index 0000000000000000000000000000000000000000..d56e9423d7fb0a826f2d386fb36c16d6f4519f4a GIT binary patch literal 2508 zcmY*adpy(o8$Y(4;mi~#IxV+jmGg6FGR!4uq+U{vxs_w6xr|ss8*`mHCHy3e5uH$M zxviX`VQF(>A#z#Bahp03ne9ZzZ>rOI{l0&^U+>rRd7jVfd3~Pe{r+laDtz$-x_xZy`W;u>Cl=w!J!@yfnzf8T6~TB^|z$NpL8@;Dbi-CfQ5oBdG8_x@$& zNOtw0-s`=)UdOI0xxLc)8+~6no*36WUS#c}z1ILh$#}S>xhYKUjaHsN`p&G0vthpG ztjP0`vTwJ;rAA1fibnlvRgAeM8E)k&+8jBTV;05YJo(9F%1LCxIqS>K54R5-xCDag zg@PPsP!?LLdn}A`{Vb~EOb|FLv*`OT|-rE(+0e{PnW3AIbC z?Cm+wJ9dRwjW2_U89%(f8X6XTGbgjHQAu(q48L&sv2MOMSZ1ZIG7KcCAoy8;sa+M%IB zg#(#xGeOx3eDQ7!y^&-bmWHU+UJ;2=tEett`R#%RT!pDLyIB19Dm)x&S zn0KvOM<@D`NBi7QcwoGURmEwm_lIdt((JjHktT;T!Suh(OsqJN^UG<-Ulf`?5>-Ox zs`VuzTg}-#hL+pp-dp>^Fy2oPr;De<63j$a)l1Q*5rS7lqadYYl0~8LqD`-PzTc&n zn@7~MdbCe0yX@Rh0VhYmyptdRrjF@HXW^Vw_}qYTR9h3e;4EAhNO#EQSpM6#6bj&%b!;hS@{wepIHSxfOF`c4hs}qCL z!dU)0yKcI^!{qU6dSUj&lGiHCHa{O=h^BOk}(lM7u{eD&8tE3ij3}geo4A>sp|9Qtbdt7pxG3JMk49vFae) z7m#G}M{Mrphn7AV953kgJX12;7fD+td#AoQ7&Z3WRJNjB%L>Ji%T?1m%g}E*^}tPm zu3ygwLcK89B0VVIa+~nwQmu7NJdyV^Ma(y`lA`TA8s& zu(Ca5_$G{=Sc3D*IdLRyS*uNh!P|V@m{|?XG)wr@rn7K}wthbjyHr;VOb9sB4D4Yn z9(+3tC}_5+e?s25*imaW^sXbEmE3PrKM`Rbi*1NV)BK*!sm*nZa1&f)Dld@n^Ff%v z_i}GLg6J9+KBdjD!h=Ia?coehUkBr%KUo@ov4^}$$O|==tznHK;lL~o8kkVLT5lnz zT`+joO-=mpa0r9m>f0Lp92@OTEf2QqHw$I2|m=? zo}k~3(-4(ZYh6?30lj)ZlS48$86wF&R)R5xJ7v5yBbcw1`q}CAw(Wi!WLo|t=zmoG zw$!;rxeNMmFm}^cF?vkGj(k4uJUM1pnSW!(W?q_Npz!l!eTd=53XVMuOgF4w$osTY zJE=fG%pt6@0{_QUYYTIeyI6K!K(p3nXHOhyWsdYAKH^r%bXj4Ypc8#z_z}}H@oo$w z5f(BLbm{JYE^EJ39>9_!TPGVr>viRrDBV#gjB&KXW1p_63kWyNhZ?9JrtGos$=#_d zTf}Ri>)SkKdlPdy_=^0JuaMSZsKEaM3*S@80NEc@qR6*T^;M}^ild9=Ff0z^@Q27T1ML&iay*n#}q3~LQ;b&Wn|%Wb?> zMO4O{zs80bJ<>Jqnb~Bd%SXlanvfXrKC^Jli>=(7!zDa2cQ&ke9$n$mr&n_lDD>v~ zpbh(%hJ&A)YkPOD{rA4IQ;qS9?sCU;9ru|BFFHTmVcn||{Zzv(Z@YF}>h4>$p2tA) zGiPbG^y!O9rE&NRbFh?xIW#1az`qx80}^X{+)x!8eM<>k-E#2o44Tpn{yjG1+0~@G zM@3A8ra6n>Xhx#`m7!&G@07>6@1_{8FZQ(16dN^oBx=@S40^oIGhSJgI*GqD6H(q> z;n8*Q10lw8)UE9U(ZhTx<44k>)AYNpS#-$(1M8OSskgdM>nYi{;A~Hgln@Z1rml^S z_F-98cGojh3bUa`Rd!``RQpO+@dnL!X&|a;{EtF>NZS62fND dUWrxhw29}b6FC=!l@Q)KH!Ye?X9@SWH00_ ziey^4U4FJXCqDEZtNH}V=4DJ9JL3x$(6^v)xf;7Hd;CnAO(`>&dCDOA?u&a0eJLa4^UiXEbcyLCQzP_XW1b3Or}#8$ zDf^`?%lPLY$^Omg(aTD5rjSQpL0n|QgHm;Yzm_W*u6ho`xp%$@Rfl zrdzHDxZP-)-%Zd{mNMj~Ks?T5m$y$#KJ#cm;^in%bfi+ka3 z0>Ko2(^xYg_*(-(HhtEAQy8`>EZW-W<#0F&*MaUkJ{-j8QG8vA;6A2hoQMqJLo|+s ziRE!d*ykH>23adVO}V+E(KZ1g(>K5aR5>VWPf~v9kK$#+kSK=*5j2W9sV5ZEEU+jc*;HC_jrGrCFjd zzfkslZB&YDYm})zVl-FQ85(z?aCUbK`5`fGh2j?_QXJXR;qWk9O-bL+ShYo`EFBC` z=&r>pWJ8Ghw@a_4z-1lJKv5|vJ3+NefhGM#7|j96y9+UA|i>Cz`LwV ztQINRvLF%@$GI;3og?AWo29wrgYp^LWG_zqu9yA$oezio5I;trd`7-ERL&}@acyqZ z!PE3E9pSJm8Wx+V*#7?N#qL$uqlYZl)}{^c~GcOHdd&=rgBe zP1A{=xmxJeSNU{L&N1u{?xf+>)s;s_d~M6(nQ_P=e1Bg1(_4v}qiyYJ2TCeqTMLf4 zp}Y?FLW=12K@QwyJ(-O=z>kO0?VX@6byOj&y$qN%%lI>3fgm7>t|fy70c8SRpR%eK zN6#8;WyqP*LtoFhDGIW!Hk#buIv~QXXiO}yNKz%p z;>|yPKMxH!sf^2$mL#9fwa~@_aCrc$08jml(*QOkl-^V=s@NL8%}-U&8BMJbOg_wM z6-=AAZi>y<>7sWr_QKhQo1LwwrjUUdy>&zENZOs$nOZwTPN$Xazt@VjSL2=EdU}Is z@*@qZ^+j5ut*>ewxt#N1?tDF(keQzH7&*{=k=I7)D%j$`;qeFfdc%EFi^FR#KsXpx zYX^H3rD)&$N^AGR?EE2dAkDwIeAwROdE6e;d=ls?$j%HEEJ_{>wb?#byU|3#aov&b=?Xg2UT}Q=)XV(jMzqoZ(if->~dV zesGA`vNraz?&Vwrwo&V1w11`3TX}Zk{HkM%6ih!0Lc8VASszF zQ~DhUHfae%>|61Ti8R`biBxEanS4!Pq5{NoNQn3h*ZS0om&Q@X11XkN;C_G#d`dO* z`SBP48o+@iN;*wde()ZNUD-^OnONeVC6MPtu$1`>sXQJ16||xzwK3q*zruERd2fV! z<(6Bs7x1NH7Y&u}ijsc~w=;_C<*-cqqS+o)AvtH(xcd^zxBXUrfK7k^+D6}CYgc$U=|Z4BV=(2xKjSXe4*9>B{-H~36V6=zu`%ce8nAj z1OMED^&GZr`0SM=cax62wyaXV;WIn*pkTkx|BGIEN;_Rg+eQa!;opkXza>1vp1v?y zWnFt~m52*=;QF4t!R#Oy^Vi`_dI_J?Wr!vI36;jI1yX97|d-Vr_YeDP-DlD+g0uj*T1eg$FZ&P^<;w{0Q?8%TOS7i literal 0 HcmV?d00001 diff --git a/src/main/resources/data/create/structures/gametest/processing/water_filling_bottle.nbt b/src/main/resources/data/create/structures/gametest/processing/water_filling_bottle.nbt new file mode 100644 index 0000000000000000000000000000000000000000..d2b527bdf19541a5142d5ef1c134ce64a2ed3408 GIT binary patch literal 1797 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 IhYS(`04c)v00000 literal 0 HcmV?d00001 From db19a394f5fac6a9ac2ad23aa367ea94a72c64cf Mon Sep 17 00:00:00 2001 From: NerdsOfAFeather Date: Thu, 11 May 2023 20:34:48 -0400 Subject: [PATCH 17/22] Add armor tags for Create armors --- src/generated/resources/.cache/cache | 3 +++ .../resources/data/forge/tags/items/armors/boots.json | 6 ++++++ .../resources/data/forge/tags/items/armors/chestplates.json | 6 ++++++ .../resources/data/forge/tags/items/armors/helmets.json | 6 ++++++ src/main/java/com/simibubi/create/AllItems.java | 4 ++++ 5 files changed, 25 insertions(+) create mode 100644 src/generated/resources/data/forge/tags/items/armors/boots.json create mode 100644 src/generated/resources/data/forge/tags/items/armors/chestplates.json create mode 100644 src/generated/resources/data/forge/tags/items/armors/helmets.json diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index e7c958a52..21c361d6d 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -5669,6 +5669,9 @@ ff1900963bc4cd8ceffa78d58ef1952ceacb2fb7 data/forge/tags/blocks/storage_blocks/b 6b73c57912934d09233ad2966110968a6109f2c9 data/forge/tags/fluids/chocolate.json 391c9b2be5740aea943a8a5fe27eb327e2d973b0 data/forge/tags/fluids/honey.json d6a4e4fe1204b718010543a28a9b9ec4e0977bd7 data/forge/tags/fluids/tea.json +58a0fbab3425558d993559e10fe14a1797b05eab data/forge/tags/items/armors/boots.json +7973972edb524683ef365bc103fcfcde0858a854 data/forge/tags/items/armors/chestplates.json +615e86e25fc29ead90e0901cdaee9d0ed9b3e4b3 data/forge/tags/items/armors/helmets.json 5af3164b14c92d2d6e235b5d4eebd93cbee37c0a data/forge/tags/items/buckets/honey.json 2f7cf5a2d485f25d451da9771ed466591cfa5204 data/forge/tags/items/dough.json 2f7cf5a2d485f25d451da9771ed466591cfa5204 data/forge/tags/items/dough/wheat.json diff --git a/src/generated/resources/data/forge/tags/items/armors/boots.json b/src/generated/resources/data/forge/tags/items/armors/boots.json new file mode 100644 index 000000000..d97b2e831 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/armors/boots.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:diving_boots" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/armors/chestplates.json b/src/generated/resources/data/forge/tags/items/armors/chestplates.json new file mode 100644 index 000000000..9c5cb97a4 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/armors/chestplates.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:copper_backtank" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/armors/helmets.json b/src/generated/resources/data/forge/tags/items/armors/helmets.json new file mode 100644 index 000000000..d5208adbf --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/armors/helmets.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:diving_helmet" + ] +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index 63b6e3b3a..ce17aa4fb 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -69,6 +69,7 @@ import net.minecraft.world.food.FoodProperties; import net.minecraft.world.item.Item; import net.minecraft.world.item.Rarity; import net.minecraftforge.common.Tags; +import net.minecraftforge.common.data.ForgeItemTagsProvider; public class AllItems { @@ -251,12 +252,15 @@ public class AllItems { COPPER_BACKTANK = REGISTRATE.item("copper_backtank", p -> new CopperBacktankItem(p, COPPER_BACKTANK_PLACEABLE)) .model(AssetLookup.customGenericItemModel("_", "item")) .tag(AllItemTags.PRESSURIZED_AIR_SOURCES.tag) + .tag(forgeItemTag("armors/chestplates")) .register(), DIVING_HELMET = REGISTRATE.item("diving_helmet", DivingHelmetItem::new) + .tag(forgeItemTag("armors/helmets")) .register(), DIVING_BOOTS = REGISTRATE.item("diving_boots", DivingBootsItem::new) + .tag(forgeItemTag("armors/boots")) .register(); public static final ItemEntry SAND_PAPER = REGISTRATE.item("sand_paper", SandPaperItem::new) From 3ad4195dd6865fb0994c37f9d95555aed35373e9 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri, 12 May 2023 13:41:28 +0200 Subject: [PATCH 18/22] Squashed commit of the following: commit a162e18c9c4d91c4020e86cf718d59d3a33b2817 Merge: 374848f97 beb61708a Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri May 12 13:40:58 2023 +0200 Merge branch 'mc1.18/dev' into mc1.18/computercraft commit 374848f978cf0cc1d91ff0b98a8bd506f1b81130 Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri May 12 13:22:29 2023 +0200 Compilation dependency toggle commit b2cd60b6195bcbdacaa47c8b8a05929cb160fe5b Merge: 8e1e4e8bd ee3a079ba Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed May 10 14:37:32 2023 +0200 Merge pull request #4650 from ChristianLW/mc1.18/computercraft Small tweaks to the wiki pages for ComputerCraft integration commit ee3a079bacbee6fccdf14a356846e12d67edece6 Author: Christian L.W Date: Thu Apr 13 00:55:20 2023 +0200 Small tweaks to the wiki pages commit 8e1e4e8bd3beb310e4e114e7d36134caf1c7eb79 Author: caelwarner Date: Mon Mar 13 18:31:56 2023 -0700 Added computer to display source ponder tag - Added advanced computer to display source ponder tag - Added missing lang entry for computer display source commit 952941e5fc86036bf2c3555ead662cdb9ea9a29d Author: caelwarner Date: Mon Mar 13 16:31:16 2023 -0700 Added documentation for train station peripherals and train schedules - Added in depth documentation for working with train stations and train schedules in Lua - Fixed small formatting issues in Lua-Rotation-Speed-Controller.md and Lua-Sequenced-Gearshift.md commit 7f3ca1cfa06b227211a41503c4ae31c3cf854ba5 Author: caelwarner Date: Mon Mar 13 16:29:05 2023 -0700 Added isTrainEnroute to station peripheral API - isTrainEnroute checks if a train is currently navigating to the station - Reworded null station exception to "station is not connected to a track" - Refactored StationPeripheral#inAssemblyMode to StationPeripheral#isInAssemblyMode - Added a check to StationPeripheral#disassemble to make sure the station isn't in assembly mode commit fac1ebcd3f1d1d570735fa6b2d57641b20c4ad8d Author: caelwarner Date: Sat Mar 11 16:12:58 2023 -0800 Added documentation for most peripherals - Lua documentation has been added for all peripherals except the train station (not looking forward to writing that one) - This documentation will be added to the GitHub wiki pages commit 3e21996984febc8b256ac8abbb11df9dbe150630 Author: caelwarner Date: Sat Mar 11 15:54:36 2023 -0800 Updated DisplayLinkPeripheral#write to move cursor to the end of the text - This change was made to be more inline with ComputerCraft's builtin display API commit 7141c10025c948ce5a78f1d484964f4324ffb463 Author: caelwarner Date: Sat Mar 11 11:45:43 2023 -0800 Added isTrainImminent and hasSchedule to train station API - Added isTrainImminent to check if a train is incoming to the station and hasSchedule to check if the currently present train has a schedule - Added StationPeripheral#getTrainOrThrow to consolidate repetitive null checks commit 909484ed5b80ac1c397e04a1ad41acab6cc8e13a Author: caelwarner Date: Sat Mar 11 11:15:58 2023 -0800 Added getSchedule to train station lua API - Added getSchedule which serializes the currently present train's schedule into a lua table - Refactored StationPeripheral#setSchedule to use a more generic method of serializing NBT tags to lua tables - Moved schedule entry special data from root tag to "Data" - Added StringHelper#camelCaseToSnakeCase - Added variety of put methods to CreateLuaTable commit 31ad3aa671339e7642f1c89118a218ff7c7eec15 Author: caelwarner Date: Wed Mar 8 18:22:23 2023 -0800 Extended train station peripheral API - Train station peripherals can now assemble and disassemble trains, check if the station is in assembly mode, set the assembly mode of the station, get and change the station name, check if a train is present at the station and get and change the currently present train name. - Refactored StationEditPacket. Moved most of the logic that was previously in StationEditPacket to StationTileEntity. This allows us to call this logic without having to send a packet. - Made Train#owner nullable. This is needed so that computers can assemble trains. All Train#owner is currently used for is to display the train status to the correct play. commit 574cd93a89d49d8ac50b865b9b7f83955fa16ffc Author: caelwarner Date: Wed Nov 30 00:37:47 2022 -0800 Serialize hasAttachedComputer in ComputerBehaviour - This eliminates some edge cases were peripherals don't realize they're being controlled by a computer on a world save and load commit 94e3ed44ad1deaa383c8da61928f67697dc13273 Author: caelwarner Date: Wed Oct 26 16:57:12 2022 -0700 Added ComputerScreen - ComputerScreen shows that tile entity currently has computers attached and therefore cannot be controlled manually commit 9afdcaded7006c1c2671cd3070185d500c3a3dca Author: caelwarner Date: Thu Oct 20 10:18:37 2022 -0700 Refactored PeripheralBase to SyncedPeripheral commit 7d47fdcd061ca8efaab5688ac2724fec3e0bf1b7 Author: caelwarner Date: Wed Oct 19 22:45:47 2022 -0700 Made LuaFunction's final commit 56a1210fff386fd538733a0a0998dd1bc0bd060f Author: caelwarner Date: Wed Oct 19 22:39:38 2022 -0700 Created ComputerBehaviour behaviour - ComputerBehaviour replaces ComputerControllable and SyncedComputerControllable commit 19d283b92376da793e7c88c443adbb3cd70b2c43 Author: caelwarner Date: Wed Oct 19 16:05:48 2022 -0700 Moved all peripheral classes to computercraft.peripherals package commit ab18034b985fe9cecf4de5add48557371789d756 Author: caelwarner Date: Wed Oct 19 15:58:56 2022 -0700 Added Train Station as peripheral - Train station can set a new auto-schedule for the train currently at the station - Added CreateLuaTable to add helper functions for working with lua tables - Added StringHelper util class to convert snake case to camel case commit 1091f3227c806f09fb443320900f7563ed264655 Author: caelwarner Date: Thu Oct 6 21:11:24 2022 -0700 Changed Display Link Peripheral API - Changed the Display Link Peripheral API to be more in line with the Monitor API - Added write, setCursorPos, getCursorPos, getSize, isColor, isColour, clearLine - Removed void writeLine, setLine, writeLines, setLines commit 18bfb216b1bd5c1b6fab99370318536ccf27b069 Author: caelwarner Date: Thu Oct 6 02:50:41 2022 -0700 Changed method of checking if a computer attached - After talking with SquidDev from CC: Tweaked I've changed to monitoring IPeripheral#attach and IPeripheral#detach for changes in the number of computers connected to the network, then updating the client using AttachedComputerPacket - This works with wired full modems, wired cabled modems and directly connected computers - Added SyncedPeripheralBase and SyncedComputerControllable for TE's and peripherals that want to be aware of attached computers commit 96dc4db6dc6cbf6519725109dbaa69851dcb0dbb Author: caelwarner Date: Tue Oct 4 21:11:38 2022 -0700 Sequenced Gearshift screen "greys out" when being controlled by a computer - This is to stop players from trying to using both the builtin sequencing and a computer to control the Sequenced Gearshift at the same time, leading to undefined behaviour - The "greyed out" screen should have a message added explaining why it's greyed out. - Added ComputerControllable#isComputerControlled to check if a tile entity is connected to a modem commit 9a807814013e54f59230d7f57f4c212164311e64 Author: caelwarner Date: Tue Oct 4 19:36:08 2022 -0700 Added PeripheralBase commit d404f073196f43eff9c0c66485693b5aed68051a Author: caelwarner Date: Mon Oct 3 20:46:16 2022 -0700 Added invalidateCaps - Changed setRemoved to invalidateCaps. I don't know why I wasn't just using invalidateCaps from the beginning commit 654476d9f33b78eb05d620ed8dd318cc9244b670 Author: caelwarner Date: Mon Oct 3 20:05:25 2022 -0700 Added Rotation Speed Controller and Sequenced Gearshift as peripherals - Rotation Speed Controller can get and set targetSpeed - Sequenced Gearshift can rotate by a certain angle and move a certain distance commit 1420406ab72204a8e34043c64404a16990104d23 Author: caelwarner Date: Mon Oct 3 16:38:12 2022 -0700 Added Speedometer and Stressometer as peripherals - Speedometer can get current speed - Stressometer can get current stress level as well as network stress capacity - Made GaugeTileEntity abstract commit 47b8619d07c9f58e6c3a34a9db97aea53071b9bd Author: caelwarner Date: Mon Oct 3 16:17:05 2022 -0700 Refactored peripheralHandler to peripheral - peripheralHandler was the wrong name. It's just a peripheral. - Changed peripheral type from "cdl" to "Create_DisplayLink" - Added equals function to DisplayLinkPeripheral commit 6591c2d46efc74d91f9a0c3d3c2aa1679fe68790 Author: caelwarner Date: Mon Oct 3 14:29:04 2022 -0700 ComputerCraft integration for Display Links - CC computers can now control display links through a variety of functions - Added ComputerControllable interface to define a tile entity as controllable by CC computers - Added CC: Tweaked soft dependency --- build.gradle | 19 ++ gradle.properties | 4 + src/main/java/com/simibubi/create/Create.java | 2 + .../java/com/simibubi/create/compat/Mods.java | 9 + .../AbstractComputerBehaviour.java | 57 ++++ .../computercraft/AttachedComputerPacket.java | 37 +++ .../computercraft/ComputerCraftProxy.java | 30 ++ .../compat/computercraft/ComputerScreen.java | 96 +++++++ .../FallbackComputerBehaviour.java | 16 ++ .../implementation/ComputerBehaviour.java | 74 +++++ .../implementation/CreateLuaTable.java | 172 +++++++++++ .../peripherals/DisplayLinkPeripheral.java | 108 +++++++ .../SequencedGearshiftPeripheral.java | 54 ++++ .../SpeedControllerPeripheral.java | 35 +++ .../peripherals/SpeedGaugePeripheral.java | 26 ++ .../peripherals/StationPeripheral.java | 269 ++++++++++++++++++ .../peripherals/StressGaugePeripheral.java | 31 ++ .../peripherals/SyncedPeripheral.java | 50 ++++ .../advanced/SpeedControllerTileEntity.java | 29 +- .../ConfigureSequencedGearshiftPacket.java | 3 + .../advanced/sequencer/Instruction.java | 6 +- .../sequencer/InstructionSpeedModifiers.java | 8 + .../sequencer/SequencedGearshiftScreen.java | 33 ++- .../SequencedGearshiftTileEntity.java | 39 ++- .../relays/gauge/GaugeTileEntity.java | 3 +- .../relays/gauge/SpeedGaugeTileEntity.java | 32 +++ .../relays/gauge/StressGaugeTileEntity.java | 25 ++ .../block/display/AllDisplayBehaviours.java | 11 + .../block/display/DisplayLinkTileEntity.java | 47 ++- .../display/source/ComputerDisplaySource.java | 33 +++ .../block/display/source/DisplaySource.java | 4 + .../logistics/trains/entity/Train.java | 19 +- .../logistics/trains/entity/TrainPacket.java | 10 +- .../station/AbstractStationScreen.java | 20 +- .../edgePoint/station/StationEditPacket.java | 100 +------ .../edgePoint/station/StationScreen.java | 2 + .../edgePoint/station/StationTileEntity.java | 122 +++++++- .../management/schedule/IScheduleInput.java | 6 +- .../schedule/ScheduleDataEntry.java | 22 +- .../condition/FluidThresholdCondition.java | 5 +- .../condition/ItemThresholdCondition.java | 5 +- .../condition/RedstoneLinkCondition.java | 5 +- .../condition/ScheduleWaitCondition.java | 16 +- .../destination/ScheduleInstruction.java | 12 +- .../create/foundation/gui/AllGuiTextures.java | 7 +- .../foundation/networking/AllPackets.java | 3 +- .../ponder/content/PonderIndex.java | 10 + .../foundation/utility/StringHelper.java | 46 +++ .../assets/create/textures/gui/computer.png | Bin 0 -> 1016 bytes wiki/Lua-Display-Link.md | 88 ++++++ wiki/Lua-Rotation-Speed-Controller.md | 18 ++ wiki/Lua-Sequenced-Gearshift.md | 28 ++ wiki/Lua-Speedometer.md | 10 + wiki/Lua-Stressometer.md | 18 ++ wiki/Lua-Train-Schedule.md | 195 +++++++++++++ wiki/Lua-Train-Station.md | 179 ++++++++++++ wiki/README.md | 2 + 57 files changed, 2152 insertions(+), 158 deletions(-) create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/ComputerCraftProxy.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/ComputerScreen.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/implementation/CreateLuaTable.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java create mode 100644 src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/display/source/ComputerDisplaySource.java create mode 100644 src/main/java/com/simibubi/create/foundation/utility/StringHelper.java create mode 100644 src/main/resources/assets/create/textures/gui/computer.png create mode 100644 wiki/Lua-Display-Link.md create mode 100644 wiki/Lua-Rotation-Speed-Controller.md create mode 100644 wiki/Lua-Sequenced-Gearshift.md create mode 100644 wiki/Lua-Speedometer.md create mode 100644 wiki/Lua-Stressometer.md create mode 100644 wiki/Lua-Train-Schedule.md create mode 100644 wiki/Lua-Train-Station.md create mode 100644 wiki/README.md diff --git a/build.gradle b/build.gradle index 05c9bdb9a..1ec83e22f 100644 --- a/build.gradle +++ b/build.gradle @@ -147,6 +147,14 @@ repositories { includeGroup "maven.modrinth" } } + maven { + // Location of maven for CC: Tweaked + name = "squiddev" + url = "https://squiddev.cc/maven/" + content { + includeGroup "org.squiddev" + } + } } dependencies { @@ -174,6 +182,11 @@ dependencies { compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_minecraft_version}-${curios_version}:api") runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_minecraft_version}-${curios_version}") + if (cc_tweaked_enable.toBoolean()) { + compileOnly fg.deobf("org.squiddev:cc-tweaked-${cc_tweaked_minecraft_version}:${cc_tweaked_version}:api") + runtimeOnly fg.deobf("org.squiddev:cc-tweaked-${cc_tweaked_minecraft_version}:${cc_tweaked_version}") + } + // implementation fg.deobf("curse.maven:druidcraft-340991:3101903") // implementation fg.deobf("com.ferreusveritas.dynamictrees:DynamicTrees-1.16.5:0.10.0-Beta25") // runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69") @@ -190,6 +203,12 @@ dependencies { } } +sourceSets.main.java { + if (!cc_tweaked_enable.toBoolean()) { + exclude 'com/simibubi/create/compat/computercraft/implementation/**' + } +} + sourceSets.main.resources { srcDir 'src/generated/resources' exclude '.cache/' diff --git a/gradle.properties b/gradle.properties index da1c49bc1..1615ed75c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -27,6 +27,10 @@ jei_version = 9.7.0.209 curios_minecraft_version = 1.18.2 curios_version = 5.0.7.0 +cc_tweaked_enable = true +cc_tweaked_minecraft_version = 1.18.2 +cc_tweaked_version = 1.100.10 + # curseforge information projectId = 328085 curse_type = beta diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 420c74a30..67acdc81b 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -9,6 +9,7 @@ import com.google.gson.GsonBuilder; import com.mojang.logging.LogUtils; import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; import com.simibubi.create.compat.Mods; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; import com.simibubi.create.compat.curios.Curios; import com.simibubi.create.content.CreateItemGroup; import com.simibubi.create.content.contraptions.TorquePropagator; @@ -130,6 +131,7 @@ public class Create { ContraptionMovementSetting.registerDefaults(); AllArmInteractionPointTypes.register(); BlockSpoutingBehaviour.registerDefaults(); + ComputerCraftProxy.register(); ForgeMod.enableMilkFluid(); CopperRegistries.inject(); diff --git a/src/main/java/com/simibubi/create/compat/Mods.java b/src/main/java/com/simibubi/create/compat/Mods.java index 55fe10952..36bd60e52 100644 --- a/src/main/java/com/simibubi/create/compat/Mods.java +++ b/src/main/java/com/simibubi/create/compat/Mods.java @@ -5,7 +5,10 @@ import java.util.function.Supplier; import com.simibubi.create.foundation.utility.Lang; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; import net.minecraftforge.fml.ModList; +import net.minecraftforge.registries.ForgeRegistries; /** * For compatibility with and without another mod present, we have to define load conditions of the specific code @@ -14,6 +17,8 @@ public enum Mods { DYNAMICTREES, TCONSTRUCT, CURIOS, + + COMPUTERCRAFT, STORAGEDRAWERS, XLPACKETS; @@ -51,4 +56,8 @@ public enum Mods { toExecute.get().run(); } } + + public Block getBlock(String id) { + return ForgeRegistries.BLOCKS.getValue(new ResourceLocation(asId(), id)); + } } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java b/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java new file mode 100644 index 000000000..a8620450b --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java @@ -0,0 +1,57 @@ +package com.simibubi.create.compat.computercraft; + +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; + +import net.minecraft.nbt.CompoundTag; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +public class AbstractComputerBehaviour extends TileEntityBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + boolean hasAttachedComputer; + + public AbstractComputerBehaviour(SmartTileEntity te) { + super(te); + this.hasAttachedComputer = false; + } + + @Override + public void read(CompoundTag nbt, boolean clientPacket) { + hasAttachedComputer = nbt.getBoolean("HasAttachedComputer"); + super.read(nbt, clientPacket); + } + + @Override + public void write(CompoundTag nbt, boolean clientPacket) { + nbt.putBoolean("HasAttachedComputer", hasAttachedComputer); + super.write(nbt, clientPacket); + } + + public boolean isPeripheralCap(Capability cap) { + return false; + } + + public LazyOptional getPeripheralCapability() { + return LazyOptional.empty(); + } + + public void removePeripheral() {} + + public void setHasAttachedComputer(boolean hasAttachedComputer) { + this.hasAttachedComputer = hasAttachedComputer; + } + + public boolean hasAttachedComputer() { + return hasAttachedComputer; + } + + @Override + public BehaviourType getType() { + return TYPE; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java b/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java new file mode 100644 index 000000000..3181217fe --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java @@ -0,0 +1,37 @@ +package com.simibubi.create.compat.computercraft; + +import com.simibubi.create.foundation.networking.TileEntityDataPacket; +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.foundation.tileEntity.SyncedTileEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; + +public class AttachedComputerPacket extends TileEntityDataPacket { + + private final boolean hasAttachedComputer; + + public AttachedComputerPacket(BlockPos tilePos, boolean hasAttachedComputer) { + super(tilePos); + this.hasAttachedComputer = hasAttachedComputer; + } + + public AttachedComputerPacket(FriendlyByteBuf buffer) { + super(buffer); + this.hasAttachedComputer = buffer.readBoolean(); + } + + @Override + protected void writeData(FriendlyByteBuf buffer) { + buffer.writeBoolean(hasAttachedComputer); + } + + @Override + protected void handlePacket(SyncedTileEntity tile) { + if (tile instanceof SmartTileEntity smartTile) { + smartTile.getBehaviour(AbstractComputerBehaviour.TYPE) + .setHasAttachedComputer(hasAttachedComputer); + } + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/ComputerCraftProxy.java b/src/main/java/com/simibubi/create/compat/computercraft/ComputerCraftProxy.java new file mode 100644 index 000000000..e424bfdad --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/ComputerCraftProxy.java @@ -0,0 +1,30 @@ +package com.simibubi.create.compat.computercraft; + +import java.util.function.Function; + +import com.simibubi.create.compat.Mods; +import com.simibubi.create.compat.computercraft.implementation.ComputerBehaviour; +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; + +public class ComputerCraftProxy { + + public static void register() { + fallbackFactory = FallbackComputerBehaviour::new; + Mods.COMPUTERCRAFT.executeIfInstalled(() -> ComputerCraftProxy::registerWithDependency); + } + + private static void registerWithDependency() { + /* Comment if computercraft.implementation is not in the source set */ + computerFactory = ComputerBehaviour::new; + } + + private static Function fallbackFactory; + private static Function computerFactory; + + public static AbstractComputerBehaviour behaviour(SmartTileEntity ste) { + if (computerFactory == null) + return fallbackFactory.apply(ste); + return computerFactory.apply(ste); + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/ComputerScreen.java b/src/main/java/com/simibubi/create/compat/computercraft/ComputerScreen.java new file mode 100644 index 000000000..2d55a2554 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/ComputerScreen.java @@ -0,0 +1,96 @@ +package com.simibubi.create.compat.computercraft; + +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.compat.Mods; +import com.simibubi.create.foundation.gui.AbstractSimiScreen; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.element.GuiGameElement; +import com.simibubi.create.foundation.gui.widget.AbstractSimiWidget; +import com.simibubi.create.foundation.gui.widget.ElementWidget; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; + +public class ComputerScreen extends AbstractSimiScreen { + + private final AllGuiTextures background = AllGuiTextures.COMPUTER; + + private final Supplier displayTitle; + private final RenderWindowFunction additional; + private final Screen previousScreen; + private final Supplier hasAttachedComputer; + + private AbstractSimiWidget computerWidget; + private IconButton confirmButton; + + public ComputerScreen(Component title, @Nullable RenderWindowFunction additional, Screen previousScreen, Supplier hasAttachedComputer) { + this(title, () -> title, additional, previousScreen, hasAttachedComputer); + } + + public ComputerScreen(Component title, Supplier displayTitle, @Nullable RenderWindowFunction additional, Screen previousScreen, Supplier hasAttachedComputer) { + super(title); + this.displayTitle = displayTitle; + this.additional = additional; + this.previousScreen = previousScreen; + this.hasAttachedComputer = hasAttachedComputer; + } + + @Override + public void tick() { + if (!hasAttachedComputer.get()) + minecraft.setScreen(previousScreen); + + super.tick(); + } + + @Override + protected void init() { + setWindowSize(background.width, background.height); + super.init(); + + int x = guiLeft; + int y = guiTop; + + Mods.COMPUTERCRAFT.executeIfInstalled(() -> () -> { + computerWidget = new ElementWidget(x + 33, y + 38) + .showingElement(GuiGameElement.of(Mods.COMPUTERCRAFT.getBlock("computer_advanced"))); + computerWidget.getToolTip().add(Lang.translate("gui.attached_computer.hint").component()); + addRenderableWidget(computerWidget); + }); + + confirmButton = new IconButton(x + background.width - 33, y + background.height - 24, AllIcons.I_CONFIRM); + confirmButton.withCallback(this::onClose); + addRenderableWidget(confirmButton); + } + + + + @Override + protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { + int x = guiLeft; + int y = guiTop; + + background.render(ms, x, y, this); + + font.draw(ms, displayTitle.get(), x + background.width / 2.0F - font.width(displayTitle.get()) / 2.0F, y + 4, 0x442000); + font.drawWordWrap(Lang.translate("gui.attached_computer.controlled").component(), x + 55, y + 32, 111, 0x7A7A7A); + + if (additional != null) + additional.render(ms, mouseX, mouseY, partialTicks, x, y, background); + } + + @FunctionalInterface + public interface RenderWindowFunction { + + void render(PoseStack ms, int mouseX, int mouseY, float partialTicks, int guiLeft, int guiTop, AllGuiTextures background); + + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java b/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java new file mode 100644 index 000000000..2e1a3da77 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java @@ -0,0 +1,16 @@ +package com.simibubi.create.compat.computercraft; + +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; + +public class FallbackComputerBehaviour extends AbstractComputerBehaviour { + + public FallbackComputerBehaviour(SmartTileEntity te) { + super(te); + } + + @Override + public boolean hasAttachedComputer() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java new file mode 100644 index 000000000..dfe1f504d --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java @@ -0,0 +1,74 @@ +package com.simibubi.create.compat.computercraft.implementation; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.implementation.peripherals.DisplayLinkPeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.SequencedGearshiftPeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.SpeedControllerPeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.SpeedGaugePeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.StationPeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.StressGaugePeripheral; +import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftTileEntity; +import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; +import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; +import com.simibubi.create.content.logistics.block.display.DisplayLinkTileEntity; +import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; + +import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.CapabilityManager; +import net.minecraftforge.common.capabilities.CapabilityToken; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.common.util.NonNullSupplier; + +public class ComputerBehaviour extends AbstractComputerBehaviour { + + protected static final Capability PERIPHERAL_CAPABILITY = + CapabilityManager.get(new CapabilityToken<>() { + }); + LazyOptional peripheral; + NonNullSupplier peripheralSupplier; + + public ComputerBehaviour(SmartTileEntity te) { + super(te); + this.peripheralSupplier = getPeripheralFor(te); + } + + public static NonNullSupplier getPeripheralFor(SmartTileEntity te) { + if (te instanceof SpeedControllerTileEntity scte) + return () -> new SpeedControllerPeripheral(scte, scte.targetSpeed); + if (te instanceof DisplayLinkTileEntity dlte) + return () -> new DisplayLinkPeripheral(dlte); + if (te instanceof SequencedGearshiftTileEntity sgte) + return () -> new SequencedGearshiftPeripheral(sgte); + if (te instanceof SpeedGaugeTileEntity sgte) + return () -> new SpeedGaugePeripheral(sgte); + if (te instanceof StressGaugeTileEntity sgte) + return () -> new StressGaugePeripheral(sgte); + if (te instanceof StationTileEntity ste) + return () -> new StationPeripheral(ste); + + throw new IllegalArgumentException("No peripheral available for " + te.getType() + .getRegistryName()); + } + + @Override + public boolean isPeripheralCap(Capability cap) { + return cap == PERIPHERAL_CAPABILITY; + } + + @Override + public LazyOptional getPeripheralCapability() { + if (peripheral == null || !peripheral.isPresent()) + peripheral = LazyOptional.of(peripheralSupplier); + return peripheral.cast(); + } + + @Override + public void removePeripheral() { + if (peripheral != null) + peripheral.invalidate(); + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/CreateLuaTable.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/CreateLuaTable.java new file mode 100644 index 000000000..3c957274e --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/CreateLuaTable.java @@ -0,0 +1,172 @@ +package com.simibubi.create.compat.computercraft.implementation; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaTable; +import dan200.computercraft.api.lua.LuaValues; + +public class CreateLuaTable implements LuaTable { + + private final Map map; + + public CreateLuaTable() { + this.map = new HashMap<>(); + } + + public CreateLuaTable(Map map) { + this.map = new HashMap<>(map); + } + + public boolean getBoolean(String key) throws LuaException { + Object value = get(key); + + if (!(value instanceof Boolean)) + throw LuaValues.badField(key, "boolean", LuaValues.getType(value)); + + return (Boolean) value; + } + + public String getString(String key) throws LuaException { + Object value = get(key); + + if (!(value instanceof String)) + throw LuaValues.badField(key, "string", LuaValues.getType(value)); + + return (String) value; + } + + public CreateLuaTable getTable(String key) throws LuaException { + Object value = get(key); + + if (!(value instanceof Map)) + throw LuaValues.badField(key, "table", LuaValues.getType(value)); + + return new CreateLuaTable((Map) value); + } + + public Optional getOptBoolean(String key) throws LuaException { + Object value = get(key); + + if (value == null) + return Optional.empty(); + + if (!(value instanceof Boolean)) + throw LuaValues.badField(key, "boolean", LuaValues.getType(value)); + + return Optional.of((Boolean) value); + } + + public Set stringKeySet() throws LuaException { + Set stringSet = new HashSet<>(); + + for (Object key : keySet()) { + if (!(key instanceof String)) + throw new LuaException("key " + key + " is not string (got " + LuaValues.getType(key) + ")"); + + stringSet.add((String) key); + } + + return Collections.unmodifiableSet(stringSet); + } + + public Collection tableValues() throws LuaException { + List tables = new ArrayList<>(); + + for (int i = 1; i <= size(); i++) { + Object value = get((double) i); + + if (!(value instanceof Map)) + throw new LuaException("value " + value + " is not table (got " + LuaValues.getType(value) + ")"); + + tables.add(new CreateLuaTable((Map) value)); + } + + return Collections.unmodifiableList(tables); + } + + public Map getMap() { + return map; + } + + @Nullable + @Override + public Object put(Object key, Object value) { + return map.put(key, value); + } + + public void putBoolean(String key, boolean value) { + map.put(key, value); + } + + public void putDouble(String key, double value) { + map.put(key, value); + } + + public void putString(String key, String value) { + map.put(key, value); + } + + public void putTable(String key, CreateLuaTable value) { + map.put(key, value); + } + + public void putTable(int i, CreateLuaTable value) { + map.put(i, value); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(Object o) { + return map.containsKey(o); + } + + @Override + public boolean containsValue(Object o) { + return map.containsValue(o); + } + + @Override + public Object get(Object o) { + return map.get(o); + } + + @NotNull + @Override + public Set keySet() { + return map.keySet(); + } + + @NotNull + @Override + public Collection values() { + return map.values(); + } + + @NotNull + @Override + public Set> entrySet() { + return map.entrySet(); + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java new file mode 100644 index 000000000..0e9275227 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java @@ -0,0 +1,108 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; +import com.simibubi.create.content.logistics.block.display.DisplayLinkTileEntity; +import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; + +import dan200.computercraft.api.lua.LuaFunction; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; + +public class DisplayLinkPeripheral extends SyncedPeripheral { + + public static final String TAG_KEY = "ComputerSourceList"; + private final AtomicInteger cursorX = new AtomicInteger(); + private final AtomicInteger cursorY = new AtomicInteger(); + + public DisplayLinkPeripheral(DisplayLinkTileEntity tile) { + super(tile); + } + + @LuaFunction + public final void setCursorPos(int x, int y) { + cursorX.set(x - 1); + cursorY.set(y - 1); + } + + @LuaFunction + public final Object[] getCursorPos() { + return new Object[] {cursorX.get() + 1, cursorY.get() + 1}; + } + + @LuaFunction(mainThread = true) + public final Object[] getSize() { + DisplayTargetStats stats = tile.activeTarget.provideStats(new DisplayLinkContext(tile.getLevel(), tile)); + return new Object[]{stats.maxRows(), stats.maxColumns()}; + } + + @LuaFunction + public final boolean isColor() { + return false; + } + + @LuaFunction + public final boolean isColour() { + return false; + } + + @LuaFunction + public final void write(String text) { + ListTag tag = tile.getSourceConfig().getList(TAG_KEY, Tag.TAG_STRING); + + int x = cursorX.get(); + int y = cursorY.get(); + + for (int i = tag.size(); i <= y; i++) { + tag.add(StringTag.valueOf("")); + } + + StringBuilder builder = new StringBuilder(tag.getString(y)); + + builder.append(" ".repeat(Math.max(0, x - builder.length()))); + builder.replace(x, x + text.length(), text); + + tag.set(y, StringTag.valueOf(builder.toString())); + + synchronized (tile) { + tile.getSourceConfig().put(TAG_KEY, tag); + } + + cursorX.set(x + text.length()); + } + + @LuaFunction + public final void clearLine() { + ListTag tag = tile.getSourceConfig().getList(TAG_KEY, Tag.TAG_STRING); + + if (tag.size() > cursorY.get()) + tag.set(cursorY.get(), StringTag.valueOf("")); + + synchronized (tile) { + tile.getSourceConfig().put(TAG_KEY, tag); + } + } + + @LuaFunction + public final void clear() { + synchronized (tile) { + tile.getSourceConfig().put(TAG_KEY, new ListTag()); + } + } + + @LuaFunction(mainThread = true) + public final void update() { + tile.tickSource(); + } + + @NotNull + @Override + public String getType() { + return "Create_DisplayLink"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java new file mode 100644 index 000000000..8addb181e --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java @@ -0,0 +1,54 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.Instruction; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.InstructionSpeedModifiers; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftTileEntity; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencerInstructions; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; + +public class SequencedGearshiftPeripheral extends SyncedPeripheral { + + public SequencedGearshiftPeripheral(SequencedGearshiftTileEntity tile) { + super(tile); + } + + @LuaFunction(mainThread = true) + public final void rotate(IArguments arguments) throws LuaException { + runInstruction(arguments, SequencerInstructions.TURN_ANGLE); + } + + @LuaFunction(mainThread = true) + public final void move(IArguments arguments) throws LuaException { + runInstruction(arguments, SequencerInstructions.TURN_DISTANCE); + } + + @LuaFunction + public final boolean isRunning() { + return !this.tile.isIdle(); + } + + private void runInstruction(IArguments arguments, SequencerInstructions instructionType) throws LuaException { + int speedModifier = arguments.count() > 1 ? arguments.getInt(1) : 1; + this.tile.getInstructions().clear(); + + this.tile.getInstructions().add(new Instruction( + instructionType, + InstructionSpeedModifiers.getByModifier(speedModifier), + Math.abs(arguments.getInt(0)))); + this.tile.getInstructions().add(new Instruction(SequencerInstructions.END)); + + this.tile.run(0); + } + + @NotNull + @Override + public String getType() { + return "Create_SequencedGearshift"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java new file mode 100644 index 000000000..2aba811f0 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java @@ -0,0 +1,35 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity; +import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; + +import dan200.computercraft.api.lua.LuaFunction; + +public class SpeedControllerPeripheral extends SyncedPeripheral { + + private final ScrollValueBehaviour targetSpeed; + + public SpeedControllerPeripheral(SpeedControllerTileEntity tile, ScrollValueBehaviour targetSpeed) { + super(tile); + this.targetSpeed = targetSpeed; + } + + @LuaFunction(mainThread = true) + public final void setTargetSpeed(int speed) { + this.targetSpeed.setValue(speed); + } + + @LuaFunction + public final float getTargetSpeed() { + return this.targetSpeed.getValue(); + } + + @NotNull + @Override + public String getType() { + return "Create_RotationSpeedController"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java new file mode 100644 index 000000000..a13b02cd5 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java @@ -0,0 +1,26 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; + +import dan200.computercraft.api.lua.LuaFunction; + +public class SpeedGaugePeripheral extends SyncedPeripheral { + + public SpeedGaugePeripheral(SpeedGaugeTileEntity tile) { + super(tile); + } + + @LuaFunction + public final float getSpeed() { + return this.tile.getSpeed(); + } + + @NotNull + @Override + public String getType() { + return "Create_Speedometer"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java new file mode 100644 index 000000000..3de8e979b --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java @@ -0,0 +1,269 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import java.util.Map; + +import javax.annotation.Nullable; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.compat.computercraft.implementation.CreateLuaTable; +import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; +import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; +import com.simibubi.create.content.logistics.trains.management.edgePoint.station.TrainEditPacket; +import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; +import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.Components; +import com.simibubi.create.foundation.utility.StringHelper; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import net.minecraft.nbt.ByteTag; +import net.minecraft.nbt.CollectionTag; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.IntTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NumericTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraftforge.network.PacketDistributor; + +public class StationPeripheral extends SyncedPeripheral { + + public StationPeripheral(StationTileEntity tile) { + super(tile); + } + + @LuaFunction(mainThread = true) + public final void assemble() throws LuaException { + if (!tile.isAssembling()) + throw new LuaException("station must be in assembly mode"); + + tile.assemble(null); + + if (tile.getStation() == null || tile.getStation().getPresentTrain() == null) + throw new LuaException("failed to assemble train"); + + if (!tile.exitAssemblyMode()) + throw new LuaException("failed to exit assembly mode"); + } + + @LuaFunction(mainThread = true) + public final void disassemble() throws LuaException { + if (tile.isAssembling()) + throw new LuaException("station must not be in assembly mode"); + + getTrainOrThrow(); + + if (!tile.enterAssemblyMode(null)) + throw new LuaException("could not disassemble train"); + } + + @LuaFunction(mainThread = true) + public final void setAssemblyMode(boolean assemblyMode) throws LuaException { + if (assemblyMode) { + if (!tile.enterAssemblyMode(null)) + throw new LuaException("failed to enter assembly mode"); + } else { + if (!tile.exitAssemblyMode()) + throw new LuaException("failed to exit assembly mode"); + } + } + + @LuaFunction + public final boolean isInAssemblyMode() { + return tile.isAssembling(); + } + + @LuaFunction + public final String getStationName() throws LuaException { + GlobalStation station = tile.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + return station.name; + } + + @LuaFunction(mainThread = true) + public final void setStationName(String name) throws LuaException { + if (!tile.updateName(name)) + throw new LuaException("could not set station name"); + } + + @LuaFunction + public final boolean isTrainPresent() throws LuaException { + GlobalStation station = tile.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + return station.getPresentTrain() != null; + } + + @LuaFunction + public final boolean isTrainImminent() throws LuaException { + GlobalStation station = tile.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + return station.getImminentTrain() != null; + } + + @LuaFunction + public final boolean isTrainEnroute() throws LuaException { + GlobalStation station = tile.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + return station.getNearestTrain() != null; + } + + @LuaFunction + public final String getTrainName() throws LuaException { + Train train = getTrainOrThrow(); + return train.name.getString(); + } + + @LuaFunction(mainThread = true) + public final void setTrainName(String name) throws LuaException { + Train train = getTrainOrThrow(); + train.name = Components.literal(name); + AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainEditPacket.TrainEditReturnPacket(train.id, name, train.icon.getId())); + } + + @LuaFunction + public final boolean hasSchedule() throws LuaException { + Train train = getTrainOrThrow(); + return train.runtime.getSchedule() != null; + } + + @LuaFunction + public final CreateLuaTable getSchedule() throws LuaException { + Train train = getTrainOrThrow(); + + Schedule schedule = train.runtime.getSchedule(); + if (schedule == null) + throw new LuaException("train doesn't have a schedule"); + + return fromCompoundTag(schedule.write()); + } + + @LuaFunction(mainThread = true) + public final void setSchedule(IArguments arguments) throws LuaException { + Train train = getTrainOrThrow(); + Schedule schedule = Schedule.fromTag(toCompoundTag(new CreateLuaTable(arguments.getTable(0)))); + boolean autoSchedule = train.runtime.getSchedule() == null || train.runtime.isAutoSchedule; + train.runtime.setSchedule(schedule, autoSchedule); + } + + private @NotNull Train getTrainOrThrow() throws LuaException { + GlobalStation station = tile.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + Train train = station.getPresentTrain(); + if (train == null) + throw new LuaException("there is no train present"); + + return train; + } + + private static @NotNull CreateLuaTable fromCompoundTag(CompoundTag tag) throws LuaException { + return (CreateLuaTable) fromNBTTag(null, tag); + } + + private static @NotNull Object fromNBTTag(@Nullable String key, Tag tag) throws LuaException { + byte type = tag.getId(); + + if (type == Tag.TAG_BYTE && key != null && key.equals("Count")) + return ((NumericTag) tag).getAsByte(); + else if (type == Tag.TAG_BYTE) + return ((NumericTag) tag).getAsByte() != 0; + else if (type == Tag.TAG_SHORT || type == Tag.TAG_INT || type == Tag.TAG_LONG) + return ((NumericTag) tag).getAsLong(); + else if (type == Tag.TAG_FLOAT || type == Tag.TAG_DOUBLE) + return ((NumericTag) tag).getAsDouble(); + else if (type == Tag.TAG_STRING) + return tag.getAsString(); + else if (type == Tag.TAG_LIST || type == Tag.TAG_BYTE_ARRAY || type == Tag.TAG_INT_ARRAY || type == Tag.TAG_LONG_ARRAY) { + CreateLuaTable list = new CreateLuaTable(); + CollectionTag listTag = (CollectionTag) tag; + + for (int i = 0; i < listTag.size(); i++) { + list.put(i + 1, fromNBTTag(null, listTag.get(i))); + } + + return list; + + } else if (type == Tag.TAG_COMPOUND) { + CreateLuaTable table = new CreateLuaTable(); + CompoundTag compoundTag = (CompoundTag) tag; + + for (String compoundKey : compoundTag.getAllKeys()) { + table.put( + StringHelper.camelCaseToSnakeCase(compoundKey), + fromNBTTag(compoundKey, compoundTag.get(compoundKey)) + ); + } + + return table; + } + + throw new LuaException("unknown tag type " + tag.getType().getName()); + } + + private static @NotNull CompoundTag toCompoundTag(CreateLuaTable table) throws LuaException { + return (CompoundTag) toNBTTag(null, table.getMap()); + } + + private static @NotNull Tag toNBTTag(@Nullable String key, Object value) throws LuaException { + if (value instanceof Boolean v) + return ByteTag.valueOf(v); + else if (value instanceof Byte || (key != null && key.equals("count"))) + return ByteTag.valueOf(((Number) value).byteValue()); + else if (value instanceof Number v) { + // If number is numerical integer + if (v.intValue() == v.doubleValue()) + return IntTag.valueOf(v.intValue()); + else + return DoubleTag.valueOf(v.doubleValue()); + + } else if (value instanceof String v) + return StringTag.valueOf(v); + else if (value instanceof Map v && v.containsKey(1.0)) { // List + ListTag list = new ListTag(); + for (Object o : v.values()) { + list.add(toNBTTag(null, o)); + } + + return list; + + } else if (value instanceof Map v) { // Table/Map + CompoundTag compound = new CompoundTag(); + for (Object objectKey : v.keySet()) { + if (!(objectKey instanceof String compoundKey)) + throw new LuaException("table key is not of type string"); + + compound.put( + // Items serialize their resource location as "id" and not as "Id". + // This check is needed to see if the 'i' should be left lowercase or not. + // Items store "count" in the same compound tag, so we can check for its presence to see if this is a serialized item + compoundKey.equals("id") && v.containsKey("count") ? "id" : StringHelper.snakeCaseToCamelCase(compoundKey), + toNBTTag(compoundKey, v.get(compoundKey)) + ); + } + + return compound; + } + + throw new LuaException("unknown object type " + value.getClass().getName()); + } + + @NotNull + @Override + public String getType() { + return "Create_Station"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java new file mode 100644 index 000000000..b712bd6da --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java @@ -0,0 +1,31 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; + +import dan200.computercraft.api.lua.LuaFunction; + +public class StressGaugePeripheral extends SyncedPeripheral { + + public StressGaugePeripheral(StressGaugeTileEntity tile) { + super(tile); + } + + @LuaFunction + public final float getStress() { + return this.tile.getNetworkStress(); + } + + @LuaFunction + public final float getStressCapacity() { + return this.tile.getNetworkCapacity(); + } + + @NotNull + @Override + public String getType() { + return "Create_Stressometer"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java new file mode 100644 index 000000000..a6371063d --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java @@ -0,0 +1,50 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.compat.computercraft.AttachedComputerPacket; +import com.simibubi.create.compat.computercraft.implementation.ComputerBehaviour; +import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; + +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraftforge.network.PacketDistributor; + +public abstract class SyncedPeripheral implements IPeripheral { + + protected final T tile; + private final AtomicInteger computers = new AtomicInteger(); + + public SyncedPeripheral(T tile) { + this.tile = tile; + } + + @Override + public void attach(@NotNull IComputerAccess computer) { + computers.incrementAndGet(); + updateTile(); + } + + @Override + public void detach(@NotNull IComputerAccess computer) { + computers.decrementAndGet(); + updateTile(); + } + + private void updateTile() { + boolean hasAttachedComputer = computers.get() > 0; + + tile.getBehaviour(ComputerBehaviour.TYPE).setHasAttachedComputer(hasAttachedComputer); + AllPackets.channel.send(PacketDistributor.ALL.noArg(), new AttachedComputerPacket(tile.getBlockPos(), hasAttachedComputer)); + } + + @Override + public boolean equals(@Nullable IPeripheral other) { + return this == other; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerTileEntity.java index 9238ed52e..37385e92b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerTileEntity.java @@ -2,6 +2,11 @@ package com.simibubi.create.content.contraptions.relays.advanced; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; import com.simibubi.create.content.contraptions.RotationPropagator; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.motor.CreativeMotorTileEntity; @@ -20,11 +25,14 @@ import net.minecraft.core.Direction; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; public class SpeedControllerTileEntity extends KineticTileEntity { public static final int DEFAULT_SPEED = 16; - protected ScrollValueBehaviour targetSpeed; + public ScrollValueBehaviour targetSpeed; + public AbstractComputerBehaviour computerBehaviour; boolean hasBracket; @@ -53,7 +61,8 @@ public class SpeedControllerTileEntity extends KineticTileEntity { targetSpeed.withCallback(i -> this.updateTargetRotation()); targetSpeed.withStepFunction(CreativeMotorTileEntity::step); behaviours.add(targetSpeed); - + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + registerAwardables(behaviours, AllAdvancements.SPEED_CONTROLLER); } @@ -63,7 +72,7 @@ public class SpeedControllerTileEntity extends KineticTileEntity { RotationPropagator.handleRemoved(level, worldPosition, this); removeSource(); attachKinetics(); - + if (isCogwheelPresent() && getSpeed() != 0) award(AllAdvancements.SPEED_CONTROLLER); } @@ -127,6 +136,20 @@ public class SpeedControllerTileEntity extends KineticTileEntity { && stateAbove.getValue(CogWheelBlock.AXIS).isHorizontal(); } + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + private class ControllerValueBoxTransform extends ValueBoxTransform.Sided { @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/ConfigureSequencedGearshiftPacket.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/ConfigureSequencedGearshiftPacket.java index 75fb4ca84..fa77415c4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/ConfigureSequencedGearshiftPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/ConfigureSequencedGearshiftPacket.java @@ -35,6 +35,9 @@ public class ConfigureSequencedGearshiftPacket extends TileEntityConfigurationPa @Override protected void applySettings(SequencedGearshiftTileEntity te) { + if (te.computerBehaviour.hasAttachedComputer()) + return; + te.run(-1); te.instructions = Instruction.deserializeAll(instructions); te.sendData(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java index 9335285d1..a7b91a04a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java @@ -19,8 +19,12 @@ public class Instruction { } public Instruction(SequencerInstructions instruction, int value) { + this(instruction, InstructionSpeedModifiers.FORWARD, value); + } + + public Instruction(SequencerInstructions instruction, InstructionSpeedModifiers speedModifier, int value) { this.instruction = instruction; - speedModifier = InstructionSpeedModifiers.FORWARD; + this.speedModifier = speedModifier; this.value = value; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/InstructionSpeedModifiers.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/InstructionSpeedModifiers.java index 93713d075..b1a1f236a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/InstructionSpeedModifiers.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/InstructionSpeedModifiers.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.relays.advanced.sequencer; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import com.simibubi.create.foundation.utility.Components; @@ -36,4 +37,11 @@ public enum InstructionSpeedModifiers { return options; } + public static InstructionSpeedModifiers getByModifier(int modifier) { + return Arrays.stream(InstructionSpeedModifiers.values()) + .filter(speedModifier -> speedModifier.value == modifier) + .findAny() + .orElse(InstructionSpeedModifiers.FORWARD); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java index 7f2c86ab4..1cf8e7259 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java @@ -4,6 +4,7 @@ import java.util.Vector; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; +import com.simibubi.create.compat.computercraft.ComputerScreen; import com.simibubi.create.foundation.gui.AbstractSimiScreen; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; @@ -15,7 +16,6 @@ import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Components; import com.simibubi.create.foundation.utility.Lang; -import net.minecraft.core.BlockPos; import net.minecraft.nbt.ListTag; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; @@ -25,22 +25,26 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { private final ItemStack renderedItem = AllBlocks.SEQUENCED_GEARSHIFT.asStack(); private final AllGuiTextures background = AllGuiTextures.SEQUENCER; private IconButton confirmButton; + private SequencedGearshiftTileEntity te; private ListTag compareTag; private Vector instructions; - private BlockPos pos; private Vector> inputs; public SequencedGearshiftScreen(SequencedGearshiftTileEntity te) { super(Lang.translateDirect("gui.sequenced_gearshift.title")); this.instructions = te.instructions; - this.pos = te.getBlockPos(); + this.te = te; compareTag = Instruction.serializeAll(instructions); } @Override protected void init() { + if (te.computerBehaviour.hasAttachedComputer()) + minecraft.setScreen(new ComputerScreen(title, this::renderAdditional, + this, te.computerBehaviour::hasAttachedComputer)); + setWindowSize(background.width, background.height); setWindowOffset(-20, 0); super.init(); @@ -127,6 +131,15 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { modifier.setState(instruction.speedModifier.ordinal()); } + @Override + public void tick() { + super.tick(); + + if (te.computerBehaviour.hasAttachedComputer()) + minecraft.setScreen(new ComputerScreen(title, this::renderAdditional, + this, te.computerBehaviour::hasAttachedComputer)); + } + @Override protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { int x = guiLeft; @@ -134,6 +147,13 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { background.render(ms, x, y, this); + for (int row = 0; row < instructions.capacity(); row++) { + AllGuiTextures toDraw = AllGuiTextures.SEQUENCER_EMPTY; + int yOffset = toDraw.height * row; + + toDraw.render(ms, x, y + 14 + yOffset, this); + } + for (int row = 0; row < instructions.capacity(); row++) { AllGuiTextures toDraw = AllGuiTextures.SEQUENCER_EMPTY; int yOffset = toDraw.height * row; @@ -156,10 +176,13 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { label(ms, 127, yOffset - 3, instruction.speedModifier.label); } + renderAdditional(ms, mouseX, mouseY, partialTicks, x, y, background); drawCenteredString(ms, font, title, x + (background.width - 8) / 2, y + 3, 0xFFFFFF); + } + private void renderAdditional(PoseStack ms, int mouseX, int mouseY, float partialTicks, int guiLeft, int guiTop, AllGuiTextures background) { GuiGameElement.of(renderedItem) - .at(x + background.width + 6, y + background.height - 56, -200) + .at(guiLeft + background.width + 6, guiTop + background.height - 56, 100) .scale(5) .render(ms); } @@ -172,7 +195,7 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { ListTag serialized = Instruction.serializeAll(instructions); if (serialized.equals(compareTag)) return; - AllPackets.channel.sendToServer(new ConfigureSequencedGearshiftPacket(pos, serialized)); + AllPackets.channel.sendToServer(new ConfigureSequencedGearshiftPacket(te.getBlockPos(), serialized)); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java index 9c595af72..2fd02b095 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java @@ -1,8 +1,15 @@ package com.simibubi.create.content.contraptions.relays.advanced.sequencer; +import java.util.List; import java.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; import com.simibubi.create.content.contraptions.relays.encased.SplitShaftTileEntity; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -10,6 +17,8 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { @@ -20,6 +29,8 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { int timer; boolean poweredPreviously; + public AbstractComputerBehaviour computerBehaviour; + public SequencedGearshiftTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); instructions = Instruction.createDefault(); @@ -30,6 +41,12 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { poweredPreviously = false; } + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + } + @Override public void tick() { super.tick(); @@ -72,6 +89,8 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { } public void onRedstoneUpdate(boolean isPowered, boolean isRunning) { + if (computerBehaviour.hasAttachedComputer()) + return; if (!poweredPreviously && isPowered) risingFlank(); poweredPreviously = isPowered; @@ -105,7 +124,7 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { } } - protected void run(int instructionIndex) { + public void run(int instructionIndex) { Instruction instruction = getInstruction(instructionIndex); if (instruction == null || instruction.instruction == SequencerInstructions.END) { if (getModifier() != 0) @@ -156,6 +175,20 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { super.read(compound, clientPacket); } + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + @Override public float getRotationSpeedModifier(Direction face) { if (isVirtual()) @@ -171,4 +204,8 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { .getSpeedModifier(); } + public Vector getInstructions() { + return this.instructions; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java index bdd77ba69..bc320e85d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java @@ -12,7 +12,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -public class GaugeTileEntity extends KineticTileEntity implements IHaveGoggleInformation { +public abstract class GaugeTileEntity extends KineticTileEntity implements IHaveGoggleInformation { public float dialTarget; public float dialState; @@ -52,4 +52,5 @@ public class GaugeTileEntity extends KineticTileEntity implements IHaveGoggleInf return true; } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java index fb48c7209..5f853e7d9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java @@ -2,24 +2,41 @@ package com.simibubi.create.content.contraptions.relays.gauge; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.utility.Color; import com.simibubi.create.foundation.utility.Lang; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; public class SpeedGaugeTileEntity extends GaugeTileEntity { + public AbstractComputerBehaviour computerBehaviour; + public SpeedGaugeTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); } + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + } + @Override public void onSpeedChanged(float prevSpeed) { super.onSpeedChanged(prevSpeed); @@ -62,4 +79,19 @@ public class SpeedGaugeTileEntity extends GaugeTileEntity { .forGoggles(tooltip); return true; } + + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/StressGaugeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/StressGaugeTileEntity.java index 665226cb1..8eb5c9d0e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/StressGaugeTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/StressGaugeTileEntity.java @@ -2,6 +2,11 @@ package com.simibubi.create.content.contraptions.relays.gauge; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; import com.simibubi.create.content.contraptions.base.IRotate.StressImpact; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.item.ItemDescription; @@ -13,14 +18,19 @@ import com.simibubi.create.foundation.utility.LangBuilder; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; public class StressGaugeTileEntity extends GaugeTileEntity { + public AbstractComputerBehaviour computerBehaviour; + static BlockPos lastSent; public StressGaugeTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { @@ -30,6 +40,7 @@ public class StressGaugeTileEntity extends GaugeTileEntity { @Override public void addBehaviours(List behaviours) { super.addBehaviours(behaviours); + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); registerAwardables(behaviours, AllAdvancements.STRESSOMETER, AllAdvancements.STRESSOMETER_MAXED); } @@ -141,4 +152,18 @@ public class StressGaugeTileEntity extends GaugeTileEntity { award(AllAdvancements.STRESSOMETER_MAXED); } + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/AllDisplayBehaviours.java b/src/main/java/com/simibubi/create/content/logistics/block/display/AllDisplayBehaviours.java index 55637bae2..5f73512f2 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/AllDisplayBehaviours.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/display/AllDisplayBehaviours.java @@ -9,6 +9,8 @@ import java.util.Map; import javax.annotation.Nullable; import com.simibubi.create.Create; +import com.simibubi.create.compat.Mods; +import com.simibubi.create.content.logistics.block.display.source.ComputerDisplaySource; import com.simibubi.create.content.logistics.block.display.source.DeathCounterDisplaySource; import com.simibubi.create.content.logistics.block.display.source.DisplaySource; import com.simibubi.create.content.logistics.block.display.source.EnchantPowerDisplaySource; @@ -237,5 +239,14 @@ public class AllDisplayBehaviours { assignTile(register(Create.asResource("scoreboard_display_source"), new ScoreboardDisplaySource()), BlockEntityType.COMMAND_BLOCK); assignTile(register(Create.asResource("enchant_power_display_source"), new EnchantPowerDisplaySource()), BlockEntityType.ENCHANTING_TABLE); assignBlock(register(Create.asResource("redstone_power_display_source"), new RedstonePowerDisplaySource()), Blocks.TARGET); + + Mods.COMPUTERCRAFT.executeIfInstalled(() -> () -> { + DisplayBehaviour computerDisplaySource = register(Create.asResource("computer_display_source"), new ComputerDisplaySource()); + + assignTile(computerDisplaySource, new ResourceLocation(Mods.COMPUTERCRAFT.asId(), "wired_modem_full")); + assignTile(computerDisplaySource, new ResourceLocation(Mods.COMPUTERCRAFT.asId(), "computer_normal")); + assignTile(computerDisplaySource, new ResourceLocation(Mods.COMPUTERCRAFT.asId(), "computer_advanced")); + assignTile(computerDisplaySource, new ResourceLocation(Mods.COMPUTERCRAFT.asId(), "computer_command")); + }); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkTileEntity.java index 9d9a5f606..448afed55 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkTileEntity.java @@ -2,6 +2,11 @@ package com.simibubi.create.content.logistics.block.display; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; import com.simibubi.create.content.logistics.block.display.source.DisplaySource; import com.simibubi.create.content.logistics.block.display.target.DisplayTarget; import com.simibubi.create.foundation.advancement.AllAdvancements; @@ -18,6 +23,8 @@ import net.minecraft.nbt.NbtUtils; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; public class DisplayLinkTileEntity extends SmartTileEntity { @@ -31,9 +38,11 @@ public class DisplayLinkTileEntity extends SmartTileEntity { public LerpedFloat glow; private boolean sendPulse; - + public int refreshTicks; + public AbstractComputerBehaviour computerBehaviour; + public DisplayLinkTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); targetOffset = BlockPos.ZERO; @@ -44,10 +53,16 @@ public class DisplayLinkTileEntity extends SmartTileEntity { glow.chase(0, 0.5f, Chaser.EXP); } + @Override + public void addBehaviours(List behaviours) { + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + registerAwardables(behaviours, AllAdvancements.DISPLAY_LINK, AllAdvancements.DISPLAY_BOARD); + } + @Override public void tick() { super.tick(); - + if (isVirtual()) { glow.tickChaser(); return; @@ -59,9 +74,9 @@ public class DisplayLinkTileEntity extends SmartTileEntity { glow.tickChaser(); return; } - + refreshTicks++; - if (refreshTicks < activeSource.getPassiveRefreshTicks()) + if (refreshTicks < activeSource.getPassiveRefreshTicks() || !activeSource.shouldPassiveReset()) return; tickSource(); } @@ -114,13 +129,8 @@ public class DisplayLinkTileEntity extends SmartTileEntity { activeSource.transferData(context, activeTarget, targetLine); sendPulse = true; sendData(); - - award(AllAdvancements.DISPLAY_LINK); - } - @Override - public void addBehaviours(List behaviours) { - registerAwardables(behaviours, AllAdvancements.DISPLAY_LINK, AllAdvancements.DISPLAY_BOARD); + award(AllAdvancements.DISPLAY_LINK); } @Override @@ -133,7 +143,7 @@ public class DisplayLinkTileEntity extends SmartTileEntity { protected void write(CompoundTag tag, boolean clientPacket) { super.write(tag, clientPacket); writeGatheredData(tag); - if (clientPacket && activeTarget != null) + if (clientPacket && activeTarget != null) tag.putString("TargetType", activeTarget.id.toString()); if (clientPacket && sendPulse) { sendPulse = false; @@ -173,6 +183,21 @@ public class DisplayLinkTileEntity extends SmartTileEntity { sourceConfig = data.copy(); } + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + public void target(BlockPos targetPosition) { this.targetOffset = targetPosition.subtract(worldPosition); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ComputerDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/ComputerDisplaySource.java new file mode 100644 index 000000000..e3e988143 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/display/source/ComputerDisplaySource.java @@ -0,0 +1,33 @@ +package com.simibubi.create.content.logistics.block.display.source; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; +import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; +import com.simibubi.create.foundation.utility.Components; + +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.MutableComponent; + +public class ComputerDisplaySource extends DisplaySource { + + @Override + public List provideText(DisplayLinkContext context, DisplayTargetStats stats) { + List components = new ArrayList<>(); + ListTag tag = context.sourceConfig().getList("ComputerSourceList", Tag.TAG_STRING); + + for (int i = 0; i < tag.size(); i++) { + components.add(Components.literal(tag.getString(i))); + } + + return components; + } + + @Override + public boolean shouldPassiveReset() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/DisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/DisplaySource.java index 5b9877273..d844a1ed1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/DisplaySource.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/display/source/DisplaySource.java @@ -49,6 +49,10 @@ public abstract class DisplaySource extends DisplayBehaviour { return 100; }; + public boolean shouldPassiveReset() { + return true; + } + protected String getTranslationKey() { return id.getPath(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index a5a371013..8c237ceaf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -15,8 +15,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.Consumer; -import javax.annotation.Nullable; - import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableObject; @@ -51,7 +49,7 @@ import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.VecHelper; - +import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; @@ -67,6 +65,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Explosion.BlockInteraction; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; + import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; @@ -86,6 +85,7 @@ public class Train { public boolean honk = false; public UUID id; + @Nullable public UUID owner; public TrackGraph graph; public Navigation navigation; @@ -124,7 +124,7 @@ public class Train { public int honkPitch; public float accumulatedSteamRelease; - + int tickOffset; double[] stress; @@ -277,7 +277,7 @@ public class Train { int carriageCount = carriages.size(); boolean stalled = false; double maxStress = 0; - + if (carriageWaitingForChunks != -1) distance = 0; @@ -317,7 +317,7 @@ public class Train { entries++; } } - + if (entries > 0) actual = total / entries; @@ -369,7 +369,7 @@ public class Train { .getLeadingPoint(); double totalStress = derailed ? 0 : leadingStress + trailingStress; - + boolean first = i == 0; boolean last = i == carriageCount - 1; int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE; @@ -1087,7 +1087,8 @@ public class Train { public CompoundTag write(DimensionPalette dimensions) { CompoundTag tag = new CompoundTag(); tag.putUUID("Id", id); - tag.putUUID("Owner", owner); + if (owner != null) + tag.putUUID("Owner", owner); if (graph != null) tag.putUUID("Graph", graph.id); tag.put("Carriages", NBTHelper.writeCompoundList(carriages, c -> c.write(dimensions))); @@ -1133,7 +1134,7 @@ public class Train { public static Train read(CompoundTag tag, Map trackNetworks, DimensionPalette dimensions) { UUID id = tag.getUUID("Id"); - UUID owner = tag.getUUID("Owner"); + UUID owner = tag.contains("Owner") ? tag.getUUID("Owner") : null; UUID graphId = tag.contains("Graph") ? tag.getUUID("Graph") : null; TrackGraph graph = graphId == null ? null : trackNetworks.get(graphId); List carriages = new ArrayList<>(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java index 479b2699e..ec43cd9f9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java @@ -12,7 +12,6 @@ import com.simibubi.create.foundation.networking.SimplePacketBase; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.RegisteredObjects; - import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.Block; @@ -37,7 +36,10 @@ public class TrainPacket extends SimplePacketBase { if (!add) return; - UUID owner = buffer.readUUID(); + UUID owner = null; + if (buffer.readBoolean()) + owner = buffer.readUUID(); + List carriages = new ArrayList<>(); List carriageSpacing = new ArrayList<>(); @@ -73,7 +75,9 @@ public class TrainPacket extends SimplePacketBase { if (!add) return; - buffer.writeUUID(train.owner); + buffer.writeBoolean(train.owner != null); + if (train.owner != null) + buffer.writeUUID(train.owner); buffer.writeVarInt(train.carriages.size()); for (Carriage carriage : train.carriages) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java index ed32075ae..a1d5ea049 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java @@ -7,6 +7,7 @@ import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.CreateClient; +import com.simibubi.create.compat.computercraft.ComputerScreen; import com.simibubi.create.content.logistics.trains.entity.Carriage; import com.simibubi.create.content.logistics.trains.entity.Train; import com.simibubi.create.content.logistics.trains.entity.TrainIconType; @@ -15,6 +16,7 @@ import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.element.GuiGameElement; import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.utility.Components; import net.minecraft.world.level.block.state.properties.BlockStateProperties; @@ -39,6 +41,10 @@ public abstract class AbstractStationScreen extends AbstractSimiScreen { @Override protected void init() { + if (te.computerBehaviour.hasAttachedComputer()) + minecraft.setScreen(new ComputerScreen(title, () -> Components.literal(station.name), + this::renderAdditional, this, te.computerBehaviour::hasAttachedComputer)); + setWindowSize(background.width, background.height); super.init(); clearWidgets(); @@ -71,17 +77,29 @@ public abstract class AbstractStationScreen extends AbstractSimiScreen { return w; } + @Override + public void tick() { + super.tick(); + + if (te.computerBehaviour.hasAttachedComputer()) + minecraft.setScreen(new ComputerScreen(title, () -> Components.literal(station.name), + this::renderAdditional, this, te.computerBehaviour::hasAttachedComputer)); + } + @Override protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { int x = guiLeft; int y = guiTop; background.render(ms, x, y, this); + renderAdditional(ms, mouseX, mouseY, partialTicks, x, y, background); + } + private void renderAdditional(PoseStack ms, int mouseX, int mouseY, float partialTicks, int guiLeft, int guiTop, AllGuiTextures background) { ms.pushPose(); TransformStack msr = TransformStack.cast(ms); msr.pushPose() - .translate(x + background.width + 4, y + background.height + 4, 100) + .translate(guiLeft + background.width + 4, guiTop + background.height + 4, 100) .scale(40) .rotateX(-22) .rotateY(63); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java index e1ec084c7..2028aca9d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java @@ -1,19 +1,11 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.station; -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.GraphLocation; -import com.simibubi.create.content.logistics.trains.entity.Train; import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; -import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; public class StationEditPacket extends TileEntityConfigurationPacket { @@ -92,18 +84,12 @@ public class StationEditPacket extends TileEntityConfigurationPacket station.assembling = true); + GlobalStation station = getStation(); + if (station != null) { + for (Train train : Create.RAILWAYS.sided(level).trains.values()) { + if (train.navigation.destination != station) + continue; + + GlobalStation preferredDestination = train.runtime.startCurrentInstruction(); + train.navigation.startNavigation(preferredDestination != null ? preferredDestination : station, Double.MAX_VALUE, false); + } + } + + return true; + } + + public boolean exitAssemblyMode() { + if (!isAssembling()) + return false; + + cancelAssembly(); + BlockState newState = getBlockState().setValue(StationBlock.ASSEMBLING, false); + level.setBlock(getBlockPos(), newState, 3); + refreshBlockState(); + + return updateStationState(station -> station.assembling = false); + } + + public boolean tryDisassembleTrain(@Nullable ServerPlayer sender) { + GlobalStation station = getStation(); + if (station == null) + return false; + + Train train = station.getPresentTrain(); + if (train == null) + return false; + + BlockPos trackPosition = edgePoint.getGlobalPosition(); + if (!train.disassemble(getAssemblyDirection(), trackPosition.above())) + return false; + + dropSchedule(sender); + return true; + } + public boolean isAssembling() { BlockState state = getBlockState(); return state.hasProperty(StationBlock.ASSEMBLING) && state.getValue(StationBlock.ASSEMBLING); @@ -341,6 +409,42 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable return true; } + public void dropSchedule(@Nullable ServerPlayer sender) { + GlobalStation station = getStation(); + if (station == null) + return; + + Train train = station.getPresentTrain(); + if (train == null) + return; + + ItemStack schedule = train.runtime.returnSchedule(); + if (schedule.isEmpty()) + return; + if (sender != null && sender.getMainHandItem().isEmpty()) { + sender.getInventory() + .placeItemBackInInventory(schedule); + return; + } + + Vec3 v = VecHelper.getCenterOf(getBlockPos()); + ItemEntity itemEntity = new ItemEntity(getLevel(), v.x, v.y, v.z, schedule); + itemEntity.setDeltaMovement(Vec3.ZERO); + getLevel().addFreshEntity(itemEntity); + } + + private boolean updateStationState(Consumer updateState) { + GlobalStation station = getStation(); + GraphLocation graphLocation = edgePoint.determineGraphLocation(); + if (station == null || graphLocation == null) + return false; + + updateState.accept(station); + Create.RAILWAYS.sync.pointAdded(graphLocation.graph, station); + Create.RAILWAYS.markTracksDirty(); + return true; + } + public void refreshAssemblyInfo() { if (!edgePoint.hasValidTrack()) return; @@ -409,6 +513,14 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable map.put(worldPosition, BoundingBox.fromCorners(startPosition, trackEnd)); } + public boolean updateName(String name) { + if (!updateStationState(station -> station.name = name)) + return false; + notifyUpdate(); + + return true; + } + public boolean isValidBogeyOffset(int i) { if ((i < 3 || bogeyCount == 0) && i != 0) return false; @@ -698,12 +810,20 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable } @Override - public LazyOptional getCapability(Capability cap, Direction side) { + public @NotNull LazyOptional getCapability(@NotNull Capability cap, Direction side) { if (isItemHandlerCap(cap)) return depotBehaviour.getItemCapability(cap, side); + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); return super.getCapability(cap, side); } + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + private void applyAutoSchedule() { ItemStack stack = getAutoSchedule(); if (!AllItems.SCHEDULE.isIn(stack)) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/IScheduleInput.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/IScheduleInput.java index 4858e0974..41392f608 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/IScheduleInput.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/IScheduleInput.java @@ -25,6 +25,8 @@ public interface IScheduleInput { public abstract CompoundTag getData(); + public abstract void setData(CompoundTag data); + public default int slotsTargeted() { return 0; } @@ -40,7 +42,7 @@ public interface IScheduleInput { } public default void setItem(int slot, ItemStack stack) {} - + public default ItemStack getItem(int slot) { return ItemStack.EMPTY; } @@ -58,4 +60,4 @@ public interface IScheduleInput { return false; } -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleDataEntry.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleDataEntry.java index 58b2eae7a..c2c7144c7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleDataEntry.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleDataEntry.java @@ -3,33 +3,39 @@ package com.simibubi.create.content.logistics.trains.management.schedule; import net.minecraft.nbt.CompoundTag; public abstract class ScheduleDataEntry implements IScheduleInput { - + protected CompoundTag data; - + public ScheduleDataEntry() { data = new CompoundTag(); } - + @Override public CompoundTag getData() { return data; } - + + @Override + public void setData(CompoundTag data) { + this.data = data; + readAdditional(data); + } + protected void writeAdditional(CompoundTag tag) {}; protected void readAdditional(CompoundTag tag) {}; - + protected T enumData(String key, Class enumClass) { T[] enumConstants = enumClass.getEnumConstants(); return enumConstants[data.getInt(key) % enumConstants.length]; } - + protected String textData(String key) { return data.getString(key); } - + protected int intData(String key) { return data.getInt(key); } - + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/FluidThresholdCondition.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/FluidThresholdCondition.java index 0c3f25f55..f9ab12a18 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/FluidThresholdCondition.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/FluidThresholdCondition.java @@ -68,7 +68,8 @@ public class FluidThresholdCondition extends CargoThresholdCondition { @Override protected void readAdditional(CompoundTag tag) { super.readAdditional(tag); - compareStack = ItemStack.of(tag.getCompound("Bucket")); + if (tag.contains("Bucket")) + compareStack = ItemStack.of(tag.getCompound("Bucket")); } @Override @@ -139,4 +140,4 @@ public class FluidThresholdCondition extends CargoThresholdCondition { Math.max(0, getThreshold() + offset), Lang.translateDirect("schedule.condition.threshold.buckets")); } -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ItemThresholdCondition.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ItemThresholdCondition.java index 78905d201..81122ad73 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ItemThresholdCondition.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ItemThresholdCondition.java @@ -69,7 +69,8 @@ public class ItemThresholdCondition extends CargoThresholdCondition { @Override protected void readAdditional(CompoundTag tag) { super.readAdditional(tag); - stack = ItemStack.of(tag.getCompound("Item")); + if (tag.contains("Item")) + stack = ItemStack.of(tag.getCompound("Item")); } @Override @@ -131,4 +132,4 @@ public class ItemThresholdCondition extends CargoThresholdCondition { Math.max(0, getThreshold() + offset), Lang.translateDirect("schedule.condition.threshold." + (inStacks() ? "stacks" : "items"))); } -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/RedstoneLinkCondition.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/RedstoneLinkCondition.java index 9bb8f4190..896c9a23f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/RedstoneLinkCondition.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/RedstoneLinkCondition.java @@ -107,7 +107,8 @@ public class RedstoneLinkCondition extends ScheduleWaitCondition { @Override protected void readAdditional(CompoundTag tag) { - freq = Couple.deserializeEach(tag.getList("Frequency", Tag.TAG_COMPOUND), c -> Frequency.of(ItemStack.of(c))); + if (tag.contains("Frequency")) + freq = Couple.deserializeEach(tag.getList("Frequency", Tag.TAG_COMPOUND), c -> Frequency.of(ItemStack.of(c))); } @Override @@ -118,7 +119,7 @@ public class RedstoneLinkCondition extends ScheduleWaitCondition { .titled(Lang.translateDirect("schedule.condition.redstone_link.frequency_state")), "Inverted"); } - + @Override public MutableComponent getWaitingStatus(Level level, Train train, CompoundTag tag) { return Lang.translateDirect("schedule.condition.redstone_link.status"); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduleWaitCondition.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduleWaitCondition.java index a8e307d6a..7da150cce 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduleWaitCondition.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduleWaitCondition.java @@ -16,16 +16,17 @@ import net.minecraft.world.level.Level; public abstract class ScheduleWaitCondition extends ScheduleDataEntry { public abstract boolean tickCompletion(Level level, Train train, CompoundTag context); - + protected void requestStatusToUpdate(CompoundTag context) { context.putInt("StatusVersion", context.getInt("StatusVersion") + 1); } - + public final CompoundTag write() { CompoundTag tag = new CompoundTag(); + CompoundTag dataCopy = data.copy(); + writeAdditional(dataCopy); tag.putString("Id", getId().toString()); - tag.put("Data", data.copy()); - writeAdditional(tag); + tag.put("Data", dataCopy); return tag; } @@ -43,11 +44,14 @@ public abstract class ScheduleWaitCondition extends ScheduleDataEntry { } ScheduleWaitCondition condition = supplier.get(); - condition.data = tag.getCompound("Data"); + // Left around for migration purposes. Data added in writeAdditional has moved into the "Data" tag condition.readAdditional(tag); + CompoundTag data = tag.getCompound("Data"); + condition.readAdditional(data); + condition.data = data; return condition; } public abstract MutableComponent getWaitingStatus(Level level, Train train, CompoundTag tag); -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ScheduleInstruction.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ScheduleInstruction.java index cc3554094..6e1e56354 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ScheduleInstruction.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ScheduleInstruction.java @@ -16,9 +16,10 @@ public abstract class ScheduleInstruction extends ScheduleDataEntry { public final CompoundTag write() { CompoundTag tag = new CompoundTag(); + CompoundTag dataCopy = data.copy(); + writeAdditional(dataCopy); tag.putString("Id", getId().toString()); - tag.put("Data", data.copy()); - writeAdditional(tag); + tag.put("Data", dataCopy); return tag; } @@ -36,9 +37,12 @@ public abstract class ScheduleInstruction extends ScheduleDataEntry { } ScheduleInstruction scheduleDestination = supplier.get(); - scheduleDestination.data = tag.getCompound("Data"); + // Left around for migration purposes. Data added in writeAdditional has moved into the "Data" tag scheduleDestination.readAdditional(tag); + CompoundTag data = tag.getCompound("Data"); + scheduleDestination.readAdditional(data); + scheduleDestination.data = data; return scheduleDestination; } -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java index 53f9571e8..71946bbe2 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java @@ -163,7 +163,7 @@ public enum AllGuiTextures implements ScreenElement { SPEECH_TOOLTIP_BACKGROUND("widgets", 0, 24, 8, 8), SPEECH_TOOLTIP_COLOR("widgets", 8, 24, 8, 8), - + TRAIN_HUD_SPEED_BG("widgets", 0, 190, 182, 5), TRAIN_HUD_SPEED("widgets", 0, 185, 182, 5), TRAIN_HUD_THROTTLE("widgets", 0, 195, 182, 5), @@ -175,7 +175,10 @@ public enum AllGuiTextures implements ScreenElement { TRAIN_PROMPT("widgets", 0, 230, 256, 16), // PlacementIndicator - PLACEMENT_INDICATOR_SHEET("placement_indicator", 0, 0, 16, 256); + PLACEMENT_INDICATOR_SHEET("placement_indicator", 0, 0, 16, 256), + + // ComputerCraft + COMPUTER("computer", 200, 102); ; diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index 10c6a635f..634fd8ec0 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -8,6 +8,7 @@ import java.util.function.Function; import java.util.function.Supplier; import com.simibubi.create.Create; +import com.simibubi.create.compat.computercraft.AttachedComputerPacket; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionBlockChangedPacket; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionDisassemblyPacket; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRelocationPacket; @@ -184,7 +185,7 @@ public enum AllPackets { S_TRAIN_PROMPT(TrainPromptPacket.class, TrainPromptPacket::new, PLAY_TO_CLIENT), CONTRAPTION_RELOCATION(ContraptionRelocationPacket.class, ContraptionRelocationPacket::new, PLAY_TO_CLIENT), TRACK_GRAPH_ROLL_CALL(TrackGraphRollCallPacket.class, TrackGraphRollCallPacket::new, PLAY_TO_CLIENT), - + ATTACHED_COMPUTER(AttachedComputerPacket.class, AttachedComputerPacket::new, PLAY_TO_CLIENT), ; public static final ResourceLocation CHANNEL_NAME = Create.asResource("main"); diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java index ed44673e8..5abcce458 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java @@ -3,6 +3,7 @@ package com.simibubi.create.foundation.ponder.content; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.Create; +import com.simibubi.create.compat.Mods; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.ponder.PonderRegistrationHelper; import com.simibubi.create.foundation.ponder.PonderRegistry; @@ -20,8 +21,11 @@ import com.simibubi.create.foundation.ponder.content.trains.TrainScenes; import com.simibubi.create.foundation.ponder.content.trains.TrainSignalScenes; import com.simibubi.create.foundation.ponder.content.trains.TrainStationScenes; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraftforge.registries.ForgeRegistries; public class PonderIndex { @@ -548,6 +552,12 @@ public class PonderIndex { .add(Blocks.COMMAND_BLOCK) .add(Blocks.TARGET); + Mods.COMPUTERCRAFT.executeIfInstalled(() -> () -> { + Block computer = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(Mods.COMPUTERCRAFT.asId(), "computer_advanced")); + if (computer != null) + PonderRegistry.TAGS.forTag(PonderTag.DISPLAY_SOURCES).add(computer); + }); + PonderRegistry.TAGS.forTag(PonderTag.DISPLAY_TARGETS) .add(AllBlocks.ORANGE_NIXIE_TUBE) .add(AllBlocks.DISPLAY_BOARD) diff --git a/src/main/java/com/simibubi/create/foundation/utility/StringHelper.java b/src/main/java/com/simibubi/create/foundation/utility/StringHelper.java new file mode 100644 index 000000000..78521b4e5 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/StringHelper.java @@ -0,0 +1,46 @@ +package com.simibubi.create.foundation.utility; + +import java.util.Locale; + +public class StringHelper { + + public static String snakeCaseToCamelCase(String text) { + StringBuilder builder = new StringBuilder(); + builder.append(text.substring(0, 1).toUpperCase(Locale.ROOT)); + + for (int i = 1; i < text.length(); i++) { + int j = text.indexOf('_', i); + + if (j == -1) { + builder.append(text.substring(i)); + break; + } + + builder.append(text.substring(i, j).toLowerCase(Locale.ROOT)); + builder.append(text.substring(j + 1, j + 2).toUpperCase(Locale.ROOT)); + + i = j + 1; + } + + return builder.toString(); + } + + public static String camelCaseToSnakeCase(String text) { + StringBuilder builder = new StringBuilder(); + + for (char c : text.toCharArray()) { + if (Character.isUpperCase(c)) { + builder.append('_'); + builder.append(Character.toLowerCase(c)); + } else { + builder.append(c); + } + } + + if (builder.length() > 0 && builder.charAt(0) == '_') + builder.deleteCharAt(0); + + return builder.toString(); + } + +} diff --git a/src/main/resources/assets/create/textures/gui/computer.png b/src/main/resources/assets/create/textures/gui/computer.png new file mode 100644 index 0000000000000000000000000000000000000000..293bedad784f171501f1983784abcf863ba62ae0 GIT binary patch literal 1016 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911MRQ8&P5D>38$lZxy-8q?;K+f|3pAc6d z{r~^}M~@!exN-BwjT_gmUq5r^%%_97$BrG_v17-QB}*1BUc7&n%Y+FNy1ToZnwlyq zDoRR9^7Hf4($d1i!$U(u9UL6uj2JB~En^KCVhtE#fJmRg+}u1`pCMY0Aqt3e8KQI; zB6S!%^~EE#86tp4iy<6{G#LyG3|zED_4M@YHH7Wdg>BS@t<{9ARD~>6fJo3nS`oN+#hRG+_7|fh9KU{vh z{rl>?&(*(cqIT_^>9>47cX@fdSN#5|`~GX(z5ie5kJg`gfA9agr6nGCn5oH||AXF^ zC?=l6QvIwR`~`)Ed}s6zK4F;q=g%+yE5|E&pX)Pisq1T&H)YNEE5mNDbATy}bHn>| z`NeAD9|~H&iBxQ6jj^w>vEo0gx8UvLcbgcvH^5Lv7322M$ZW=2kq2_WI<1qk{T7wY zy&}$|nh|IUCYlxHP!@VMs-aA*z+{hF2BTO47+tu+)EBUr+rn*k_)B}&zspy!UJ+XG zwOHm4(4G~_2cEWX(0g5RI-uYs9d3@9zXff`dYdd7&r}=IWDX{bt>Io(;;l) z^z(gg=_gs8*d^x8{Tjr5gwNm&kYeGV5T}sT@F@I2al;cPM&^?3OgzjYh4EYm z#!bDS*E27<=c5tSkW>5bIm1cwU@p;w@A?P7%=SFW7jXFO7AN)!-+aKopOC}t+<| Date: Fri, 12 May 2023 15:14:08 +0200 Subject: [PATCH 19/22] Fivepointone-ify Again --- .../resources/assets/create/lang/en_us.json | 3 + .../data/create/tags/blocks/safe_nbt.json | 2 - .../AbstractComputerBehaviour.java | 10 +-- .../computercraft/AttachedComputerPacket.java | 12 ++-- .../computercraft/ComputerCraftProxy.java | 12 ++-- .../FallbackComputerBehaviour.java | 4 +- .../implementation/ComputerBehaviour.java | 30 ++++----- .../peripherals/DisplayLinkPeripheral.java | 6 +- .../SequencedGearshiftPeripheral.java | 6 +- .../SpeedControllerPeripheral.java | 8 +-- .../peripherals/SpeedGaugePeripheral.java | 6 +- .../peripherals/StationPeripheral.java | 8 +-- .../peripherals/StressGaugePeripheral.java | 6 +- .../peripherals/SyncedPeripheral.java | 6 +- .../station/AbstractStationScreen.java | 8 +-- .../simibubi/create/events/ClientEvents.java | 4 +- .../infrastructure/CreateGameTestHelper.java | 62 +++++++++---------- .../create/gametest/tests/TestFluids.java | 12 ++-- .../create/gametest/tests/TestItems.java | 28 ++++----- .../create/gametest/tests/TestMisc.java | 15 +++-- .../assets/create/lang/default/interface.json | 4 ++ 21 files changed, 125 insertions(+), 127 deletions(-) diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 07280a38b..c46ec6649 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1809,6 +1809,7 @@ "create.display_source.redstone_power.progress_bar": "Progress Bar", "create.display_source.boiler.not_enough_space": "Not enough space ", "create.display_source.boiler.for_boiler_status": "for Boiler Status", + "create.display_source.computer_display_source": "From Computer", "create.display_target.line": "Line %1$s", "create.display_target.page": "Page %1$s", @@ -1831,6 +1832,8 @@ "create.super_glue.not_enough": "Not enough glue in inventory", "create.super_glue.success": "Applying Glue...", + "create.gui.attached_computer.controlled": "This device is being controlled by a computer", + "create.gui.attached_computer.hint": "To use device manually, disconnect all computers and modems", "create.gui.config.overlay1": "Hi :)", "create.gui.config.overlay2": "This is a sample overlay", "create.gui.config.overlay3": "Click or drag with your mouse", diff --git a/src/generated/resources/data/create/tags/blocks/safe_nbt.json b/src/generated/resources/data/create/tags/blocks/safe_nbt.json index 3c18772a3..4e678d26c 100644 --- a/src/generated/resources/data/create/tags/blocks/safe_nbt.json +++ b/src/generated/resources/data/create/tags/blocks/safe_nbt.json @@ -19,10 +19,8 @@ "create:andesite_belt_funnel", "create:brass_funnel", "create:brass_belt_funnel", - "create:creative_crate", "create:redstone_link", "create:analog_lever", - "create:placard", "create:pulse_repeater", "create:pulse_extender", "create:clipboard", diff --git a/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java b/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java index a8620450b..ef2777d1a 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java @@ -1,20 +1,20 @@ package com.simibubi.create.compat.computercraft; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; import net.minecraft.nbt.CompoundTag; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; -public class AbstractComputerBehaviour extends TileEntityBehaviour { +public class AbstractComputerBehaviour extends BlockEntityBehaviour { public static final BehaviourType TYPE = new BehaviourType<>(); boolean hasAttachedComputer; - public AbstractComputerBehaviour(SmartTileEntity te) { + public AbstractComputerBehaviour(SmartBlockEntity te) { super(te); this.hasAttachedComputer = false; } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java b/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java index 3181217fe..0b40217ab 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java @@ -1,13 +1,13 @@ package com.simibubi.create.compat.computercraft; -import com.simibubi.create.foundation.networking.TileEntityDataPacket; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.SyncedTileEntity; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.SyncedBlockEntity; +import com.simibubi.create.foundation.networking.BlockEntityDataPacket; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; -public class AttachedComputerPacket extends TileEntityDataPacket { +public class AttachedComputerPacket extends BlockEntityDataPacket { private final boolean hasAttachedComputer; @@ -27,8 +27,8 @@ public class AttachedComputerPacket extends TileEntityDataPacket fallbackFactory; - private static Function computerFactory; + private static Function fallbackFactory; + private static Function computerFactory; - public static AbstractComputerBehaviour behaviour(SmartTileEntity ste) { + public static AbstractComputerBehaviour behaviour(SmartBlockEntity sbe) { if (computerFactory == null) - return fallbackFactory.apply(ste); - return computerFactory.apply(ste); + return fallbackFactory.apply(sbe); + return computerFactory.apply(sbe); } } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java b/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java index 2e1a3da77..7e58c270d 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java @@ -1,10 +1,10 @@ package com.simibubi.create.compat.computercraft; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; public class FallbackComputerBehaviour extends AbstractComputerBehaviour { - public FallbackComputerBehaviour(SmartTileEntity te) { + public FallbackComputerBehaviour(SmartBlockEntity te) { super(te); } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java index dfe1f504d..43c8a7211 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java @@ -7,13 +7,13 @@ import com.simibubi.create.compat.computercraft.implementation.peripherals.Speed import com.simibubi.create.compat.computercraft.implementation.peripherals.SpeedGaugePeripheral; import com.simibubi.create.compat.computercraft.implementation.peripherals.StationPeripheral; import com.simibubi.create.compat.computercraft.implementation.peripherals.StressGaugePeripheral; -import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity; -import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftTileEntity; -import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; -import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; -import com.simibubi.create.content.logistics.block.display.DisplayLinkTileEntity; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlockEntity; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftBlockEntity; +import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeBlockEntity; +import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeBlockEntity; +import com.simibubi.create.content.logistics.block.display.DisplayLinkBlockEntity; +import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlockEntity; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraftforge.common.capabilities.Capability; @@ -30,23 +30,23 @@ public class ComputerBehaviour extends AbstractComputerBehaviour { LazyOptional peripheral; NonNullSupplier peripheralSupplier; - public ComputerBehaviour(SmartTileEntity te) { + public ComputerBehaviour(SmartBlockEntity te) { super(te); this.peripheralSupplier = getPeripheralFor(te); } - public static NonNullSupplier getPeripheralFor(SmartTileEntity te) { - if (te instanceof SpeedControllerTileEntity scte) + public static NonNullSupplier getPeripheralFor(SmartBlockEntity te) { + if (te instanceof SpeedControllerBlockEntity scte) return () -> new SpeedControllerPeripheral(scte, scte.targetSpeed); - if (te instanceof DisplayLinkTileEntity dlte) + if (te instanceof DisplayLinkBlockEntity dlte) return () -> new DisplayLinkPeripheral(dlte); - if (te instanceof SequencedGearshiftTileEntity sgte) + if (te instanceof SequencedGearshiftBlockEntity sgte) return () -> new SequencedGearshiftPeripheral(sgte); - if (te instanceof SpeedGaugeTileEntity sgte) + if (te instanceof SpeedGaugeBlockEntity sgte) return () -> new SpeedGaugePeripheral(sgte); - if (te instanceof StressGaugeTileEntity sgte) + if (te instanceof StressGaugeBlockEntity sgte) return () -> new StressGaugePeripheral(sgte); - if (te instanceof StationTileEntity ste) + if (te instanceof StationBlockEntity ste) return () -> new StationPeripheral(ste); throw new IllegalArgumentException("No peripheral available for " + te.getType() diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java index 0e9275227..cff49977e 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java @@ -4,8 +4,8 @@ import java.util.concurrent.atomic.AtomicInteger; import org.jetbrains.annotations.NotNull; +import com.simibubi.create.content.logistics.block.display.DisplayLinkBlockEntity; import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.DisplayLinkTileEntity; import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; import dan200.computercraft.api.lua.LuaFunction; @@ -13,13 +13,13 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; -public class DisplayLinkPeripheral extends SyncedPeripheral { +public class DisplayLinkPeripheral extends SyncedPeripheral { public static final String TAG_KEY = "ComputerSourceList"; private final AtomicInteger cursorX = new AtomicInteger(); private final AtomicInteger cursorY = new AtomicInteger(); - public DisplayLinkPeripheral(DisplayLinkTileEntity tile) { + public DisplayLinkPeripheral(DisplayLinkBlockEntity tile) { super(tile); } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java index 8addb181e..26574bd7f 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java @@ -4,16 +4,16 @@ import org.jetbrains.annotations.NotNull; import com.simibubi.create.content.contraptions.relays.advanced.sequencer.Instruction; import com.simibubi.create.content.contraptions.relays.advanced.sequencer.InstructionSpeedModifiers; -import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftTileEntity; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftBlockEntity; import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencerInstructions; import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; -public class SequencedGearshiftPeripheral extends SyncedPeripheral { +public class SequencedGearshiftPeripheral extends SyncedPeripheral { - public SequencedGearshiftPeripheral(SequencedGearshiftTileEntity tile) { + public SequencedGearshiftPeripheral(SequencedGearshiftBlockEntity tile) { super(tile); } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java index 2aba811f0..a10f594f7 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java @@ -2,16 +2,16 @@ package com.simibubi.create.compat.computercraft.implementation.peripherals; import org.jetbrains.annotations.NotNull; -import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; +import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour; import dan200.computercraft.api.lua.LuaFunction; -public class SpeedControllerPeripheral extends SyncedPeripheral { +public class SpeedControllerPeripheral extends SyncedPeripheral { private final ScrollValueBehaviour targetSpeed; - public SpeedControllerPeripheral(SpeedControllerTileEntity tile, ScrollValueBehaviour targetSpeed) { + public SpeedControllerPeripheral(SpeedControllerBlockEntity tile, ScrollValueBehaviour targetSpeed) { super(tile); this.targetSpeed = targetSpeed; } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java index a13b02cd5..a2ff521c5 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java @@ -2,13 +2,13 @@ package com.simibubi.create.compat.computercraft.implementation.peripherals; import org.jetbrains.annotations.NotNull; -import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; +import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeBlockEntity; import dan200.computercraft.api.lua.LuaFunction; -public class SpeedGaugePeripheral extends SyncedPeripheral { +public class SpeedGaugePeripheral extends SyncedPeripheral { - public SpeedGaugePeripheral(SpeedGaugeTileEntity tile) { + public SpeedGaugePeripheral(SpeedGaugeBlockEntity tile) { super(tile); } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java index 3de8e979b..552304fb8 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java @@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; import com.simibubi.create.compat.computercraft.implementation.CreateLuaTable; import com.simibubi.create.content.logistics.trains.entity.Train; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; +import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlockEntity; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.TrainEditPacket; import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; import com.simibubi.create.foundation.networking.AllPackets; @@ -30,9 +30,9 @@ import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraftforge.network.PacketDistributor; -public class StationPeripheral extends SyncedPeripheral { +public class StationPeripheral extends SyncedPeripheral { - public StationPeripheral(StationTileEntity tile) { + public StationPeripheral(StationBlockEntity tile) { super(tile); } @@ -129,7 +129,7 @@ public class StationPeripheral extends SyncedPeripheral { public final void setTrainName(String name) throws LuaException { Train train = getTrainOrThrow(); train.name = Components.literal(name); - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainEditPacket.TrainEditReturnPacket(train.id, name, train.icon.getId())); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainEditPacket.TrainEditReturnPacket(train.id, name, train.icon.getId())); } @LuaFunction diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java index b712bd6da..480ad12ab 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java @@ -2,13 +2,13 @@ package com.simibubi.create.compat.computercraft.implementation.peripherals; import org.jetbrains.annotations.NotNull; -import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; +import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeBlockEntity; import dan200.computercraft.api.lua.LuaFunction; -public class StressGaugePeripheral extends SyncedPeripheral { +public class StressGaugePeripheral extends SyncedPeripheral { - public StressGaugePeripheral(StressGaugeTileEntity tile) { + public StressGaugePeripheral(StressGaugeBlockEntity tile) { super(tile); } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java index a6371063d..59b378619 100644 --- a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java @@ -7,14 +7,14 @@ import org.jetbrains.annotations.Nullable; import com.simibubi.create.compat.computercraft.AttachedComputerPacket; import com.simibubi.create.compat.computercraft.implementation.ComputerBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraftforge.network.PacketDistributor; -public abstract class SyncedPeripheral implements IPeripheral { +public abstract class SyncedPeripheral implements IPeripheral { protected final T tile; private final AtomicInteger computers = new AtomicInteger(); @@ -39,7 +39,7 @@ public abstract class SyncedPeripheral implements IPe boolean hasAttachedComputer = computers.get() > 0; tile.getBehaviour(ComputerBehaviour.TYPE).setHasAttachedComputer(hasAttachedComputer); - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new AttachedComputerPacket(tile.getBlockPos(), hasAttachedComputer)); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new AttachedComputerPacket(tile.getBlockPos(), hasAttachedComputer)); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java index dea096157..2db8e7cdc 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java @@ -41,9 +41,9 @@ public abstract class AbstractStationScreen extends AbstractSimiScreen { @Override protected void init() { - if (te.computerBehaviour.hasAttachedComputer()) + if (blockEntity.computerBehaviour.hasAttachedComputer()) minecraft.setScreen(new ComputerScreen(title, () -> Components.literal(station.name), - this::renderAdditional, this, te.computerBehaviour::hasAttachedComputer)); + this::renderAdditional, this, blockEntity.computerBehaviour::hasAttachedComputer)); setWindowSize(background.width, background.height); super.init(); @@ -81,9 +81,9 @@ public abstract class AbstractStationScreen extends AbstractSimiScreen { public void tick() { super.tick(); - if (te.computerBehaviour.hasAttachedComputer()) + if (blockEntity.computerBehaviour.hasAttachedComputer()) minecraft.setScreen(new ComputerScreen(title, () -> Components.literal(station.name), - this::renderAdditional, this, te.computerBehaviour::hasAttachedComputer)); + this::renderAdditional, this, blockEntity.computerBehaviour::hasAttachedComputer)); } @Override diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index a2baade8a..a98047339 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -295,14 +295,14 @@ public class ClientEvents { if (AllFluids.CHOCOLATE.get() .isSame(fluid)) { - event.scaleFarPlaneDistance(1f / 32f * AllConfigs.CLIENT.chocolateTransparencyMultiplier.getF()); + event.scaleFarPlaneDistance(1f / 32f * AllConfigs.client().chocolateTransparencyMultiplier.getF()); event.setCanceled(true); return; } if (AllFluids.HONEY.get() .isSame(fluid)) { - event.scaleFarPlaneDistance(1f / 8f * AllConfigs.CLIENT.honeyTransparencyMultiplier.getF()); + event.scaleFarPlaneDistance(1f / 8f * AllConfigs.client().honeyTransparencyMultiplier.getF()); event.setCanceled(true); return; } diff --git a/src/main/java/com/simibubi/create/gametest/infrastructure/CreateGameTestHelper.java b/src/main/java/com/simibubi/create/gametest/infrastructure/CreateGameTestHelper.java index 51b86f548..9a3a27162 100644 --- a/src/main/java/com/simibubi/create/gametest/infrastructure/CreateGameTestHelper.java +++ b/src/main/java/com/simibubi/create/gametest/infrastructure/CreateGameTestHelper.java @@ -4,34 +4,23 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelBlockEntity.SelectionMode; +import com.simibubi.create.content.logistics.block.redstone.NixieTubeBlockEntity; +import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour; +import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.mixin.accessor.GameTestHelperAccessor; +import com.simibubi.create.foundation.utility.RegisteredObjects; import it.unimi.dsi.fastutil.objects.Object2LongArrayMap; import it.unimi.dsi.fastutil.objects.Object2LongMap; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.LeverBlock; -import net.minecraftforge.fluids.FluidStack; - -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemHandlerHelper; - -import org.jetbrains.annotations.Contract; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity.SelectionMode; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; -import com.simibubi.create.foundation.utility.RegisteredObjects; - import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Registry; @@ -44,14 +33,21 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LeverBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.phys.Vec3; - -import org.jetbrains.annotations.NotNull; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; /** * A helper class expanding the functionality of {@link GameTestHelper}. @@ -91,7 +87,7 @@ public class CreateGameTestHelper extends GameTestHelper { } public void assertNixiePower(BlockPos pos, int strength) { - NixieTubeTileEntity nixie = getBlockEntity(AllTileEntities.NIXIE_TUBE.get(), pos); + NixieTubeBlockEntity nixie = getBlockEntity(AllBlockEntityTypes.NIXIE_TUBE.get(), pos); int actualStrength = nixie.getRedstoneStrength(); if (actualStrength != strength) fail("Expected nixie tube at %s to have power of %s, got %s".formatted(pos, strength, actualStrength)); @@ -146,20 +142,20 @@ public class CreateGameTestHelper extends GameTestHelper { } /** - * Given any segment of an {@link IMultiTileContainer}, get the controller for it. + * Given any segment of an {@link IMultiBlockEntityContainer}, get the controller for it. */ - public T getControllerBlockEntity(BlockEntityType type, BlockPos anySegment) { - T be = getBlockEntity(type, anySegment).getControllerTE(); + public T getControllerBlockEntity(BlockEntityType type, BlockPos anySegment) { + T be = getBlockEntity(type, anySegment).getControllerBE(); if (be == null) fail("Could not get block entity controller with type [%s] from pos [%s]".formatted(RegisteredObjects.getKeyOrThrow(type), anySegment)); return be; } /** - * Get the expected {@link TileEntityBehaviour} from the given position, failing if not present. + * Get the expected {@link BlockEntityBehaviour} from the given position, failing if not present. */ - public T getBehavior(BlockPos pos, BehaviourType type) { - T behavior = TileEntityBehaviour.get(getLevel(), absolutePos(pos), type); + public T getBehavior(BlockPos pos, BehaviourType type) { + T behavior = BlockEntityBehaviour.get(getLevel(), absolutePos(pos), type); if (behavior == null) fail("Behavior at " + pos + " missing, expected " + type.getName()); return behavior; diff --git a/src/main/java/com/simibubi/create/gametest/tests/TestFluids.java b/src/main/java/com/simibubi/create/gametest/tests/TestFluids.java index 0624e29d5..8e4d06f06 100644 --- a/src/main/java/com/simibubi/create/gametest/tests/TestFluids.java +++ b/src/main/java/com/simibubi/create/gametest/tests/TestFluids.java @@ -1,12 +1,10 @@ package com.simibubi.create.gametest.tests; -import com.simibubi.create.AllTileEntities; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyFluidHandler; -import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; -import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; - +import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeBlockEntity; +import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeBlockEntity; import com.simibubi.create.gametest.infrastructure.CreateGameTestHelper; - import com.simibubi.create.gametest.infrastructure.GameTestGroup; import net.minecraft.core.BlockPos; @@ -95,8 +93,8 @@ public class TestFluids { BlockPos stressometer = new BlockPos(5, 2, 5); BlockPos speedometer = new BlockPos(4, 2, 5); helper.succeedWhen(() -> { - StressGaugeTileEntity stress = helper.getBlockEntity(AllTileEntities.STRESSOMETER.get(), stressometer); - SpeedGaugeTileEntity speed = helper.getBlockEntity(AllTileEntities.SPEEDOMETER.get(), speedometer); + StressGaugeBlockEntity stress = helper.getBlockEntity(AllBlockEntityTypes.STRESSOMETER.get(), stressometer); + SpeedGaugeBlockEntity speed = helper.getBlockEntity(AllBlockEntityTypes.SPEEDOMETER.get(), speedometer); float capacity = stress.getNetworkCapacity(); helper.assertCloseEnoughTo(capacity, 2048); float rotationSpeed = Mth.abs(speed.getSpeed()); diff --git a/src/main/java/com/simibubi/create/gametest/tests/TestItems.java b/src/main/java/com/simibubi/create/gametest/tests/TestItems.java index 43dc317e3..fe41664e7 100644 --- a/src/main/java/com/simibubi/create/gametest/tests/TestItems.java +++ b/src/main/java/com/simibubi/create/gametest/tests/TestItems.java @@ -5,18 +5,18 @@ import java.util.Locale; import java.util.Map; import java.util.stream.Stream; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity.SelectionMode; -import com.simibubi.create.content.logistics.block.depot.DepotTileEntity; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; +import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelBlockEntity.SelectionMode; +import com.simibubi.create.content.logistics.block.depot.DepotBlockEntity; +import com.simibubi.create.content.logistics.block.redstone.NixieTubeBlockEntity; +import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayBlockEntity; import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayLayout; import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; +import com.simibubi.create.foundation.utility.Components; import com.simibubi.create.gametest.infrastructure.CreateGameTestHelper; import com.simibubi.create.gametest.infrastructure.GameTestGroup; -import com.simibubi.create.foundation.utility.Components; import it.unimi.dsi.fastutil.objects.Object2LongMap; import net.minecraft.Util; @@ -53,9 +53,9 @@ public class TestItems { public static void armPurgatory(CreateGameTestHelper helper) { BlockPos lever = new BlockPos(2, 3, 2); BlockPos depot1Pos = new BlockPos(3, 2, 1); - DepotTileEntity depot1 = helper.getBlockEntity(AllTileEntities.DEPOT.get(), depot1Pos); + DepotBlockEntity depot1 = helper.getBlockEntity(AllBlockEntityTypes.DEPOT.get(), depot1Pos); BlockPos depot2Pos = new BlockPos(1, 2, 1); - DepotTileEntity depot2 = helper.getBlockEntity(AllTileEntities.DEPOT.get(), depot2Pos); + DepotBlockEntity depot2 = helper.getBlockEntity(AllBlockEntityTypes.DEPOT.get(), depot2Pos); helper.pullLever(lever); helper.succeedWhen(() -> { helper.assertSecondsPassed(5); @@ -234,12 +234,12 @@ public class TestItems { BlockPos chest = new BlockPos(3, 2, 1); long totalChestItems = helper.getTotalItems(chest); BlockPos chestNixiePos = new BlockPos(2, 3, 1); - NixieTubeTileEntity chestNixie = helper.getBlockEntity(AllTileEntities.NIXIE_TUBE.get(), chestNixiePos); + NixieTubeBlockEntity chestNixie = helper.getBlockEntity(AllBlockEntityTypes.NIXIE_TUBE.get(), chestNixiePos); BlockPos doubleChest = new BlockPos(2, 2, 3); long totalDoubleChestItems = helper.getTotalItems(doubleChest); BlockPos doubleChestNixiePos = new BlockPos(1, 3, 3); - NixieTubeTileEntity doubleChestNixie = helper.getBlockEntity(AllTileEntities.NIXIE_TUBE.get(), doubleChestNixiePos); + NixieTubeBlockEntity doubleChestNixie = helper.getBlockEntity(AllBlockEntityTypes.NIXIE_TUBE.get(), doubleChestNixiePos); helper.succeedWhen(() -> { String chestNixieText = chestNixie.getFullText().getString(); @@ -256,16 +256,16 @@ public class TestItems { @GameTest(template = "depot_display", timeoutTicks = CreateGameTestHelper.TEN_SECONDS) public static void depotDisplay(CreateGameTestHelper helper) { BlockPos displayPos = new BlockPos(5, 3, 1); - List depots = Stream.of( + List depots = Stream.of( new BlockPos(2, 2, 1), new BlockPos(1, 2, 1) - ).map(pos -> helper.getBlockEntity(AllTileEntities.DEPOT.get(), pos)).toList(); + ).map(pos -> helper.getBlockEntity(AllBlockEntityTypes.DEPOT.get(), pos)).toList(); List levers = List.of( new BlockPos(2, 5, 0), new BlockPos(1, 5, 0) ); levers.forEach(helper::pullLever); - FlapDisplayTileEntity display = helper.getBlockEntity(AllTileEntities.FLAP_DISPLAY.get(), displayPos).getController(); + FlapDisplayBlockEntity display = helper.getBlockEntity(AllBlockEntityTypes.FLAP_DISPLAY.get(), displayPos).getController(); helper.succeedWhen(() -> { for (int i = 0; i < 2; i++) { FlapDisplayLayout line = display.getLines().get(i); @@ -273,7 +273,7 @@ public class TestItems { line.getSections().stream().map(FlapDisplaySection::getText).forEach(textComponent::append); String text = textComponent.getString().toLowerCase(Locale.ROOT).trim(); - DepotTileEntity depot = depots.get(i); + DepotBlockEntity depot = depots.get(i); ItemStack item = depot.getHeldItem(); String name = Registry.ITEM.getKey(item.getItem()).getPath(); diff --git a/src/main/java/com/simibubi/create/gametest/tests/TestMisc.java b/src/main/java/com/simibubi/create/gametest/tests/TestMisc.java index 829bd3d4b..cfd3209c9 100644 --- a/src/main/java/com/simibubi/create/gametest/tests/TestMisc.java +++ b/src/main/java/com/simibubi/create/gametest/tests/TestMisc.java @@ -1,11 +1,12 @@ package com.simibubi.create.gametest.tests; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.schematics.SchematicExport; -import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; -import com.simibubi.create.content.schematics.block.SchematicannonTileEntity.State; -import com.simibubi.create.content.schematics.item.SchematicItem; +import static com.simibubi.create.gametest.infrastructure.CreateGameTestHelper.FIFTEEN_SECONDS; +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.schematics.SchematicExport; +import com.simibubi.create.content.schematics.block.SchematicannonBlockEntity; +import com.simibubi.create.content.schematics.block.SchematicannonBlockEntity.State; +import com.simibubi.create.content.schematics.item.SchematicItem; import com.simibubi.create.gametest.infrastructure.CreateGameTestHelper; import com.simibubi.create.gametest.infrastructure.GameTestGroup; @@ -20,8 +21,6 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Blocks; -import static com.simibubi.create.gametest.infrastructure.CreateGameTestHelper.FIFTEEN_SECONDS; - @GameTestGroup(path = "misc") public class TestMisc { @GameTest(template = "schematicannon", timeoutTicks = FIFTEEN_SECONDS) @@ -41,7 +40,7 @@ public class TestMisc { schematic.getOrCreateTag().put("Anchor", NbtUtils.writeBlockPos(anchor)); // setup cannon BlockPos cannonPos = new BlockPos(3, 2, 6); - SchematicannonTileEntity cannon = helper.getBlockEntity(AllTileEntities.SCHEMATICANNON.get(), cannonPos); + SchematicannonBlockEntity cannon = helper.getBlockEntity(AllBlockEntityTypes.SCHEMATICANNON.get(), cannonPos); cannon.inventory.setStackInSlot(0, schematic); // run cannon.state = State.RUNNING; diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index de2d84281..db0568ce7 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -963,6 +963,7 @@ "create.display_source.redstone_power.progress_bar": "Progress Bar", "create.display_source.boiler.not_enough_space": "Not enough space ", "create.display_source.boiler.for_boiler_status": "for Boiler Status", + "create.display_source.computer_display_source": "From Computer", "create.display_target.line": "Line %1$s", "create.display_target.page": "Page %1$s", @@ -985,6 +986,9 @@ "create.super_glue.not_enough": "Not enough glue in inventory", "create.super_glue.success": "Applying Glue...", + "create.gui.attached_computer.controlled": "This device is being controlled by a computer", + "create.gui.attached_computer.hint": "To use device manually, disconnect all computers and modems", + "create.gui.config.overlay1": "Hi :)", "create.gui.config.overlay2": "This is a sample overlay", "create.gui.config.overlay3": "Click or drag with your mouse", From aa102dfabd8af4e4c5694354fad475b1c32b8394 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Fri, 12 May 2023 10:55:03 -0700 Subject: [PATCH 20/22] Filtering for filters - Allow filtering for filters when filter is empty - Refine waterwheel model generation code --- .../waterwheel/WaterWheelInstance.java | 1 - .../waterwheel/WaterWheelRenderer.java | 64 +++++++++++-------- .../logistics/item/filter/FilterItem.java | 34 ++++++++-- .../logistics/item/filter/ItemAttribute.java | 2 + 4 files changed, 67 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelInstance.java index f125d09c2..8fac23bb8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelInstance.java @@ -42,7 +42,6 @@ public class WaterWheelInstance extends CutoutR return getRotatingMaterial().model(key, () -> { BakedModel model = WaterWheelRenderer.generateModel(key); BlockState state = key.state(); - // TODO waterwheels Direction dir; if (key.large()) { dir = Direction.fromAxisAndDirection(state.getValue(LargeWaterWheelBlock.AXIS), AxisDirection.POSITIVE); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelRenderer.java index f93835d60..2c8c1405c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelRenderer.java @@ -5,7 +5,6 @@ import java.util.Map; import java.util.Optional; import java.util.Random; -import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.StitchedSprite; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllPartialModels; @@ -31,6 +30,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.registries.ForgeRegistries; public class WaterWheelRenderer extends KineticBlockEntityRenderer { @@ -40,6 +40,8 @@ public class WaterWheelRenderer extends Kinetic public static final StitchedSprite OAK_LOG_TEMPLATE = new StitchedSprite(new ResourceLocation("block/oak_log")); public static final StitchedSprite OAK_LOG_TOP_TEMPLATE = new StitchedSprite(new ResourceLocation("block/oak_log_top")); + private static final String[] LOG_SUFFIXES = new String[] { "_log", "_stem" }; + protected final boolean large; public WaterWheelRenderer(Context context, boolean large) { @@ -59,9 +61,8 @@ public class WaterWheelRenderer extends Kinetic protected SuperByteBuffer getRotatedModel(T be, BlockState state) { WaterWheelModelKey key = new WaterWheelModelKey(large, state, be.material); return CreateClient.BUFFER_CACHE.get(WATER_WHEEL, key, () -> { - BakedModel model = WaterWheelRenderer.generateModel(key); + BakedModel model = generateModel(key); BlockState state1 = key.state(); - // TODO waterwheels Direction dir; if (key.large()) { dir = Direction.fromAxisAndDirection(state1.getValue(LargeWaterWheelBlock.AXIS), AxisDirection.POSITIVE); @@ -73,25 +74,24 @@ public class WaterWheelRenderer extends Kinetic }); } - public static PartialModel getTemplateModel(boolean large, boolean extension) { - if (large) { + public static BakedModel generateModel(WaterWheelModelKey key) { + BakedModel template; + if (key.large()) { + boolean extension = key.state() + .getValue(LargeWaterWheelBlock.EXTENSION); if (extension) { - return AllPartialModels.LARGE_WATER_WHEEL_EXTENSION; + template = AllPartialModels.LARGE_WATER_WHEEL_EXTENSION.get(); } else { - return AllPartialModels.LARGE_WATER_WHEEL; + template = AllPartialModels.LARGE_WATER_WHEEL.get(); } } else { - return AllPartialModels.WATER_WHEEL; + template = AllPartialModels.WATER_WHEEL.get(); } + + return generateModel(template, key.material()); } - public static BakedModel generateModel(WaterWheelModelKey key) { - boolean extension = key.state() - .getOptionalValue(LargeWaterWheelBlock.EXTENSION) - .orElse(false); - BakedModel template = getTemplateModel(key.large(), extension).get(); - - BlockState planksBlockState = key.material(); + public static BakedModel generateModel(BakedModel template, BlockState planksBlockState) { Block planksBlock = planksBlockState.getBlock(); ResourceLocation id = RegisteredObjects.getKeyOrThrow(planksBlock); String path = id.getPath(); @@ -103,7 +103,7 @@ public class WaterWheelRenderer extends Kinetic Map map = new Reference2ReferenceOpenHashMap<>(); map.put(OAK_PLANKS_TEMPLATE.get(), getSpriteOnSide(planksBlockState, Direction.UP)); - map.put(OAK_LOG_TEMPLATE.get(), getSpriteOnSide(logBlockState, Direction.NORTH)); + map.put(OAK_LOG_TEMPLATE.get(), getSpriteOnSide(logBlockState, Direction.SOUTH)); map.put(OAK_LOG_TOP_TEMPLATE.get(), getSpriteOnSide(logBlockState, Direction.UP)); return BakedModelHelper.generateModel(template, map::get); @@ -113,7 +113,7 @@ public class WaterWheelRenderer extends Kinetic } private static BlockState getLogBlockState(String namespace, String wood) { - for (String suffix : new String[] { "_log", "_stem" }) { + for (String suffix : LOG_SUFFIXES) { Optional state = ForgeRegistries.BLOCKS.getHolder(new ResourceLocation(namespace, wood + suffix)) .map(Holder::value) @@ -124,18 +124,28 @@ public class WaterWheelRenderer extends Kinetic return Blocks.OAK_LOG.defaultBlockState(); } - private static TextureAtlasSprite getSpriteOnSide(BlockState blockstate, Direction side) { - BakedModel blockModel = Minecraft.getInstance() + private static TextureAtlasSprite getSpriteOnSide(BlockState state, Direction side) { + BakedModel model = Minecraft.getInstance() .getBlockRenderer() - .getBlockModel(blockstate); - if (blockModel == null) + .getBlockModel(state); + if (model == null) return null; - @SuppressWarnings("deprecation") - List quads = blockModel.getQuads(blockstate, side, new Random()); - if (quads.isEmpty()) - return null; - return quads.get(0) - .getSprite(); + Random random = new Random(42L); + List quads = model.getQuads(state, side, random, EmptyModelData.INSTANCE); + if (!quads.isEmpty()) { + return quads.get(0) + .getSprite(); + } + random.setSeed(42L); + quads = model.getQuads(state, null, random, EmptyModelData.INSTANCE); + if (!quads.isEmpty()) { + for (BakedQuad quad : quads) { + if (quad.getDirection() == side) { + return quad.getSprite(); + } + } + } + return model.getParticleIcon(EmptyModelData.INSTANCE); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java index 2c1a56730..b7f134fb4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java @@ -127,6 +127,8 @@ public class FilterItem extends Item implements MenuProvider { for (Tag inbt : attributes) { CompoundTag compound = (CompoundTag) inbt; ItemAttribute attribute = ItemAttribute.fromNBT(compound); + if (attribute == null) + continue; boolean inverted = compound.getBoolean("Inverted"); if (count > 3) { list.add(Components.literal("- ...") @@ -194,15 +196,19 @@ public class FilterItem extends Item implements MenuProvider { return test(world, stack, filter, true); } - private static boolean test(Level world, ItemStack stack, ItemStack filter, boolean matchNBT) { + public static boolean test(Level world, ItemStack stack, ItemStack filter, boolean matchNBT) { if (filter.isEmpty()) return true; if (!(filter.getItem() instanceof FilterItem)) - return (matchNBT ? ItemHandlerHelper.canItemStacksStack(filter, stack) : ItemStack.isSame(filter, stack)); + return testDirect(stack, filter, matchNBT); boolean defaults = !filter.hasTag(); + if (defaults) { + return testDirect(filter, stack, matchNBT); + } + if (AllItems.FILTER.get() == filter.getItem()) { ItemStackHandler filterItems = getFilterItems(filter); boolean respectNBT = defaults ? false @@ -211,24 +217,32 @@ public class FilterItem extends Item implements MenuProvider { boolean blacklist = defaults ? false : filter.getTag() .getBoolean("Blacklist"); + boolean isEmpty = true; for (int slot = 0; slot < filterItems.getSlots(); slot++) { ItemStack stackInSlot = filterItems.getStackInSlot(slot); if (stackInSlot.isEmpty()) continue; + isEmpty = false; boolean matches = test(world, stack, stackInSlot, respectNBT); if (matches) return !blacklist; } + if (isEmpty) { + return testDirect(filter, stack, matchNBT); + } return blacklist; } if (AllItems.ATTRIBUTE_FILTER.get() == filter.getItem()) { - WhitelistMode whitelistMode = WhitelistMode.values()[defaults ? 0 - : filter.getTag() - .getInt("WhitelistMode")]; ListTag attributes = defaults ? new ListTag() : filter.getTag() .getList("MatchedAttributes", Tag.TAG_COMPOUND); + if (attributes.isEmpty()) { + return testDirect(filter, stack, matchNBT); + } + WhitelistMode whitelistMode = WhitelistMode.values()[defaults ? 0 + : filter.getTag() + .getInt("WhitelistMode")]; for (Tag inbt : attributes) { CompoundTag compound = (CompoundTag) inbt; ItemAttribute attribute = ItemAttribute.fromNBT(compound); @@ -270,7 +284,7 @@ public class FilterItem extends Item implements MenuProvider { return false; } - private static boolean test(Level world, FluidStack stack, ItemStack filter, boolean matchNBT) { + public static boolean test(Level world, FluidStack stack, ItemStack filter, boolean matchNBT) { if (filter.isEmpty()) return true; if (stack.isEmpty()) @@ -313,4 +327,12 @@ public class FilterItem extends Item implements MenuProvider { return false; } + private static boolean testDirect(ItemStack filter, ItemStack stack, boolean matchNBT) { + if (matchNBT) { + return ItemHandlerHelper.canItemStacksStack(filter, stack); + } else { + return ItemStack.isSame(filter, stack); + } + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java index be6b26340..7e8939102 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java @@ -10,6 +10,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Nullable; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.content.contraptions.processing.InWorldProcessing; @@ -78,6 +79,7 @@ public interface ItemAttribute { return attributeType; } + @Nullable static ItemAttribute fromNBT(CompoundTag nbt) { for (ItemAttribute itemAttribute : types) if (itemAttribute.canRead(nbt)) From 0fa0bbaf5d1c346cca2723b6a99fc6b3f9ca3d89 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Fri, 12 May 2023 11:00:54 -0700 Subject: [PATCH 21/22] Unswap parameters to make sense --- .../create/content/logistics/item/filter/FilterItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java index b7f134fb4..6b9754b3b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java @@ -201,7 +201,7 @@ public class FilterItem extends Item implements MenuProvider { return true; if (!(filter.getItem() instanceof FilterItem)) - return testDirect(stack, filter, matchNBT); + return testDirect(filter, stack, matchNBT); boolean defaults = !filter.hasTag(); From 56b35484d6fbdcff5df78db7f7909fe39a8fe7e1 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri, 12 May 2023 22:33:39 +0200 Subject: [PATCH 22/22] Netherite armor tags --- src/generated/resources/.cache/cache | 6 +++--- .../data/forge/tags/items/armors/boots.json | 3 ++- .../forge/tags/items/armors/chestplates.json | 3 ++- .../data/forge/tags/items/armors/helmets.json | 3 ++- .../content/schematics/SchematicWorld.java | 16 ++++++++-------- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index f32dc95fb..06affe969 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -5378,9 +5378,9 @@ ff1900963bc4cd8ceffa78d58ef1952ceacb2fb7 data/forge/tags/blocks/storage_blocks/b 6b73c57912934d09233ad2966110968a6109f2c9 data/forge/tags/fluids/chocolate.json 391c9b2be5740aea943a8a5fe27eb327e2d973b0 data/forge/tags/fluids/honey.json d6a4e4fe1204b718010543a28a9b9ec4e0977bd7 data/forge/tags/fluids/tea.json -58a0fbab3425558d993559e10fe14a1797b05eab data/forge/tags/items/armors/boots.json -7973972edb524683ef365bc103fcfcde0858a854 data/forge/tags/items/armors/chestplates.json -615e86e25fc29ead90e0901cdaee9d0ed9b3e4b3 data/forge/tags/items/armors/helmets.json +277e826738027ad38b1e0102ea0e6a87f9a42407 data/forge/tags/items/armors/boots.json +8c8f6658ee72bdea2fcef77bade7bfa48de784c8 data/forge/tags/items/armors/chestplates.json +2fa68898dd74fe40c404af7ecb0244b7765e58e6 data/forge/tags/items/armors/helmets.json 5af3164b14c92d2d6e235b5d4eebd93cbee37c0a data/forge/tags/items/buckets/honey.json 2f7cf5a2d485f25d451da9771ed466591cfa5204 data/forge/tags/items/dough.json 2f7cf5a2d485f25d451da9771ed466591cfa5204 data/forge/tags/items/dough/wheat.json diff --git a/src/generated/resources/data/forge/tags/items/armors/boots.json b/src/generated/resources/data/forge/tags/items/armors/boots.json index d97b2e831..7da61d8ca 100644 --- a/src/generated/resources/data/forge/tags/items/armors/boots.json +++ b/src/generated/resources/data/forge/tags/items/armors/boots.json @@ -1,6 +1,7 @@ { "replace": false, "values": [ - "create:diving_boots" + "create:copper_diving_boots", + "create:netherite_diving_boots" ] } \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/armors/chestplates.json b/src/generated/resources/data/forge/tags/items/armors/chestplates.json index 9c5cb97a4..3b3bbadd0 100644 --- a/src/generated/resources/data/forge/tags/items/armors/chestplates.json +++ b/src/generated/resources/data/forge/tags/items/armors/chestplates.json @@ -1,6 +1,7 @@ { "replace": false, "values": [ - "create:copper_backtank" + "create:copper_backtank", + "create:netherite_backtank" ] } \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/armors/helmets.json b/src/generated/resources/data/forge/tags/items/armors/helmets.json index d5208adbf..42f6e845e 100644 --- a/src/generated/resources/data/forge/tags/items/armors/helmets.json +++ b/src/generated/resources/data/forge/tags/items/armors/helmets.json @@ -1,6 +1,7 @@ { "replace": false, "values": [ - "create:diving_helmet" + "create:copper_diving_helmet", + "create:netherite_diving_helmet" ] } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/schematics/SchematicWorld.java b/src/main/java/com/simibubi/create/content/schematics/SchematicWorld.java index 573616dcd..424e07f20 100644 --- a/src/main/java/com/simibubi/create/content/schematics/SchematicWorld.java +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicWorld.java @@ -11,6 +11,7 @@ import java.util.stream.Stream; import com.simibubi.create.Create; import com.simibubi.create.foundation.utility.BBHelper; +import com.simibubi.create.foundation.utility.NBTProcessors; import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; import net.minecraft.core.BlockPos; @@ -18,6 +19,7 @@ import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.decoration.ItemFrame; import net.minecraft.world.entity.player.Player; @@ -73,14 +75,12 @@ public class SchematicWorld extends WrappedWorld implements ServerLevelAccessor @Override public boolean addFreshEntity(Entity entityIn) { - if (entityIn instanceof ItemFrame) - ((ItemFrame) entityIn).getItem() - .setTag(null); - if (entityIn instanceof ArmorStand) { - ArmorStand armorStandEntity = (ArmorStand) entityIn; - armorStandEntity.getAllSlots() - .forEach(stack -> stack.setTag(null)); - } + if (entityIn instanceof ItemFrame itemFrame) + itemFrame.setItem(NBTProcessors.withUnsafeNBTDiscarded(itemFrame.getItem())); + if (entityIn instanceof ArmorStand armorStand) + for (EquipmentSlot equipmentSlot : EquipmentSlot.values()) + armorStand.setItemSlot(equipmentSlot, + NBTProcessors.withUnsafeNBTDiscarded(armorStand.getItemBySlot(equipmentSlot))); return entities.add(entityIn); }