From dfb0ff65c3c0488b49ac2d2539e5cf652484fa0a Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Sat, 11 Jan 2025 13:21:58 +0100 Subject: [PATCH 1/8] Package deal - Ponder scenes for the packager --- .../content/logistics/box/PackageEntity.java | 8 + .../content/logistics/box/PackageItem.java | 2 +- .../ponder/AllCreatePonderScenes.java | 12 +- .../FrogAndConveyorScenes.java | 55 +- .../scenes/highLogistics/PackagerScenes.java | 569 ++++++++++++++++++ .../scenes/highLogistics/PonderHilo.java | 54 ++ .../{ => high_logistics}/chain_conveyor.nbt | Bin .../{ => high_logistics}/package_frogport.nbt | Bin .../create/ponder/high_logistics/packager.nbt | Bin 0 -> 1236 bytes .../high_logistics/packager_address.nbt | Bin 0 -> 2415 bytes .../assets/minecraft/atlases/blocks.json | 4 - 11 files changed, 662 insertions(+), 42 deletions(-) rename src/main/java/com/simibubi/create/infrastructure/ponder/scenes/{ => highLogistics}/FrogAndConveyorScenes.java (97%) create mode 100644 src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/PackagerScenes.java create mode 100644 src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/PonderHilo.java rename src/main/resources/assets/create/ponder/{ => high_logistics}/chain_conveyor.nbt (100%) rename src/main/resources/assets/create/ponder/{ => high_logistics}/package_frogport.nbt (100%) create mode 100644 src/main/resources/assets/create/ponder/high_logistics/packager.nbt create mode 100644 src/main/resources/assets/create/ponder/high_logistics/packager_address.nbt diff --git a/src/main/java/com/simibubi/create/content/logistics/box/PackageEntity.java b/src/main/java/com/simibubi/create/content/logistics/box/PackageEntity.java index ffa2718e33..5aa7c56d11 100644 --- a/src/main/java/com/simibubi/create/content/logistics/box/PackageEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/box/PackageEntity.java @@ -13,6 +13,7 @@ import com.simibubi.create.content.logistics.chute.ChuteBlock; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.ponder.api.level.PonderLevel; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; @@ -169,6 +170,13 @@ public class PackageEntity extends LivingEntity implements IEntityAdditionalSpaw verifyInitialEntity(); originalEntity = null; } + + if (level() instanceof PonderLevel) { + setDeltaMovement(getDeltaMovement().add(0, -0.06, 0)); + if (position().y < 0.125) + discard(); + } + insertionDelay = Math.min(insertionDelay + 1, 30); super.tick(); diff --git a/src/main/java/com/simibubi/create/content/logistics/box/PackageItem.java b/src/main/java/com/simibubi/create/content/logistics/box/PackageItem.java index 1bdf5909e6..3e5fe59a07 100644 --- a/src/main/java/com/simibubi/create/content/logistics/box/PackageItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/box/PackageItem.java @@ -201,7 +201,7 @@ public class PackageItem extends Item { if (compoundnbt.contains("Address", Tag.TAG_STRING) && !compoundnbt.getString("Address") .isBlank()) - pTooltipComponents.add(Components.literal("-> " + compoundnbt.getString("Address")) + pTooltipComponents.add(Components.literal("\u2192 " + compoundnbt.getString("Address")) .withStyle(ChatFormatting.GOLD)); /* diff --git a/src/main/java/com/simibubi/create/infrastructure/ponder/AllCreatePonderScenes.java b/src/main/java/com/simibubi/create/infrastructure/ponder/AllCreatePonderScenes.java index 4e82b92d44..1d56d16323 100644 --- a/src/main/java/com/simibubi/create/infrastructure/ponder/AllCreatePonderScenes.java +++ b/src/main/java/com/simibubi/create/infrastructure/ponder/AllCreatePonderScenes.java @@ -19,7 +19,6 @@ import com.simibubi.create.infrastructure.ponder.scenes.DisplayScenes; import com.simibubi.create.infrastructure.ponder.scenes.EjectorScenes; import com.simibubi.create.infrastructure.ponder.scenes.ElevatorScenes; import com.simibubi.create.infrastructure.ponder.scenes.FanScenes; -import com.simibubi.create.infrastructure.ponder.scenes.FrogAndConveyorScenes; import com.simibubi.create.infrastructure.ponder.scenes.FunnelScenes; import com.simibubi.create.infrastructure.ponder.scenes.GantryScenes; import com.simibubi.create.infrastructure.ponder.scenes.ItemVaultScenes; @@ -42,6 +41,8 @@ import com.simibubi.create.infrastructure.ponder.scenes.fluid.HosePulleyScenes; import com.simibubi.create.infrastructure.ponder.scenes.fluid.PipeScenes; import com.simibubi.create.infrastructure.ponder.scenes.fluid.PumpScenes; import com.simibubi.create.infrastructure.ponder.scenes.fluid.SpoutScenes; +import com.simibubi.create.infrastructure.ponder.scenes.highLogistics.FrogAndConveyorScenes; +import com.simibubi.create.infrastructure.ponder.scenes.highLogistics.PackagerScenes; import com.simibubi.create.infrastructure.ponder.scenes.trains.TrackObserverScenes; import com.simibubi.create.infrastructure.ponder.scenes.trains.TrackScenes; import com.simibubi.create.infrastructure.ponder.scenes.trains.TrainScenes; @@ -350,10 +351,13 @@ public class AllCreatePonderScenes { // Hilo HELPER.forComponents(AllBlocks.CHAIN_CONVEYOR) - .addStoryBoard("chain_conveyor", FrogAndConveyorScenes::conveyor); + .addStoryBoard("high_logistics/chain_conveyor", FrogAndConveyorScenes::conveyor); HELPER.forComponents(AllBlocks.PACKAGE_FROGPORT) - .addStoryBoard("package_frogport", FrogAndConveyorScenes::frogPort); - + .addStoryBoard("high_logistics/package_frogport", FrogAndConveyorScenes::frogPort); + HELPER.forComponents(AllBlocks.PACKAGER) + .addStoryBoard("high_logistics/packager", PackagerScenes::packager) + .addStoryBoard("high_logistics/packager_address", PackagerScenes::packagerAddress); + // Trains HELPER.forComponents(TrackMaterial.allBlocks() .stream() diff --git a/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/FrogAndConveyorScenes.java b/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/FrogAndConveyorScenes.java similarity index 97% rename from src/main/java/com/simibubi/create/infrastructure/ponder/scenes/FrogAndConveyorScenes.java rename to src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/FrogAndConveyorScenes.java index 53cd2921a3..7c83de7bd4 100644 --- a/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/FrogAndConveyorScenes.java +++ b/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/FrogAndConveyorScenes.java @@ -1,4 +1,4 @@ -package com.simibubi.create.infrastructure.ponder.scenes; +package com.simibubi.create.infrastructure.ponder.scenes.highLogistics; import java.util.Iterator; import java.util.function.Supplier; @@ -564,10 +564,19 @@ public class FrogAndConveyorScenes { scene.world() .multiplyKineticSpeed(util.select() .fromTo(9, 0, 1, 5, 1, 0), 1 / 32f); - scene.idle(5); scene.overlay() - .showText(75) + .showText(60) + .attachKeyFrame() + .text("If a package is addressed to a different name..") + .pointAt(util.vector() + .topOf(5, 0, 3)) + .placeNearTarget(); + + scene.idle(70); + + scene.overlay() + .showText(40) .colored(PonderPalette.BLUE) .text("Albert") .pointAt(util.vector() @@ -575,24 +584,15 @@ public class FrogAndConveyorScenes { .placeNearTarget(); scene.idle(5); scene.overlay() - .showText(70) + .showText(40) .colored(PonderPalette.OUTPUT) - .text("Peter") + .text("\u2192 Peter") .pointAt(util.vector() .centerOf(util.grid() .at(5, 2, 0))) .placeNearTarget(); - scene.idle(30); - scene.overlay() - .showText(80) - .attachKeyFrame() - .text("If a package is addressed to a different name..") - .pointAt(util.vector() - .topOf(5, 0, 3)) - .placeNearTarget(); - - scene.idle(60); + scene.idle(50); scene.world() .multiplyKineticSpeed(util.select() @@ -712,7 +712,7 @@ public class FrogAndConveyorScenes { scene.overlay() .showText(55) .colored(PonderPalette.OUTPUT) - .text("Peter") + .text("\u2192 Peter") .pointAt(util.vector() .centerOf(util.grid() .at(0, 2, 5))) @@ -775,7 +775,7 @@ public class FrogAndConveyorScenes { scene.world() .showIndependentSection(fromPackager, Direction.WEST); ElementLink toPackagerE = scene.world() - .showIndependentSection(toPackager, Direction.WEST); + .showIndependentSection(toPackager, Direction.EAST); scene.world() .moveSection(toPackagerE, util.vector() .of(0, 0, 1), 0); @@ -849,14 +849,8 @@ public class FrogAndConveyorScenes { .fromTo(5, 1, 2, 6, 1, 1)); scene.idle(5); - scene.world() - .modifyBlockEntity(util.grid() - .at(5, 1, 2), PackagerBlockEntity.class, be -> { - be.animationTicks = PackagerBlockEntity.CYCLE; - be.animationInward = false; - be.heldBox = box; - }); - + PonderHilo.packagerCreate(scene, util.grid() + .at(5, 1, 2), box); scene.idle(30); scene.world() @@ -873,15 +867,10 @@ public class FrogAndConveyorScenes { .modifyBlockEntity(conv2, ChainConveyorBlockEntity.class, be -> boxTransfer(conv1, conv2, be)); scene.idle(50); - scene.world() - .modifyBlockEntity(util.grid() - .at(2, 1, 4), PackagerBlockEntity.class, be -> { - be.animationTicks = PackagerBlockEntity.CYCLE; - be.animationInward = true; - be.previouslyUnwrapped = box; - }); - + PonderHilo.packagerUnpack(scene, util.grid() + .at(2, 1, 4), box); scene.idle(20); + scene.overlay() .showControls(util.vector() .blockSurface(util.grid() diff --git a/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/PackagerScenes.java b/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/PackagerScenes.java new file mode 100644 index 0000000000..e713358119 --- /dev/null +++ b/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/PackagerScenes.java @@ -0,0 +1,569 @@ +package com.simibubi.create.infrastructure.ponder.scenes.highLogistics; + +import java.util.List; + +import com.simibubi.create.AllItems; +import com.simibubi.create.content.logistics.box.PackageItem; +import com.simibubi.create.content.logistics.box.PackageStyles; +import com.simibubi.create.foundation.ponder.CreateSceneBuilder; + +import net.createmod.catnip.utility.Pointing; +import net.createmod.ponder.api.PonderPalette; +import net.createmod.ponder.api.element.ElementLink; +import net.createmod.ponder.api.element.WorldSectionElement; +import net.createmod.ponder.api.scene.SceneBuilder; +import net.createmod.ponder.api.scene.SceneBuildingUtil; +import net.createmod.ponder.api.scene.Selection; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class PackagerScenes { + + public static void packager(SceneBuilder builder, SceneBuildingUtil util) { + CreateSceneBuilder scene = new CreateSceneBuilder(builder); + scene.title("packager", "Creating and unwrapping packages"); + scene.configureBasePlate(0, 0, 7); + scene.showBasePlate(); + + Selection chest1 = util.select() + .fromTo(5, 2, 3, 5, 2, 4); + BlockPos funnel1 = util.grid() + .at(4, 2, 2); + BlockPos funnel2 = util.grid() + .at(1, 2, 2); + Selection funnel1S = util.select() + .position(funnel1); + Selection funnel2S = util.select() + .position(funnel2); + BlockPos packager1 = util.grid() + .at(5, 2, 2); + BlockPos packager2 = util.grid() + .at(1, 2, 3); + Selection packager1S = util.select() + .position(packager1); + Selection packager2S = util.select() + .position(packager2); + Selection largeCog = util.select() + .position(7, 0, 3); + Selection cogNBelt = util.select() + .fromTo(6, 1, 2, 0, 1, 2) + .add(util.select() + .position(6, 1, 3)); + BlockPos lever = util.grid() + .at(5, 3, 2); + Selection scaff1 = util.select() + .fromTo(5, 1, 3, 5, 1, 4); + Selection scaff2 = util.select() + .fromTo(1, 1, 3, 1, 1, 4); + scene.idle(5); + + ElementLink chestL = scene.world() + .showIndependentSection(chest1, Direction.DOWN); + scene.world() + .moveSection(chestL, util.vector() + .of(-2, -1, 0), 0); + scene.idle(10); + ElementLink packagerL = scene.world() + .showIndependentSection(packager1S, Direction.SOUTH); + scene.world() + .moveSection(packagerL, util.vector() + .of(-2, -1, 0), 0); + scene.idle(20); + + ItemStack dirt = new ItemStack(Items.DIRT); + scene.overlay() + .showControls(util.vector() + .of(2.5, 3, 2.5), Pointing.DOWN, 40) + .withItem(dirt); + scene.idle(20); + + scene.overlay() + .showText(80) + .text("Place packagers next to the inventory they should target") + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector() + .of(2, 2.5, 2.5)); + scene.idle(60); + + ElementLink leverL = scene.world() + .showIndependentSection(util.select() + .position(lever), Direction.DOWN); + scene.world() + .moveSection(leverL, util.vector() + .of(-2, -1, 0), 0); + scene.idle(30); + + scene.world() + .toggleRedstonePower(util.select() + .fromTo(lever, packager1)); + scene.effects() + .indicateRedstone(lever.west(2) + .below()); + + scene.idle(10); + ItemStack box = PackageStyles.getDefaultBox() + .copy(); + PackageItem.addAddress(box, "Warehouse"); + PonderHilo.packagerCreate(scene, packager1, box); + scene.idle(30); + + scene.overlay() + .showText(80) + .text("Given redstone power, it will pack items from the inventory into a package") + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(3, 1, 2), Direction.UP)); + scene.idle(30); + + scene.idle(80); + + scene.world() + .moveSection(leverL, util.vector() + .of(2, 1, 0), 10); + scene.world() + .moveSection(packagerL, util.vector() + .of(2, 1, 0), 10); + scene.world() + .moveSection(chestL, util.vector() + .of(2, 1, 0), 10); + scene.world() + .showSection(scaff1, Direction.UP); + scene.idle(10); + scene.world() + .showSection(largeCog, Direction.UP); + scene.world() + .showSection(cogNBelt, Direction.SOUTH); + scene.idle(10); + scene.world() + .showSection(funnel1S, Direction.DOWN); + scene.idle(15); + scene.world() + .createItemOnBelt(util.grid() + .at(4, 1, 2), Direction.EAST, box); + PonderHilo.packagerClear(scene, packager1); + scene.idle(20); + scene.world() + .toggleRedstonePower(util.select() + .fromTo(5, 2, 2, 5, 3, 2)); + scene.idle(10); + + scene.world() + .multiplyKineticSpeed(util.select() + .everywhere(), 1 / 16f); + + scene.overlay() + .showText(70) + .text("These can be picked up and transported like any other item") + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(3, 2, 2), Direction.EAST)); + + scene.idle(80); + scene.world() + .multiplyKineticSpeed(util.select() + .everywhere(), 16f); + scene.idle(10); + + scene.world() + .showSection(scaff2, Direction.DOWN); + scene.idle(5); + scene.world() + .showSection(packager2S, Direction.DOWN); + scene.world() + .showSection(util.select() + .position(1, 2, 4), Direction.DOWN); + scene.idle(10); + scene.world() + .showSection(funnel2S, Direction.SOUTH); + scene.rotateCameraY(-15); + scene.idle(40); + + scene.world() + .removeItemsFromBelt(util.grid() + .at(1, 1, 2)); + scene.world() + .flapFunnel(util.grid() + .at(1, 2, 2), false); + PonderHilo.packagerUnpack(scene, packager2, box); + + scene.idle(20); + scene.overlay() + .showControls(util.vector() + .topOf(util.grid() + .at(1, 2, 4)), + Pointing.DOWN, 40) + .withItem(dirt); + scene.idle(20); + + scene.overlay() + .showText(90) + .text("Packages inserted will be destroyed, unpacking the contents into the inventory") + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(1, 2, 3), Direction.WEST)); + scene.idle(100); + + scene.world() + .toggleRedstonePower(util.select() + .fromTo(5, 2, 2, 5, 3, 2)); + scene.effects() + .indicateRedstone(util.grid() + .at(5, 3, 2)); + PonderHilo.packagerCreate(scene, packager1, box); + scene.idle(25); + + scene.world() + .createItemOnBelt(util.grid() + .at(4, 1, 2), Direction.EAST, box); + PonderHilo.packagerClear(scene, packager1); + scene.idle(30); + + scene.overlay() + .showText(60) + .text("Full") + .colored(PonderPalette.RED) + .placeNearTarget() + .pointAt(util.vector() + .topOf(util.grid() + .at(1, 2, 4))); + scene.idle(80); + + scene.overlay() + .showOutlineWithText(util.select() + .fromTo(1, 2, 3, 1, 2, 4), 90) + .text("Packagers will not accept packages they cannot fully unpack") + .colored(PonderPalette.RED) + .placeNearTarget() + .attachKeyFrame() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(1, 2, 3), Direction.WEST)); + scene.idle(40); + + PonderHilo.packageHopsOffBelt(scene, util.grid() + .at(0, 1, 2), Direction.WEST); + scene.idle(40); + + } + + public static void packagerAddress(SceneBuilder builder, SceneBuildingUtil util) { + CreateSceneBuilder scene = new CreateSceneBuilder(builder); + scene.title("packager_address", "Routing packages with an address"); + scene.configureBasePlate(0, 0, 9); + scene.scaleSceneView(.875f); + scene.showBasePlate(); + + Selection frogport = util.select() + .position(7, 1, 1); + Selection postbox = util.select() + .fromTo(6, 1, 2, 6, 2, 2); + Selection northBelt = util.select() + .fromTo(3, 1, 3, 4, 1, 0); + Selection initialKinetics = util.select() + .fromTo(3, 1, 5, 3, 1, 9); + Selection largeCog = util.select() + .position(2, 0, 9); + Selection saw = util.select() + .fromTo(2, 1, 5, 0, 1, 4); + Selection eastBelt = util.select() + .fromTo(3, 1, 4, 8, 1, 4); + Selection tunnelS = util.select() + .position(4, 2, 4); + Selection chest = util.select() + .fromTo(7, 2, 8, 7, 2, 7); + Selection scaffold = util.select() + .fromTo(7, 1, 8, 7, 1, 7); + BlockPos packager = util.grid() + .at(7, 2, 6); + Selection packagerAndLever = util.select() + .fromTo(7, 2, 6, 7, 3, 6); + Selection packagerBelt = util.select() + .fromTo(7, 1, 6, 4, 1, 6); + BlockPos funnel = util.grid() + .at(6, 2, 6); + Selection signS = util.select() + .position(7, 2, 5); + + scene.idle(10); + ElementLink chestL = scene.world() + .showIndependentSection(chest, Direction.DOWN); + scene.world() + .moveSection(chestL, util.vector() + .of(-2, -1, -2), 0); + scene.idle(5); + scene.world() + .showSectionAndMerge(packagerAndLever, Direction.SOUTH, chestL); + scene.idle(20); + + scene.world() + .showSectionAndMerge(signS, Direction.SOUTH, chestL); + scene.idle(15); + + scene.overlay() + .showText(40) + .text("Warehouse") + .colored(PonderPalette.OUTPUT) + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(5, 1, 4), Direction.NORTH) + .add(-0.5, 0, 0)); + scene.idle(50); + + scene.overlay() + .showText(60) + .text("When a sign is placed on a packager..") + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(5, 1, 4), Direction.NORTH) + .add(-0.5, 0, 0)); + scene.idle(50); + + scene.world() + .toggleRedstonePower(packagerAndLever); + scene.effects() + .indicateRedstone(util.grid() + .at(5, 1, 4)); + ItemStack box = PackageStyles.getDefaultBox() + .copy(); + PonderHilo.packagerCreate(scene, packager, box); + + scene.idle(20); + scene.world() + .moveSection(chestL, util.vector() + .of(0, 1, 0), 10); + scene.idle(10); + scene.world() + .showSectionAndMerge(scaffold, Direction.NORTH, chestL); + scene.world() + .showSection(largeCog, Direction.UP); + scene.world() + .showSection(initialKinetics, Direction.NORTH); + scene.world() + .showSectionAndMerge(packagerBelt, Direction.SOUTH, chestL); + scene.idle(5); + scene.world() + .showSectionAndMerge(util.select() + .position(funnel), Direction.DOWN, chestL); + scene.idle(15); + + PonderHilo.packagerClear(scene, packager); + scene.world() + .createItemOnBelt(util.grid() + .at(6, 1, 6), Direction.EAST, box); + scene.idle(20); + + scene.world() + .multiplyKineticSpeed(util.select() + .everywhere(), 1 / 32f); + scene.overlay() + .showText(40) + .text("\u2192 Warehouse") + .colored(PonderPalette.OUTPUT) + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(3, 2, 4), Direction.NORTH)); + scene.idle(50); + + scene.overlay() + .showText(100) + .text("Created packages will carry the written line of text as their address") + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(3, 2, 4), Direction.NORTH) + .add(-0.5, 0, 0)); + scene.idle(120); + + scene.world() + .hideIndependentSection(chestL, Direction.NORTH); + scene.idle(15); + scene.world() + .removeItemsFromBelt(util.grid() + .at(5, 1, 6)); + scene.world() + .removeItemsFromBelt(util.grid() + .at(4, 1, 6)); + scene.idle(15); + + scene.world() + .showSection(eastBelt, Direction.WEST); + scene.idle(5); + scene.world() + .showSection(tunnelS, Direction.DOWN); + scene.idle(5); + scene.world() + .showSection(saw, Direction.EAST); + scene.idle(5); + scene.world() + .showSection(northBelt, Direction.SOUTH); + scene.rotateCameraY(-15); + scene.idle(15); + + scene.overlay() + .showControls(util.vector() + .of(4, 2.825, 4.5), Pointing.DOWN, 60) + .withItem(AllItems.PACKAGE_FILTER.asStack()); + scene.idle(10); + scene.overlay() + .showFilterSlotInput(util.vector() + .of(4.1, 2.825, 4.5), 50); + scene.idle(30); + + scene.overlay() + .showText(70) + .text("Package filters route packages based on their address") + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector() + .of(4, 2.825, 4.5)); + scene.idle(70); + + ItemStack warehouseBox = PackageStyles.getDefaultBox() + .copy(); + ItemStack factoryBox = PackageItem.containing(List.of(new ItemStack(Items.IRON_INGOT))); + PackageItem.addAddress(warehouseBox, "Warehouse"); + PackageItem.addAddress(factoryBox, "Factory"); + + scene.world() + .createItemOnBelt(util.grid() + .at(6, 1, 4), Direction.EAST, warehouseBox); + scene.idle(10); + + scene.overlay() + .showText(50) + .text("\u2192 Warehouse") + .colored(PonderPalette.OUTPUT) + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(7, 2, 4), Direction.WEST)); + scene.overlay() + .showText(50) + .colored(PonderPalette.BLUE) + .text("Factory") + .placeNearTarget() + .pointAt(util.vector() + .of(4, 2.825, 4.5)); + scene.idle(60); + + scene.world() + .multiplyKineticSpeed(util.select() + .everywhere(), 32f); + + scene.idle(60); + + scene.world() + .createItemOnBelt(util.grid() + .at(6, 1, 4), Direction.EAST, factoryBox); + scene.world() + .multiplyKineticSpeed(util.select() + .everywhere(), 1 / 32f); + scene.idle(10); + + scene.overlay() + .showText(50) + .text("\u2192 Factory") + .colored(PonderPalette.OUTPUT) + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(7, 2, 4), Direction.WEST)); + scene.overlay() + .showText(50) + .colored(PonderPalette.BLUE) + .text("Factory") + .placeNearTarget() + .pointAt(util.vector() + .of(4, 2.825, 4.5)); + scene.idle(60); + + scene.world() + .multiplyKineticSpeed(util.select() + .everywhere(), 32f); + + scene.idle(40); + PonderHilo.packageHopsOffBelt(scene, util.grid() + .at(4, 1, 0), Direction.NORTH); + scene.idle(40); + scene.world() + .multiplyKineticSpeed(util.select() + .everywhere(), 1 / 32f); + scene.overlay() + .showText(100) + .text("For compactness, mechanical saws can unwrap packages straight onto a belt") + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector() + .topOf(util.grid() + .at(2, 1, 4))); + scene.idle(110); + + scene.world() + .multiplyKineticSpeed(util.select() + .everywhere(), 32f); + + scene.idle(20); + scene.world() + .hideSection(eastBelt, Direction.EAST); + scene.idle(5); + scene.world() + .hideSection(tunnelS, Direction.UP); + scene.idle(5); + scene.world() + .hideSection(saw, Direction.WEST); + scene.idle(5); + scene.world() + .hideSection(initialKinetics, Direction.UP); + scene.world() + .hideSection(largeCog, Direction.DOWN); + scene.world() + .hideSection(northBelt, Direction.NORTH); + scene.rotateCameraY(15); + scene.idle(15); + + ElementLink extrasL = scene.world() + .showIndependentSection(postbox, Direction.DOWN); + scene.world() + .moveSection(extrasL, util.vector() + .of(-3, 0, 2), 0); + scene.idle(5); + scene.world() + .showSectionAndMerge(frogport, Direction.DOWN, extrasL); + scene.idle(20); + + scene.overlay() + .showText(100) + .text("Aside from those filters, Frogports and Postboxes have package routing capabilities") + .attachKeyFrame() + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(3, 2, 4), Direction.NORTH)); + scene.idle(110); + + scene.overlay() + .showText(80) + .text("Inspect them to find out more about their behaviour") + .placeNearTarget() + .pointAt(util.vector() + .blockSurface(util.grid() + .at(3, 2, 4), Direction.NORTH)); + scene.idle(90); + + } + +} diff --git a/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/PonderHilo.java b/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/PonderHilo.java new file mode 100644 index 0000000000..2b19469aee --- /dev/null +++ b/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/highLogistics/PonderHilo.java @@ -0,0 +1,54 @@ +package com.simibubi.create.infrastructure.ponder.scenes.highLogistics; + +import com.simibubi.create.content.logistics.box.PackageEntity; +import com.simibubi.create.content.logistics.box.PackageStyles; +import com.simibubi.create.content.logistics.packager.PackagerBlockEntity; +import com.simibubi.create.foundation.ponder.CreateSceneBuilder; + +import net.createmod.ponder.api.element.ElementLink; +import net.createmod.ponder.api.element.EntityElement; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; + +public class PonderHilo { + + public static void packagerCreate(CreateSceneBuilder scene, BlockPos pos, ItemStack box) { + scene.world() + .modifyBlockEntity(pos, PackagerBlockEntity.class, be -> { + be.animationTicks = PackagerBlockEntity.CYCLE; + be.animationInward = false; + be.heldBox = box; + }); + } + + public static void packagerUnpack(CreateSceneBuilder scene, BlockPos pos, ItemStack box) { + scene.world() + .modifyBlockEntity(pos, PackagerBlockEntity.class, be -> { + be.animationTicks = PackagerBlockEntity.CYCLE; + be.animationInward = true; + be.previouslyUnwrapped = box; + }); + } + + public static void packagerClear(CreateSceneBuilder scene, BlockPos pos) { + scene.world() + .modifyBlockEntity(pos, PackagerBlockEntity.class, be -> be.heldBox = ItemStack.EMPTY); + } + + public static ElementLink packageHopsOffBelt(CreateSceneBuilder scene, BlockPos beltPos, + Direction side) { + scene.world() + .removeItemsFromBelt(beltPos); + return scene.world() + .createEntity(l -> { + PackageEntity packageEntity = new PackageEntity(l, beltPos.getX() + 0.5 + side.getStepX() * 0.25, + beltPos.getY() + 0.875, beltPos.getZ() + 0.5 + side.getStepZ() * 0.25); + packageEntity.setDeltaMovement(new Vec3(side.getStepX(), 0.5f, side.getStepZ()).scale(0.25f)); + packageEntity.box = PackageStyles.getDefaultBox(); + return packageEntity; + }); + } + +} diff --git a/src/main/resources/assets/create/ponder/chain_conveyor.nbt b/src/main/resources/assets/create/ponder/high_logistics/chain_conveyor.nbt similarity index 100% rename from src/main/resources/assets/create/ponder/chain_conveyor.nbt rename to src/main/resources/assets/create/ponder/high_logistics/chain_conveyor.nbt diff --git a/src/main/resources/assets/create/ponder/package_frogport.nbt b/src/main/resources/assets/create/ponder/high_logistics/package_frogport.nbt similarity index 100% rename from src/main/resources/assets/create/ponder/package_frogport.nbt rename to src/main/resources/assets/create/ponder/high_logistics/package_frogport.nbt diff --git a/src/main/resources/assets/create/ponder/high_logistics/packager.nbt b/src/main/resources/assets/create/ponder/high_logistics/packager.nbt new file mode 100644 index 0000000000000000000000000000000000000000..3319f35325186891376bcdbb412083a68d7ee915 GIT binary patch literal 1236 zcmb2|=3oGW|92x!=RGzPSvqgpTbs0tOsuWY)I7tG`Jv`#XEv%TSeDa;|AJ+Al9+>v6gEaOd}V&Ud|cJA2G-(c0hCAP}@i zxTgI_-d0bhnCDjPu3h1?kEHu75x#n`dwZ_XnHHn&Y3mzYyn=bJcB%DjZ~JJLP{Tg& zK%;uegHD->B<}v}0o8MlC)lvd-EUMcc)%%Jp~OD##-YdNSK^)|A}m zdTY%e-WeB~fNoTBpSNIHqJx#ngLEsUiywIue)HPDo^XxvMeBsg9V)d}i!;~h->=m; z@X(O&Uz3)~KZV2fb*ld!9`87EJgQ0Sc%9Q98|C@Sg$#~pPxVjd@l&^CpSxVvrE90p z#}5zwMofG1x1_fAui*cGJ=gVLOKp>~;mx-EZYQ$!Jx@q{fi7#ZLSgP7xgQ?=+h%I!-#`J1N0?Qp|nlNe^bKWbX8Ql#Lt{^&-JXwfSI;-m zi#mC!gsIBG{^L9C?%XNsPCCuYS-yq+kIeq%+?6-os(6D#d#Bu0UijhmZ%dg|Jlu-q zE5BdbwDJ+#*GX(&=Y3rBF#P5JeJ|G}7RA|TZ&^Ku`O_nppml8uznwPt=u`;GC+|5s zlPywhll9RHE0;L`?RvH%;fi?iI___Cg|5w>CO;v66>I3T!=zW(^C&{A!o5#!H48 zdmD5AM(p`4zriGDL&^95S(#S?-W=97&3P@I^8O--ls8-}nYzGK#6EVP$A;2NniKTH zV!8|0Jv0%O2|et}_VFgy!W|KF?)~`}X|u*X=*)!^G9p!*4p>a;yvXr8&18v>qthgv z<3DUzAJz8i{`SexU3T@Z>fh;8-9_4)w1fgQW%&xN4ic*U2E}#O{q+;gNuT11f1S!n`Lu$bI-wG_OcbcmAa_1*Huq?{e4e% zUYE$)w5NWx(q-?tTB|(eUU}=N>-8jG_|h=#?Hj|WtsBcdXFaM|=~_P_;+?Cjk$kW8 o?7nK>-Xn_53tP<R literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/ponder/high_logistics/packager_address.nbt b/src/main/resources/assets/create/ponder/high_logistics/packager_address.nbt new file mode 100644 index 0000000000000000000000000000000000000000..9079e0e4ba7ea985465a408b40bf39b8e76da052 GIT binary patch literal 2415 zcmZ9Gc{~#g7{`l589B<8+gwFdzFH>qm-pF93S8kySU?dI&FECu&Je!sB)Gj=)j$ne-Kzg!tb8<2x7@nK7Q-NM6iWhm6C!g>Rw>&`rboL@B64)@Cq{d zfb_9vQ>h)yg!S?9otV$piMr0Krf9_^!G&Pw*_tWv@x$8PqkWP*)gPaN3er=@d5Vk$ zHT84GP*F(aTIeQ6;OCau_V)hi?aK0o<#+mdJcETjH9@lGyhK$n18K$=kazuHkbFY< zp_G`r4`bXuf``P!eRF_KDLPH3=P4&XUGBZq_3u?FTBwhcT#VWPx2yp@M)IOos*x5` zoAHe7!nqq1g#LU5m91$p#4G6Tg^c^$gMz)Ih%lrfwj*HC3IO9!?SUm-DB5w@);1*Fn%?k zoK~*S=$nS8toAzQ=Y@tgN80x^BSQ^#>XSk^UxH6SIa&Fj_(H~;m&Lgwv|+xF+b-5K z(PAa;LGMTI5_Qzqw>%W%B+J6ttD8&iYm>E19~I<49Tpv4zlsF*Pl#TfknabDW5@88 zSVvc^7OVk(0m~bX)d{q~Zs-F0Vc?BwoK$$J>cd;$aiKNrUgg~r$eM^y3+-2+TDw07 zM!T;WM?SXfq-8ubcJWZzo^WMg#;Ftf8~6^}G+GNe`wYY`kYelg5Jz{m$LdP?_6(GD z+tynf(b9omvAiuuToimW0(ycF-@dO-jE0^nw(`$+IyQoD28oe2@DFA4%4C(~pcXu{ zk-~%sff5vf)^^9oLEJn2lrFKYU8w|KLvWfNgD}CCtP)g?mA%Ktx~BEMQ-(`41Gz*# zb12cV1NfCMYrwGgL}UDxK%vd)okg7zd7sHo3ET4Dz`0jGHsAJNkGkG-&621Vc}Kt; zRZBAr^HJJ~IH2?b7~0);T%qPKpZJr%nY3fmmLqL zP+*!n&Yh6YA`bJ8)^PzwA#>J4BG;3MHe$u=%LrBeUa&P%6*> z5evo%7V0uaZP1)`ujTYpA3JZ8CddZX>WC2`bE1dskjt=JN0F+Bx&6( zWHL{pOu|C(V%iIT$!rK`?fy`qM%{bmAF@Z54w|Qbm!YsguBSaSjThVVst8X<(J;X)rIP3aj6T#y+_R;ga_)&XGE=5e9^ z`bhC|`&9rXZdK4P?Yv3xO;ABx3ge6VTl#2Q8)F$&TGJr9rt*^u3k#3cO#$8BFIxmF z)j8WN3vHcBxc=Q1&|!bS2v&PkeT@~wVNfG!ZyOXP${5eZeI~t`dw>nmC&fH&cncPsD2u2o5V(Qom^5K{p;RtjqaP|~HL5IBqKsHJkt9Z1f0bXSQH| zRCV-a22ROrh;?olQXaO_2^S}s8d7Y~bEK}75WV}5mXon|;0ZYZsd=+llI@{pP@5(@ z);pR;HbuxFx{N80_&aNOK=Cn$U8MQ$`tJrUdc>Ux zjD-3ZNsrtUqtrM!?uiWr{?}a5BCsR+a8cP_Wt+-MseglOjg9t2~ebgPOI6}>z7?(s#We_N6EEN*)uFK*~Di<2|N%U1;JDW&6=>F!RR zy|&eUZs$I0^FqpK%+||7=MSL)z0F~jX>n&}?Aq3vK7ma>gXRg~TVCd!Qn!a{nr1L_ zZcg==O_-#(A zo{GdaPrUuRDjQbHgR>u28j~dlu>MbaRz!DVndOfO64ze3QU4)pRnQZvzR){U*Py;n z(of=?t=CPEIaK>kX0(+yvNLox7v-4D7LU7CuO07_ta==a~wBv!S~f z0e)>+?MC>Pqf*}Bk9yK~wt+O%b#gDxsBp%sf~gECUpAzNtw#oO$Ra59>gC&d@04#M v$Qjq5xyoigC^AQ@4Qa4-{tsK;t}MKnM8~cBHC2qd9d2C@XfzjS&z}DPCOEZG literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/minecraft/atlases/blocks.json b/src/main/resources/assets/minecraft/atlases/blocks.json index 5a63bd52fb..c6c0cec114 100644 --- a/src/main/resources/assets/minecraft/atlases/blocks.json +++ b/src/main/resources/assets/minecraft/atlases/blocks.json @@ -24,10 +24,6 @@ "type": "single", "resource": "create:entity/blueprint_small" }, - { - "type": "single", - "resource": "create:entity/display_cloth" - }, { "type": "single", "resource": "create:entity/coupling" From 0e69f537f276d01c3bd295728a6d9b371957690d Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Sat, 11 Jan 2025 18:14:30 +0100 Subject: [PATCH 2/8] Special Delivery - Added train schedule instructions for delivering or retrieving packages - Moved schedule instruction logic into their respective subclasses - Fixed schedule screen no longer showing tooltips in the entry editor --- .../2d64935085b86659cb7857bad9701dbf9bab6e4c | 6 +- .../resources/assets/create/lang/en_ud.json | 58 ++++++ .../resources/assets/create/lang/en_us.json | 58 ++++++ .../content/trains/entity/TrainStatus.java | 7 + .../content/trains/schedule/Schedule.java | 4 + .../trains/schedule/ScheduleRuntime.java | 88 +++------ .../trains/schedule/ScheduleScreen.java | 12 +- .../ChangeThrottleInstruction.java | 14 ++ .../destination/ChangeTitleInstruction.java | 14 ++ .../DeliverPackagesInstruction.java | 126 +++++++++++++ .../destination/DestinationInstruction.java | 45 +++++ .../destination/FetchPackagesInstruction.java | 170 ++++++++++++++++++ .../destination/ScheduleInstruction.java | 7 + .../assets/create/lang/default/interface.json | 14 ++ 14 files changed, 555 insertions(+), 68 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/trains/schedule/destination/DeliverPackagesInstruction.java create mode 100644 src/main/java/com/simibubi/create/content/trains/schedule/destination/FetchPackagesInstruction.java diff --git a/src/generated/resources/.cache/2d64935085b86659cb7857bad9701dbf9bab6e4c b/src/generated/resources/.cache/2d64935085b86659cb7857bad9701dbf9bab6e4c index a464cf4561..1b87b3e135 100644 --- a/src/generated/resources/.cache/2d64935085b86659cb7857bad9701dbf9bab6e4c +++ b/src/generated/resources/.cache/2d64935085b86659cb7857bad9701dbf9bab6e4c @@ -1,4 +1,4 @@ -// 1.20.1 2025-01-08T12:42:08.2186069 Registrate Provider for create [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2025-01-11T18:12:51.5905299 Registrate Provider for create [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 60bbdf92d2ac9824ea6144955c74043a6005f79d assets/create/blockstates/acacia_window.json 6a67703c2697d81b7dc83e9d72a66f9c9ff08383 assets/create/blockstates/acacia_window_pane.json c3ae87b62e81d8e9476eccd793bb1548d74c66a1 assets/create/blockstates/adjustable_chain_gearshift.json @@ -642,8 +642,8 @@ b0d8f08968763a5f74e5cd5644377a76a9f39753 assets/create/blockstates/yellow_toolbo fe8c497aacc641c2f01cec90bba9f19e59cc2ed2 assets/create/blockstates/yellow_valve_handle.json e819e93fdcbe9fd9c050a052d2718ff3b3539365 assets/create/blockstates/zinc_block.json 64121dcb216381c83b4fe28aa361ea07c24c9ad0 assets/create/blockstates/zinc_ore.json -c1d7b1f496afa2f971078caf90f20255292d760b assets/create/lang/en_ud.json -ce3c58e8401db1c42f3e1187bec1343fbf15009e assets/create/lang/en_us.json +913f3794fb772a0736ae66dff722b3c468bcde79 assets/create/lang/en_ud.json +1f6031cb19932ad54d645fbca1f2773385dd47ed assets/create/lang/en_us.json a97e1060e00ae701a02e39cd4ef8054cf345fac4 assets/create/models/block/acacia_window.json 103e032c0b1a0a6a27c67da8c91179a564bd281c assets/create/models/block/acacia_window_pane_noside.json fb00b627abda76ad4fea867ca57dbfadd24fffa3 assets/create/models/block/acacia_window_pane_noside_alt.json diff --git a/src/generated/resources/assets/create/lang/en_ud.json b/src/generated/resources/assets/create/lang/en_ud.json index 403ebcb5bc..5f8a0dc827 100644 --- a/src/generated/resources/assets/create/lang/en_ud.json +++ b/src/generated/resources/assets/create/lang/en_ud.json @@ -1692,6 +1692,12 @@ "create.ponder.cart_assembler_rails.text_2": "pǝɹǝʍoԀ s,ʇı ןıʇun ǝɔɐןd uı pןǝɥ ǝq ןןıʍ sʇɹɐɔ ǝɥʇ 'ןıɐᴚ ɹǝןןoɹʇuoƆ ɹo pǝɹǝʍoԀ uo uǝɥM", "create.ponder.cart_assembler_rails.text_3": "ɹoɥɔuɐ ǝɥʇ sɐ pǝsn ǝq uɐɔ sʇɹɐɔǝuıW ɟo sǝdʎʇ ɹǝɥʇO", "create.ponder.cart_assembler_rails.text_4": "sǝıɹoʇuǝʌuı pǝɥɔɐʇʇɐ ʎuɐ ɯoɹɟ ןǝnɟ buıןןnd 'pǝɹǝʍod sǝʌןǝsɯǝɥʇ dǝǝʞ ןןıʍ sʇɹɐƆ ǝɔɐuɹnℲ", + "create.ponder.chain_conveyor.header": "sɹoʎǝʌuoƆ uıɐɥƆ buısn ǝɔɹoɟ ןɐuoıʇɐʇoɹ buıʎɐןǝᴚ", + "create.ponder.chain_conveyor.text_1": "ɯǝɥʇ ʇɔǝuuoɔ oʇ suıɐɥɔ ɥʇıʍ sɹoʎǝʌuoɔ oʍʇ ʞɔıןɔ-ʇɥbıᴚ", + "create.ponder.chain_conveyor.text_2": "˙˙ʎןqıxǝןɟ ʎɹǝʌ ɹǝɥʇo ɥɔɐǝ oʇ ɹǝʍod ןɐuoıʇɐʇoɹ ʎɐןǝɹ ǝsǝɥ⟘", + "create.ponder.chain_conveyor.text_3": "ɯǝɥʇ ʍoןǝq ɹo ǝʌoqɐ sʇɟɐɥs oʇ ʇɔǝuuoɔ puɐ˙˙", + "create.ponder.chain_conveyor.text_4": "uıɐɥɔ ǝɥʇ uo buıןןǝʌɐɹʇ ʇɹɐʇs oʇ ɥɔuǝɹʍ ɐ buıpןoɥ ʞɔıןɔ-ʇɥbıᴚ", + "create.ponder.chain_conveyor.text_5": "ʇı ʍoןןoɟ oʇ uıɐɥɔ ɐ spɹɐʍoʇ ǝɔɐɟ 'uoıʇɔunظ ɐ ʇⱯ", "create.ponder.chain_drive.header": "sǝʌıɹᗡ uıɐɥƆ ɥʇıʍ ǝɔɹoɟ ןɐuoıʇɐʇoɹ buıʎɐןǝᴚ", "create.ponder.chain_drive.text_1": "ʍoɹ ɐ uı ɹǝɥʇo ɥɔɐǝ oʇ uoıʇɐʇoɹ ʎɐןǝɹ sǝʌıɹᗡ uıɐɥƆ", "create.ponder.chain_drive.text_2": "uoıʇɔǝɹıp ǝɯɐs ǝɥʇ uı ǝʇɐʇoɹ ןןıʍ sıɥʇ ǝʞıן pǝʇɔǝuuoɔ sʇɟɐɥs ןןⱯ", @@ -2124,6 +2130,46 @@ "create.ponder.nixie_tube.text_1": "ɥʇbuǝɹʇs ןɐubıs ǝɥʇ ʎɐןdsıp ןןıʍ sǝqn⟘ ǝıxıN 'ǝuoʇspǝᴚ ʎq pǝɹǝʍod uǝɥM", "create.ponder.nixie_tube.text_2": "pǝʎɐןdsıp ǝq uɐɔ ʇxǝʇ ɯoʇsnɔ 'spɹɐoqdıןƆ uǝʇʇıɹʍ buıs∩", "create.ponder.nixie_tube.text_3": "ɹnoןoɔ ʎɐןdsıp ɹıǝɥʇ ǝbuɐɥɔ oʇ ǝʎᗡ ɥʇıʍ ʞɔıןƆ-ʇɥbıᴚ", + "create.ponder.package_frogport.header": "sʇɹodboɹℲ ɥʇıʍ sǝbɐʞɔɐd buıʇɹodsuɐɹ⟘", + "create.ponder.package_frogport.text_1": "ʎqɹɐǝu ʇɹodboɹℲ ǝɥʇ ǝɔɐןd puɐ ɹoʎǝʌuoƆ uıɐɥƆ ɐ ʞɔıןɔ-ʇɥbıᴚ", + "create.ponder.package_frogport.text_10": "ʞɹoʍʇǝu uıɐɥɔ ǝɥʇ uo boɹɟ buıɥɔʇɐɯ ɐ oʇ ɥʇɐd ɹıǝɥʇ puıɟ sǝbɐʞɔɐԀ", + "create.ponder.package_frogport.text_11": "ɹǝʇǝԀ", + "create.ponder.package_frogport.text_12": "ɹǝʇǝԀ →", + "create.ponder.package_frogport.text_13": "ɯǝɥʇ ʍoןǝq sǝıɹoʇuǝʌuı ɥʇıʍ ǝɔɐɟɹǝʇuı ʎןʇɔǝɹıp uɐɔ sʇɹodboɹℲ", + "create.ponder.package_frogport.text_14": "ʎןʇɔǝɹıp pǝddıɥs puɐ pǝʞɔɐd ǝq uɐɔ sɯǝʇı 'sɹǝbɐʞɔɐd ɥʇıʍ sʞɹoʍ sıɥ⟘", + "create.ponder.package_frogport.text_15": "ʇɹǝqןⱯ", + "create.ponder.package_frogport.text_16": "ɹǝʇǝԀ", + "create.ponder.package_frogport.text_17": ",ɹǝʇǝԀ, oʇ sǝbɐʞɔɐd sǝssǝɹppⱯ", + "create.ponder.package_frogport.text_18": "ssǝɹppɐ ɹıǝɥʇ ʇɔǝןןoɔ oʇ pɹɐoqdıןɔ ɐ ɥʇıʍ sʇɹodboɹℲ ʞɔıןɔ-ʇɥbıᴚ", + "create.ponder.package_frogport.text_19": "sI∩ ɹǝɥʇo uı sʇnduı ssǝɹppɐ ǝʇǝןdɯoɔ-oʇnɐ dןǝɥ uɐɔ sǝɯɐu pǝʇɔǝןןoɔ ɥʇıʍ spɹɐoqdıןƆ", + "create.ponder.package_frogport.text_2": "I∩ ʎɹoʇuǝʌuı ɹıǝɥʇ uı ǝɯɐu ɐ uǝʌıb ǝq uɐɔ ʎǝɥ⟘", + "create.ponder.package_frogport.text_3": "˙˙ǝɯɐu ʇuǝɹǝɟɟıp ɐ oʇ pǝssǝɹppɐ sı ǝbɐʞɔɐd ɐ ɟI", + "create.ponder.package_frogport.text_4": "ʇɹǝqןⱯ", + "create.ponder.package_frogport.text_5": "ɹǝʇǝԀ →", + "create.ponder.package_frogport.text_6": "ɹoʎǝʌuoɔ ǝɥʇ uo ǝbɐʞɔɐd ǝɥʇ ǝɔɐןd ןןıʍ ʇɹodboɹℲ ǝɥʇ˙˙", + "create.ponder.package_frogport.text_7": "uoıʇɐuıʇsǝp pıןɐʌ ou ǝʌɐɥ ʎǝɥʇ ɟı ǝɔɐןd uı uıds sǝbɐʞɔɐԀ", + "create.ponder.package_frogport.text_8": "ʞɹoʍʇǝu uıɐɥɔ ǝɥʇ uo ǝɹǝɥʍʎuɐ pǝppɐ ǝq uɐɔ sʇɹodboɹℲ ǝɹoW", + "create.ponder.package_frogport.text_9": "ɹǝʇǝԀ", + "create.ponder.packager.header": "sǝbɐʞɔɐd buıddɐɹʍun puɐ buıʇɐǝɹƆ", + "create.ponder.packager.text_1": "ʇǝbɹɐʇ pןnoɥs ʎǝɥʇ ʎɹoʇuǝʌuı ǝɥʇ oʇ ʇxǝu sɹǝbɐʞɔɐd ǝɔɐןԀ", + "create.ponder.packager.text_2": "ǝbɐʞɔɐd ɐ oʇuı ʎɹoʇuǝʌuı ǝɥʇ ɯoɹɟ sɯǝʇı ʞɔɐd ןןıʍ ʇı 'ɹǝʍod ǝuoʇspǝɹ uǝʌı⅁", + "create.ponder.packager.text_3": "ɯǝʇı ɹǝɥʇo ʎuɐ ǝʞıן pǝʇɹodsuɐɹʇ puɐ dn pǝʞɔıd ǝq uɐɔ ǝsǝɥ⟘", + "create.ponder.packager.text_4": "ʎɹoʇuǝʌuı ǝɥʇ oʇuı sʇuǝʇuoɔ ǝɥʇ buıʞɔɐdun 'pǝʎoɹʇsǝp ǝq ןןıʍ pǝʇɹǝsuı sǝbɐʞɔɐԀ", + "create.ponder.packager.text_5": "ןןnℲ", + "create.ponder.packager.text_6": "ʞɔɐdun ʎןןnɟ ʇouuɐɔ ʎǝɥʇ sǝbɐʞɔɐd ʇdǝɔɔɐ ʇou ןןıʍ sɹǝbɐʞɔɐԀ", + "create.ponder.packager_address.header": "ssǝɹppɐ uɐ ɥʇıʍ sǝbɐʞɔɐd buıʇnoᴚ", + "create.ponder.packager_address.text_1": "ǝsnoɥǝɹɐM", + "create.ponder.packager_address.text_10": "ʇןǝq ɐ oʇuo ʇɥbıɐɹʇs sǝbɐʞɔɐd dɐɹʍun uɐɔ sʍɐs ןɐɔıuɐɥɔǝɯ 'ssǝuʇɔɐdɯoɔ ɹoℲ", + "create.ponder.packager_address.text_11": "sǝıʇıןıqɐdɐɔ buıʇnoɹ ǝbɐʞɔɐd ǝʌɐɥ sǝxoqʇsoԀ puɐ sʇɹodboɹℲ 'sɹǝʇןıɟ ǝsoɥʇ ɯoɹɟ ǝpısⱯ", + "create.ponder.packager_address.text_12": "ɹnoıʌɐɥǝq ɹıǝɥʇ ʇnoqɐ ǝɹoɯ ʇno puıɟ oʇ ɯǝɥʇ ʇɔǝdsuI", + "create.ponder.packager_address.text_2": "˙˙ɹǝbɐʞɔɐd ɐ uo pǝɔɐןd sı ubıs ɐ uǝɥM", + "create.ponder.packager_address.text_3": "ǝsnoɥǝɹɐM →", + "create.ponder.packager_address.text_4": "ssǝɹppɐ ɹıǝɥʇ sɐ ʇxǝʇ ɟo ǝuıן uǝʇʇıɹʍ ǝɥʇ ʎɹɹɐɔ ןןıʍ sǝbɐʞɔɐd pǝʇɐǝɹƆ", + "create.ponder.packager_address.text_5": "ssǝɹppɐ ɹıǝɥʇ uo pǝsɐq sǝbɐʞɔɐd ǝʇnoɹ sɹǝʇןıɟ ǝbɐʞɔɐԀ", + "create.ponder.packager_address.text_6": "ǝsnoɥǝɹɐM →", + "create.ponder.packager_address.text_7": "ʎɹoʇɔɐℲ", + "create.ponder.packager_address.text_8": "ʎɹoʇɔɐℲ →", + "create.ponder.packager_address.text_9": "ʎɹoʇɔɐℲ", "create.ponder.piston_pole.header": "sǝןoԀ uoısuǝʇxƎ uoʇsıԀ", "create.ponder.piston_pole.text_1": "ǝʌoɯ ʇouuɐɔ uoʇsıԀ ןɐɔıuɐɥɔǝW ɐ 'sǝןoԀ pǝɥɔɐʇʇɐ ʇnoɥʇıM", "create.ponder.piston_pole.text_2": "ǝbuɐᴚ uoısuǝʇxƎ ǝɥʇ sǝuıɯɹǝʇǝp ʞɔɐq sʇı ʇɐ pǝppɐ ǝןod ɟo ɥʇbuǝꞀ ǝɥ⟘", @@ -2596,6 +2642,10 @@ "create.schedule.condition.unloaded.status": "pɐoןun ʞunɥɔ ɹoɟ buıʇıɐM", "create.schedule.condition_type": ":ɹǝʇɟɐ/ɟı ǝnuıʇuoƆ", "create.schedule.continued": "pǝɯnsǝɹ ǝןnpǝɥɔS", + "create.schedule.instruction.address_filter_edit_box": "ssǝɹppⱯ sıɥʇ ɥʇıʍ sǝbɐʞɔɐԀ ǝʌǝıɹʇǝᴚ", + "create.schedule.instruction.address_filter_edit_box_1": "pɹɐɔpןıʍ ʇxǝʇ ɐ sɐ * ǝs∩", + "create.schedule.instruction.address_filter_edit_box_2": "ʇı ʇɔǝןןoɔ oʇ ǝɹǝɥʍʎuɐ ǝʇɐbıʌɐu ʎɐɯ uıɐɹ⟘", + "create.schedule.instruction.address_filter_edit_box_3": "uɹnʇǝɹ ʇı ǝʞɐɯ oʇ uoıʇɔnɹʇsuı ɹǝɥʇouɐ ppⱯ", "create.schedule.instruction.destination": "uoıʇɐʇS oʇ ןǝʌɐɹ⟘", "create.schedule.instruction.destination.summary": ":doʇS ʇxǝN", "create.schedule.instruction.editor": "ɹoʇıpƎ uoıʇɔnɹʇsuI", @@ -2606,6 +2656,14 @@ "create.schedule.instruction.name_edit_box": "ǝןʇı⟘ ǝןnpǝɥɔS", "create.schedule.instruction.name_edit_box_1": "sʎɐןdsıp uo uʍoɥs ʇxǝʇ sʇɔǝɟɟⱯ", "create.schedule.instruction.name_edit_box_2": "ǝɯɐu s,uoıʇɐuıʇsǝp ʇxǝu oʇ sʇןnɐɟǝᗡ", + "create.schedule.instruction.package_delivery": "ǝbɐʞɔɐԀ ɹǝʌıןǝᗡ", + "create.schedule.instruction.package_delivery.summary": "obɹɐɔ uı ǝbɐʞɔɐd ʇsɹıɟ ɹǝʌıןǝᗡ", + "create.schedule.instruction.package_delivery.summary_1": "ɥʇıʍ uoıʇɐʇs ǝɥʇ oʇ sǝʌıɹᗡ", + "create.schedule.instruction.package_delivery.summary_2": "xoqʇsod ʇɔǝɹɹoɔ ǝɥʇ", + "create.schedule.instruction.package_retrieval": "ǝbɐʞɔɐԀ ǝʌǝıɹʇǝᴚ", + "create.schedule.instruction.package_retrieval.summary": ":oʇ pǝssǝɹppɐ ǝbɐʞɔɐd ɐ ɥɔʇǝℲ", + "create.schedule.instruction.package_retrieval.summary_1": "ɥʇıʍ xoqʇsod ɐ oʇ sǝʌıɹᗡ", + "create.schedule.instruction.package_retrieval.summary_2": "ǝbɐʞɔɐd pǝɹǝʌıןǝpun uɐ", "create.schedule.instruction.rename": "ǝןʇı⟘ ǝןnpǝɥɔS ǝʇɐpd∩", "create.schedule.instruction.rename.summary": ":ǝןʇı⟘ ʍǝN", "create.schedule.instruction.throttle": "pǝǝdS xɐW ʇıɯıꞀ", diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index af4a9663c2..852ed87650 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1692,6 +1692,12 @@ "create.ponder.cart_assembler_rails.text_2": "When on Powered or Controller Rail, the carts will be held in place until it's Powered", "create.ponder.cart_assembler_rails.text_3": "Other types of Minecarts can be used as the anchor", "create.ponder.cart_assembler_rails.text_4": "Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", + "create.ponder.chain_conveyor.header": "Relaying rotational force using Chain Conveyors", + "create.ponder.chain_conveyor.text_1": "Right-click two conveyors with chains to connect them", + "create.ponder.chain_conveyor.text_2": "These relay rotational power to each other very flexibly..", + "create.ponder.chain_conveyor.text_3": "..and connect to shafts above or below them", + "create.ponder.chain_conveyor.text_4": "Right-click holding a wrench to start travelling on the chain", + "create.ponder.chain_conveyor.text_5": "At a junction, face towards a chain to follow it", "create.ponder.chain_drive.header": "Relaying rotational force with Chain Drives", "create.ponder.chain_drive.text_1": "Chain Drives relay rotation to each other in a row", "create.ponder.chain_drive.text_2": "All shafts connected like this will rotate in the same direction", @@ -2124,6 +2130,46 @@ "create.ponder.nixie_tube.text_1": "When powered by Redstone, Nixie Tubes will display the signal strength", "create.ponder.nixie_tube.text_2": "Using written Clipboards, custom text can be displayed", "create.ponder.nixie_tube.text_3": "Right-Click with Dye to change their display colour", + "create.ponder.package_frogport.header": "Transporting packages with Frogports", + "create.ponder.package_frogport.text_1": "Right-click a Chain Conveyor and place the Frogport nearby", + "create.ponder.package_frogport.text_10": "Packages find their path to a matching frog on the chain network", + "create.ponder.package_frogport.text_11": "Peter", + "create.ponder.package_frogport.text_12": "→ Peter", + "create.ponder.package_frogport.text_13": "Frogports can directly interface with inventories below them", + "create.ponder.package_frogport.text_14": "This works with packagers, items can be packed and shipped directly", + "create.ponder.package_frogport.text_15": "Albert", + "create.ponder.package_frogport.text_16": "Peter", + "create.ponder.package_frogport.text_17": "Addresses packages to 'Peter'", + "create.ponder.package_frogport.text_18": "Right-click Frogports with a clipboard to collect their address", + "create.ponder.package_frogport.text_19": "Clipboards with collected names can help auto-complete address inputs in other UIs", + "create.ponder.package_frogport.text_2": "They can be given a name in their inventory UI", + "create.ponder.package_frogport.text_3": "If a package is addressed to a different name..", + "create.ponder.package_frogport.text_4": "Albert", + "create.ponder.package_frogport.text_5": "→ Peter", + "create.ponder.package_frogport.text_6": "..the Frogport will place the package on the conveyor", + "create.ponder.package_frogport.text_7": "Packages spin in place if they have no valid destination", + "create.ponder.package_frogport.text_8": "More Frogports can be added anywhere on the chain network", + "create.ponder.package_frogport.text_9": "Peter", + "create.ponder.packager.header": "Creating and unwrapping packages", + "create.ponder.packager.text_1": "Place packagers next to the inventory they should target", + "create.ponder.packager.text_2": "Given redstone power, it will pack items from the inventory into a package", + "create.ponder.packager.text_3": "These can be picked up and transported like any other item", + "create.ponder.packager.text_4": "Packages inserted will be destroyed, unpacking the contents into the inventory", + "create.ponder.packager.text_5": "Full", + "create.ponder.packager.text_6": "Packagers will not accept packages they cannot fully unpack", + "create.ponder.packager_address.header": "Routing packages with an address", + "create.ponder.packager_address.text_1": "Warehouse", + "create.ponder.packager_address.text_10": "For compactness, mechanical saws can unwrap packages straight onto a belt", + "create.ponder.packager_address.text_11": "Aside from those filters, Frogports and Postboxes have package routing capabilities", + "create.ponder.packager_address.text_12": "Inspect them to find out more about their behaviour", + "create.ponder.packager_address.text_2": "When a sign is placed on a packager..", + "create.ponder.packager_address.text_3": "→ Warehouse", + "create.ponder.packager_address.text_4": "Created packages will carry the written line of text as their address", + "create.ponder.packager_address.text_5": "Package filters route packages based on their address", + "create.ponder.packager_address.text_6": "→ Warehouse", + "create.ponder.packager_address.text_7": "Factory", + "create.ponder.packager_address.text_8": "→ Factory", + "create.ponder.packager_address.text_9": "Factory", "create.ponder.piston_pole.header": "Piston Extension Poles", "create.ponder.piston_pole.text_1": "Without attached Poles, a Mechanical Piston cannot move", "create.ponder.piston_pole.text_2": "The Length of pole added at its back determines the Extension Range", @@ -2596,6 +2642,10 @@ "create.schedule.condition.unloaded.status": "Waiting for chunk unload", "create.schedule.condition_type": "Continue if/after:", "create.schedule.continued": "Schedule resumed", + "create.schedule.instruction.address_filter_edit_box": "Retrieve Packages with this Address", + "create.schedule.instruction.address_filter_edit_box_1": "Use * as a text wildcard", + "create.schedule.instruction.address_filter_edit_box_2": "Train may navigate anywhere to collect it", + "create.schedule.instruction.address_filter_edit_box_3": "Add another instruction to make it return", "create.schedule.instruction.destination": "Travel to Station", "create.schedule.instruction.destination.summary": "Next Stop:", "create.schedule.instruction.editor": "Instruction Editor", @@ -2606,6 +2656,14 @@ "create.schedule.instruction.name_edit_box": "Schedule Title", "create.schedule.instruction.name_edit_box_1": "Affects text shown on displays", "create.schedule.instruction.name_edit_box_2": "Defaults to next destination's name", + "create.schedule.instruction.package_delivery": "Deliver Package", + "create.schedule.instruction.package_delivery.summary": "Deliver first package in cargo", + "create.schedule.instruction.package_delivery.summary_1": "Drives to the station with", + "create.schedule.instruction.package_delivery.summary_2": "the correct postbox", + "create.schedule.instruction.package_retrieval": "Retrieve Package", + "create.schedule.instruction.package_retrieval.summary": "Fetch a package addressed to:", + "create.schedule.instruction.package_retrieval.summary_1": "Drives to a postbox with", + "create.schedule.instruction.package_retrieval.summary_2": "an undelivered package", "create.schedule.instruction.rename": "Update Schedule Title", "create.schedule.instruction.rename.summary": "New Title:", "create.schedule.instruction.throttle": "Limit Max Speed", diff --git a/src/main/java/com/simibubi/create/content/trains/entity/TrainStatus.java b/src/main/java/com/simibubi/create/content/trains/entity/TrainStatus.java index 812334e51d..ee8f7c120b 100644 --- a/src/main/java/com/simibubi/create/content/trains/entity/TrainStatus.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/TrainStatus.java @@ -44,6 +44,13 @@ public class TrainStatus { displayInformation("no_match", false, filter); navigation = true; } + + public void failedPackageNoTarget(String address) { + if (navigation) + return; + displayInformation("no_package_target", false, address); + navigation = true; + } public void successfulNavigation() { if (!navigation) diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/Schedule.java b/src/main/java/com/simibubi/create/content/trains/schedule/Schedule.java index 324a1d72ed..b50407d4e6 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/Schedule.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/Schedule.java @@ -17,7 +17,9 @@ import com.simibubi.create.content.trains.schedule.condition.StationUnloadedCond import com.simibubi.create.content.trains.schedule.condition.TimeOfDayCondition; import com.simibubi.create.content.trains.schedule.destination.ChangeThrottleInstruction; import com.simibubi.create.content.trains.schedule.destination.ChangeTitleInstruction; +import com.simibubi.create.content.trains.schedule.destination.DeliverPackagesInstruction; import com.simibubi.create.content.trains.schedule.destination.DestinationInstruction; +import com.simibubi.create.content.trains.schedule.destination.FetchPackagesInstruction; import com.simibubi.create.content.trains.schedule.destination.ScheduleInstruction; import net.createmod.catnip.utility.NBTHelper; @@ -38,6 +40,8 @@ public class Schedule { static { registerInstruction("destination", DestinationInstruction::new); + registerInstruction("package_delivery", DeliverPackagesInstruction::new); + registerInstruction("package_retrieval", FetchPackagesInstruction::new); registerInstruction("rename", ChangeTitleInstruction::new); registerInstruction("throttle", ChangeThrottleInstruction::new); registerCondition("delay", ScheduledDelay::new); diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleRuntime.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleRuntime.java index b3e7c960fb..e0595c913a 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleRuntime.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleRuntime.java @@ -4,17 +4,14 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; -import java.util.regex.PatternSyntaxException; import com.simibubi.create.AllItems; import com.simibubi.create.content.trains.display.GlobalTrainDisplayData.TrainDeparturePrediction; import com.simibubi.create.content.trains.entity.Carriage; import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.content.trains.graph.DiscoveredPath; -import com.simibubi.create.content.trains.graph.EdgePointType; import com.simibubi.create.content.trains.schedule.condition.ScheduleWaitCondition; import com.simibubi.create.content.trains.schedule.condition.ScheduledDelay; -import com.simibubi.create.content.trains.schedule.destination.ChangeThrottleInstruction; import com.simibubi.create.content.trains.schedule.destination.ChangeTitleInstruction; import com.simibubi.create.content.trains.schedule.destination.DestinationInstruction; import com.simibubi.create.content.trains.schedule.destination.ScheduleInstruction; @@ -38,30 +35,35 @@ public class ScheduleRuntime { PRE_TRANSIT, IN_TRANSIT, POST_TRANSIT } - Train train; - Schedule schedule; + public Train train; + public Schedule schedule; public boolean isAutoSchedule; public boolean paused; public boolean completed; public int currentEntry; public State state; + + public List conditionProgress; + public List conditionContext; + public String currentTitle; - static final int INTERVAL = 40; - int cooldown; - List conditionProgress; - List conditionContext; - String currentTitle; - - int ticksInTransit; - List predictionTicks; + public int ticksInTransit; + public List predictionTicks; public boolean displayLinkUpdateRequested; + + private static final int INTERVAL = 40; + private int cooldown; public ScheduleRuntime(Train train) { this.train = train; reset(); } + + public void startCooldown() { + cooldown = INTERVAL; + } public void destinationReached() { if (state != State.IN_TRANSIT) @@ -142,7 +144,15 @@ public class ScheduleRuntime { } public void tickConditions(Level level) { - List> conditions = schedule.entries.get(currentEntry).conditions; + ScheduleEntry entry = schedule.entries.get(currentEntry); + List> conditions = entry.conditions; + + if (!entry.instruction.supportsConditions()) { + state = State.PRE_TRANSIT; + currentEntry++; + return; + } + for (int i = 0; i < conditions.size(); i++) { List list = conditions.get(i); int progress = conditionProgress.get(i); @@ -173,55 +183,7 @@ public class ScheduleRuntime { public DiscoveredPath startCurrentInstruction() { ScheduleEntry entry = schedule.entries.get(currentEntry); ScheduleInstruction instruction = entry.instruction; - - if (instruction instanceof DestinationInstruction destination) { - String regex = destination.getFilterForRegex(); - boolean anyMatch = false; - ArrayList validStations = new ArrayList<>(); - - if (!train.hasForwardConductor() && !train.hasBackwardConductor()) { - train.status.missingConductor(); - cooldown = INTERVAL; - return null; - } - - try { - for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) { - if (!globalStation.name.matches(regex)) - continue; - anyMatch = true; - validStations.add(globalStation); - } - } catch (PatternSyntaxException ignored) {} - - DiscoveredPath best = train.navigation.findPathTo(validStations, Double.MAX_VALUE); - if (best == null) { - if (anyMatch) - train.status.failedNavigation(); - else - train.status.failedNavigationNoTarget(destination.getFilter()); - cooldown = INTERVAL; - return null; - } - - return best; - } - - if (instruction instanceof ChangeTitleInstruction title) { - currentTitle = title.getScheduleTitle(); - state = State.PRE_TRANSIT; - currentEntry++; - return null; - } - - if (instruction instanceof ChangeThrottleInstruction throttle) { - train.throttle = throttle.getThrottle(); - state = State.PRE_TRANSIT; - currentEntry++; - return null; - } - - return null; + return instruction.start(this); } public void setSchedule(Schedule schedule, boolean auto) { diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java index 253de2337f..ee453212e1 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java @@ -57,6 +57,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Mth; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.phys.Vec3; @@ -991,8 +992,15 @@ public class ScheduleScreen extends AbstractSimiContainerScreen im for (int i = 0; i < Math.max(1, rendered.slotsTargeted()); i++) { List secondLineTooltip = rendered.getSecondLineTooltip(i); - if (secondLineTooltip == null || (hoveredSlot != menu.getSlot(36 + i) || !hoveredSlot.getItem() - .isEmpty())) + if (secondLineTooltip == null) + continue; + Slot slot = menu.getSlot(36 + i); + if (slot == null || !slot.getItem() + .isEmpty()) + continue; + if (mouseX < leftPos + slot.x || mouseX > leftPos + slot.x + 18) + continue; + if (mouseY < topPos + slot.y || mouseY > topPos + slot.y + 18) continue; renderActionTooltip(graphics, secondLineTooltip, mouseX, mouseY); } diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeThrottleInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeThrottleInstruction.java index bafa5b3d1e..9459fa79bc 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeThrottleInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeThrottleInstruction.java @@ -2,9 +2,14 @@ package com.simibubi.create.content.trains.schedule.destination; import java.util.List; +import javax.annotation.Nullable; + import com.google.common.collect.ImmutableList; import com.simibubi.create.AllBlocks; import com.simibubi.create.Create; +import com.simibubi.create.content.trains.graph.DiscoveredPath; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -83,4 +88,13 @@ public class ChangeThrottleInstruction extends ScheduleInstruction { .withStyle(ChatFormatting.GRAY)); } + @Override + @Nullable + public DiscoveredPath start(ScheduleRuntime runtime) { + runtime.train.throttle = getThrottle(); + runtime.state = State.PRE_TRANSIT; + runtime.currentEntry++; + return null; + } + } diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeTitleInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeTitleInstruction.java index f0e726cc49..efbce32038 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeTitleInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeTitleInstruction.java @@ -2,8 +2,13 @@ package com.simibubi.create.content.trains.schedule.destination; import java.util.List; +import javax.annotation.Nullable; + import com.google.common.collect.ImmutableList; import com.simibubi.create.Create; +import com.simibubi.create.content.trains.graph.DiscoveredPath; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Pair; @@ -53,4 +58,13 @@ public class ChangeTitleInstruction extends TextScheduleInstruction { .withStyle(ChatFormatting.DARK_GRAY)); } + @Override + @Nullable + public DiscoveredPath start(ScheduleRuntime runtime) { + runtime.currentTitle = getScheduleTitle(); + runtime.state = State.PRE_TRANSIT; + runtime.currentEntry++; + return null; + } + } diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/DeliverPackagesInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DeliverPackagesInstruction.java new file mode 100644 index 0000000000..c48f87c1f0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DeliverPackagesInstruction.java @@ -0,0 +1,126 @@ +package com.simibubi.create.content.trains.schedule.destination; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +import javax.annotation.Nullable; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.Create; +import com.simibubi.create.content.logistics.box.PackageItem; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.graph.DiscoveredPath; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.content.trains.station.GlobalStation.GlobalPackagePort; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.Pair; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.IItemHandlerModifiable; + +public class DeliverPackagesInstruction extends ScheduleInstruction { + + @Override + public Pair getSummary() { + return Pair.of(getSecondLineIcon(), CreateLang.translateDirect("schedule.instruction.package_delivery")); + } + + @Override + public ItemStack getSecondLineIcon() { + return AllBlocks.PACKAGE_POSTBOXES.get(DyeColor.WHITE) + .asStack(); + } + + @Override + public List getTitleAs(String type) { + return ImmutableList.of(CreateLang.translate("schedule.instruction.package_delivery.summary") + .style(ChatFormatting.GOLD) + .component(), + CreateLang.translateDirect("schedule.instruction.package_delivery.summary_1") + .withStyle(ChatFormatting.GRAY), + CreateLang.translateDirect("schedule.instruction.package_delivery.summary_2") + .withStyle(ChatFormatting.GRAY)); + } + + @Override + public ResourceLocation getId() { + return Create.asResource("package_delivery"); + } + + @Override + public boolean supportsConditions() { + return true; + } + + @Override + @Nullable + public DiscoveredPath start(ScheduleRuntime runtime) { + boolean anyMatch = false; + String firstPackage = null; + ArrayList validStations = new ArrayList<>(); + Train train = runtime.train; + + if (!train.hasForwardConductor() && !train.hasBackwardConductor()) { + train.status.missingConductor(); + runtime.startCooldown(); + return null; + } + + for (Carriage carriage : train.carriages) { + IItemHandlerModifiable carriageInventory = carriage.storage.getItems(); + if (carriageInventory == null) + continue; + + // Export to station + for (int slot = 0; slot < carriageInventory.getSlots(); slot++) { + ItemStack stack = carriageInventory.getStackInSlot(slot); + if (!PackageItem.isPackage(stack)) + continue; + if (firstPackage == null) + firstPackage = PackageItem.getAddress(stack); + for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) { + for (Entry port : globalStation.connectedPorts.entrySet()) { + if (!PackageItem.matchAddress(stack, port.getValue().address)) + continue; + anyMatch = true; + validStations.add(globalStation); + break; + } + } + } + } + + if (validStations.isEmpty()) { + if (firstPackage != null) { + train.status.failedPackageNoTarget(firstPackage); + runtime.startCooldown(); + } else { + runtime.state = State.PRE_TRANSIT; + runtime.currentEntry++; + } + return null; + } + + DiscoveredPath best = train.navigation.findPathTo(validStations, Double.MAX_VALUE); + if (best == null) { + if (anyMatch) + train.status.failedNavigation(); + runtime.startCooldown(); + return null; + } + + return best; + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java index b68c3d1587..10130ca88a 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java @@ -1,12 +1,21 @@ package com.simibubi.create.content.trains.schedule.destination; +import java.util.ArrayList; import java.util.List; +import java.util.regex.PatternSyntaxException; + +import javax.annotation.Nullable; import org.apache.commons.lang3.StringUtils; import com.google.common.collect.ImmutableList; import com.simibubi.create.AllBlocks; import com.simibubi.create.Create; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.graph.DiscoveredPath; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime; +import com.simibubi.create.content.trains.station.GlobalStation; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Pair; @@ -69,4 +78,40 @@ public class DestinationInstruction extends TextScheduleInstruction { box.setFilter(s -> StringUtils.countMatches(s, '*') <= 3); } + @Override + @Nullable + public DiscoveredPath start(ScheduleRuntime runtime) { + String regex = getFilterForRegex(); + boolean anyMatch = false; + ArrayList validStations = new ArrayList<>(); + Train train = runtime.train; + + if (!train.hasForwardConductor() && !train.hasBackwardConductor()) { + train.status.missingConductor(); + runtime.startCooldown(); + return null; + } + + try { + for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) { + if (!globalStation.name.matches(regex)) + continue; + anyMatch = true; + validStations.add(globalStation); + } + } catch (PatternSyntaxException ignored) {} + + DiscoveredPath best = train.navigation.findPathTo(validStations, Double.MAX_VALUE); + if (best == null) { + if (anyMatch) + train.status.failedNavigation(); + else + train.status.failedNavigationNoTarget(getFilter()); + runtime.startCooldown(); + return null; + } + + return best; + } + } diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/FetchPackagesInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/FetchPackagesInstruction.java new file mode 100644 index 0000000000..b214c58e3e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/FetchPackagesInstruction.java @@ -0,0 +1,170 @@ +package com.simibubi.create.content.trains.schedule.destination; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import java.util.regex.PatternSyntaxException; + +import org.apache.commons.lang3.StringUtils; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.Create; +import com.simibubi.create.content.logistics.box.PackageItem; +import com.simibubi.create.content.logistics.box.PackageStyles; +import com.simibubi.create.content.logistics.packagePort.postbox.PostboxBlockEntity; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.graph.DiscoveredPath; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.content.trains.station.GlobalStation.GlobalPackagePort; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.items.IItemHandlerModifiable; + +public class FetchPackagesInstruction extends TextScheduleInstruction { + + @Override + public Pair getSummary() { + return Pair.of(getSecondLineIcon(), CreateLang.translateDirect("schedule.instruction.package_retrieval")); + } + + @Override + public List getTitleAs(String type) { + return ImmutableList.of(CreateLang.translate("schedule.instruction.package_retrieval.summary") + .style(ChatFormatting.GOLD) + .component(), CreateLang.translateDirect("generic.in_quotes", Components.literal(getLabelText())), + CreateLang.translateDirect("schedule.instruction.package_retrieval.summary_1") + .withStyle(ChatFormatting.GRAY), + CreateLang.translateDirect("schedule.instruction.package_retrieval.summary_2") + .withStyle(ChatFormatting.GRAY)); + } + + @Override + public ItemStack getSecondLineIcon() { + return PackageStyles.getDefaultBox(); + } + + public String getFilter() { + return getLabelText(); + } + + public String getFilterForRegex() { + String filter = getFilter(); + if (filter.isBlank()) + return filter; + return "\\Q" + filter.replace("*", "\\E.*\\Q") + "\\E"; + } + + @Override + public List getSecondLineTooltip(int slot) { + return ImmutableList.of(CreateLang.translateDirect("schedule.instruction.address_filter_edit_box"), + CreateLang.translateDirect("schedule.instruction.address_filter_edit_box_1") + .withStyle(ChatFormatting.GRAY), + CreateLang.translateDirect("schedule.instruction.address_filter_edit_box_2") + .withStyle(ChatFormatting.DARK_GRAY), + CreateLang.translateDirect("schedule.instruction.address_filter_edit_box_3") + .withStyle(ChatFormatting.DARK_GRAY)); + } + + @Override + @OnlyIn(Dist.CLIENT) + protected void modifyEditBox(EditBox box) { + box.setFilter(s -> StringUtils.countMatches(s, '*') <= 3); + } + + @Override + public ResourceLocation getId() { + return Create.asResource("package_retrieval"); + } + + @Override + public boolean supportsConditions() { + return false; + } + + @Override + public DiscoveredPath start(ScheduleRuntime runtime) { + String regex = getFilterForRegex(); + boolean anyMatch = false; + ArrayList validStations = new ArrayList<>(); + Train train = runtime.train; + + if (!train.hasForwardConductor() && !train.hasBackwardConductor()) { + train.status.missingConductor(); + runtime.startCooldown(); + return null; + } + + Level level = null; + for (Carriage carriage : train.carriages) { + if (level == null) { + CarriageContraptionEntity entity = carriage.anyAvailableEntity(); + if (entity != null && entity.level() instanceof ServerLevel sl) + level = sl; + } + } + + for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) { + for (Entry entry : globalStation.connectedPorts.entrySet()) { + GlobalPackagePort port = entry.getValue(); + BlockPos pos = entry.getKey(); + + IItemHandlerModifiable postboxInventory = port.offlineBuffer; + if (level != null && level.isLoaded(pos) + && level.getBlockEntity(pos) instanceof PostboxBlockEntity ppbe) { + postboxInventory = ppbe.inventory; + } + + for (int slot = 0; slot < postboxInventory.getSlots(); slot++) { + ItemStack stack = postboxInventory.getStackInSlot(slot); + if (!PackageItem.isPackage(stack)) + continue; + if (PackageItem.matchAddress(stack, port.address)) + continue; + try { + if (!PackageItem.getAddress(stack) + .matches(regex)) + continue; + anyMatch = true; + validStations.add(globalStation); + } catch (PatternSyntaxException ignored) { + } + } + } + } + + if (validStations.isEmpty()) { + runtime.startCooldown(); + runtime.state = State.PRE_TRANSIT; + runtime.currentEntry++; + return null; + } + + DiscoveredPath best = train.navigation.findPathTo(validStations, Double.MAX_VALUE); + if (best == null) { + if (anyMatch) + train.status.failedNavigation(); + runtime.startCooldown(); + return null; + } + + return best; + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java index fdd98715e2..533d1a67e5 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java @@ -2,9 +2,13 @@ package com.simibubi.create.content.trains.schedule.destination; import java.util.function.Supplier; +import javax.annotation.Nullable; + import com.simibubi.create.Create; +import com.simibubi.create.content.trains.graph.DiscoveredPath; import com.simibubi.create.content.trains.schedule.Schedule; import com.simibubi.create.content.trains.schedule.ScheduleDataEntry; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime; import net.createmod.catnip.utility.Pair; import net.minecraft.nbt.CompoundTag; @@ -13,6 +17,9 @@ import net.minecraft.resources.ResourceLocation; public abstract class ScheduleInstruction extends ScheduleDataEntry { public abstract boolean supportsConditions(); + + @Nullable + public abstract DiscoveredPath start(ScheduleRuntime runtime); public final CompoundTag write() { CompoundTag tag = new CompoundTag(); diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index 2ec46b6a36..f40f23f9f4 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -790,6 +790,20 @@ "create.schedule.instruction.throttle.summary": "Change Max Speed to %1$s", "create.schedule.instruction.throttle_edit_box": "Throttle", "create.schedule.instruction.throttle_edit_box_1": "Affects the top speed of the Train", + + "create.schedule.instruction.package_delivery": "Deliver Package", + "create.schedule.instruction.package_delivery.summary": "Deliver first package in cargo", + "create.schedule.instruction.package_delivery.summary_1": "Drives to the station with", + "create.schedule.instruction.package_delivery.summary_2": "the correct postbox", + + "create.schedule.instruction.package_retrieval": "Retrieve Package", + "create.schedule.instruction.package_retrieval.summary": "Fetch a package addressed to:", + "create.schedule.instruction.package_retrieval.summary_1": "Drives to a postbox with", + "create.schedule.instruction.package_retrieval.summary_2": "an undelivered package", + "create.schedule.instruction.address_filter_edit_box": "Retrieve Packages with this Address", + "create.schedule.instruction.address_filter_edit_box_1": "Use * as a text wildcard", + "create.schedule.instruction.address_filter_edit_box_2": "Train may navigate anywhere to collect it", + "create.schedule.instruction.address_filter_edit_box_3": "Add another instruction to make it return", "create.schedule.condition_type": "Continue if/after:", "create.schedule.condition.editor": "Condition Editor", From db352dfa09048de836e3797266766fa7ce077a93 Mon Sep 17 00:00:00 2001 From: Kryppers <65094918+Kryppers@users.noreply.github.com> Date: Sat, 11 Jan 2025 22:08:36 +0000 Subject: [PATCH 3/8] rare package updates added rare_evan. Updated textures for rare_up and rare_darcy --- .../textures/item/package/rare_darcy.png | Bin 1100 -> 1119 bytes .../textures/item/package/rare_evan.png | Bin 0 -> 987 bytes .../create/textures/item/package/rare_up.png | Bin 981 -> 952 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/resources/assets/create/textures/item/package/rare_evan.png diff --git a/src/main/resources/assets/create/textures/item/package/rare_darcy.png b/src/main/resources/assets/create/textures/item/package/rare_darcy.png index 30ee855168afe04150ac6828cc84fa61bc9f408e..e579dec23f783e7716d3d7aadc56245b5f2aac8e 100644 GIT binary patch delta 1033 zcmV+k1or#P2;T^hBo78+OGiWiHvl&PH*?#G^N}GS2n!G&HIOkUmXS#)f5%BgK~z}7 z-B(X&6KNFxH8YdU*p5xoKeRTYT`Or*gHV=*iVL!bJt%k(6ch!)dJs`$>BW=iMbIMb z#e?i&1^42D2dRSKA+VsHv^7+1EsDk3GA{j+&LlIFWZFF>^O^Y{+oG@!hHt+2&CK`S z@4fe%_W|Eon#`N*-8R^EB9Vw? zEEEbGhCs*xNmJD^mgBxj2w1z~)8fClbMFBzogX z%sUW5aAtoJ8ku(up#y;}UF`q>qf&8f(z~t4(-T49p{g1rNrI|se=u}~u9YhW)#q|~ z)EgRd`&j=E2~VAyVf7LYM*skNse)K6=2&M~);|Z@wkC1(#E9dCqbEkt(z*SsV{95> z8s?b;qqm-*Srk!_#{mFEMZu<)7SGX3>>k?1jvz&#s3<7NGMYsZMMXhJcen58$q~iE zR~bgNS5NO3#^;o#`BZw^GlEP%3Oy;RcO4d~t0 zgRzlzy3o`A6CO?y5JGSuEu!%GJza~(4CBv)Z(hAZYb;u=OGCe=vu0p({We@Gg2CLjM3* zhC#(Ju$<2amZ2$x5CCm72kapTd1Yzh#Rbeu2IeILFMdBu^+7z~+}!$IUj*D_UaDYj z(ZE1Jd8w)fLEtINF_9Jk5&(c>8APM47RC%T;L*wvC@=rS+@gWhu~VK&WXj!p<4ANy z>okuc0uTW_f4KY1^6W<`=WT!)t1Vsa`1H$3q-qtS>$)!jiOwiZ;5GdXM{hl`uw9iE z<=Xro2OGMHu6=;h_KxapkhE4300000NkvXXu0mjf Dtp@AU delta 1042 zcmV+t1nv9Z2+RnOBqa%ONLh0L04^f{04^f|c%?sf00007bV*G`2k8L_6bCE)nT4K_ zTPT0VNklEEpd| z6p_62skASJDuurIAbqHyFBXJIEJ_4}fgrv}TPh6|3&F%NmfT(E@6OIn(udu-&fncx zV`!lVE@$T4`8nr1=X`Sp_>ZN-KltsZFV}w+MQ-aR+ol-%=&O#+a6t4AR##V1C=@^` zg)GZVJC1`~E*H|KX>J+cFONl9rA+U9@4*=lR>#>)NY#-)Eq9`(Kn?lnx*fxKK z=NN3yt$WN~sZ_}-Z+on(ynX#OZ>jIzw03=aBKHnW;%v1;NtbGjQ*B`OC;-UQM z32qVja{b0MiUaw8=4IsS|U&!$g=|8 z(ARMC@_dNx8my={&*x%nm?RE;1#O0d)|%(>nJ~z9rmnYS!^GB;WwsW(Ro%wy>}(@O#lD@ diff --git a/src/main/resources/assets/create/textures/item/package/rare_evan.png b/src/main/resources/assets/create/textures/item/package/rare_evan.png new file mode 100644 index 0000000000000000000000000000000000000000..59aecc320cf9b5fb8ab2324e97c279e63dc36b0e GIT binary patch literal 987 zcmV<110?*3P)ZE6D>zlEsN4Vm187M^ zK~z}7)t66e+(sD2f7YL!U2NAIK}@I}ichu!z4lP@0Rlam-g@h)6hrBuNe?BI9s+^% zV)_9Jg@gq6)ZR)0A=jJ&rnCXm)(&MCYqgt|HM1+NdsvSwX-8T+b}4-?TFt!DJny6D zeP$N^T}_MXe?PP=j$^qWZZ!+sToh2jIN*HcuYhqrLic;(_++Q=UAy z$L!@5BY?8b(Lgk?N)5!lR~)p*sxL;^-X#`-e!pKSs$zwr<}i$t^uEYo%0TyZ1i)aR zatZo@?6}S~MRXXR3Yd`r-}e~~6NW>7T=j9kg<+T*uL@1Is5wMZp$0LQb>dmY0-bCJ zD0MQqwDw-wM!`Xwu)Ukkd7f7aU@$l~u0cG(q+{FFPWbE24hxr><37H;!ayAo9JJ{K zK7YRaeN2BRVC~wqsZ3}F$`~?!g7>dqCr%O^+oo1?xzzNSpKAafjkR?g+a^vDdfl#Z zpZMf6dtw1CLal+~Cz$YotV-kFtBLV4A6T?!*xnjVicieto~vXa8=d{%5JK?x?hZnT zQWfji*tBvEXNx(c>Hy$6HqGV&0F6eSD3a3wn3yq%NXNq;e`0yDnHl*7faiwXy;e{T zU|OYRvAoz!1^mXlVO3k5CX_s()+%9Zlq6;V-PaMGcS3d5!eve<>ho^0LEZF}}I~{EhyqS<~FDxPMPO6P{}?Fr5j{;)MUp_y-9A(HhYTwC4Z-002ov JPDHLkV1lec&!_+Z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/item/package/rare_up.png b/src/main/resources/assets/create/textures/item/package/rare_up.png index 032272266be2c64c7e2e1a269ed33bc9b6af08ed..18c20406b95ddb97d7f445f04564f40cc323a073 100644 GIT binary patch delta 930 zcmV;T16};p2e=22B!32COGiWiHvl&PH*?#G^8f$<32;bRa{vGf6951U69E94oEQKA z00(qQO+^Rk0SgcxIPQR3D*ylkMM*?KR9M5^S4(RXQ560 znP( zP1jLya>6PgHPnx=W5i3c?=v%@GqIuTph&X05}JxvEdE3+7PoAxO6W&Ar=Rfam0y5% z6Pt0JEg;$r*lIy0nVs<{FV=hYDvZ3cEMxH~$Vv?yqQWNd8zXZ)dh!$leO#zmn_01W z0p0y0sDI?waU?Z{Vo8FMTMI;HppV1BZmwnIsGyTl@ubTigoGm3p(T8Ztr~`R0lP&B z=?|~0Q;bh0Q4j?HJPM+K@9B@V_X;8sgDKD8G!sHcA`!@b92gxNv-Sm1Kqgn~RVF7Q zk*J}ONF+U_c=X~`=teaZ>RMM9p-4H)(TZK z5RH%^qX$6frRGYwxUhujnJK(~n?`mkhj>pM7cPzaDq$ukf~FNWFBIoqf}%+NBuuZY zp^&eSNp>rT>6s}kE-VGZ+RH(!)^*K1aU&WgB7B_oFThOr^4Xgjv~;-3>B{TpU>dJl z0e@2<2MH0^%h^t=DO%`4_B;guaQf^BXqtxpXI?K~I}ZSuymF>#Y*Pmal0?-oTqrm- zz*h-Zmp>!Fy;HyOcCnZ^H`-KQ_eF|TRl&)LVXQ6#`RyIBU983ap!Hz>U0Z+EY)Z)U z^#{WzjsgINjva34PPnJv0_UADd9(+WiW}m(BmP(GHvp%dzwq$B3IG5A07*qoM6N<$ Ef>MZ{W&i*H delta 959 zcmV;w13>(^2h|6VB!2;OQb$4nuFf3k000AZNklIN!rcU zB%R%4H~J7}vzOV6wIKMxawcbI&-v!eIcFxoKSm21yq&rAOMg-1SRYZUozA&~+WMEZfpB3=l$GvQnw+hi?Et!mDU$X)H`kCil%r7(}n)aPLXzdKG5z zt4n{dBL`WQU~Yco8rtg?`XaFX^#i6R@A*EOn!JZ{{&S#FMUg?Nj(k23N_A-3j!QcA zPNF^n0I>RL1Amrj`g8z%dM_l200630!zCF6(H(Rjf$u-I0*$Y&e+zXUhnN?>95|9m z;pUBNFpLIs#`yZx38YeOD3{Bjj=U@MI`&4;j=)Zdat-oA9yAvK=q|rRy~G$?T2)n1 zt68YkQ~)0|)h=Smo@9TuD zQEHf z&Z96%9XZ6W4Gx0Jh~dHGS@d+KW7*osYtaPSyH8+uYaPdOeJGVFjKW%IWO_Q&IMg1G zfD=9f&VQAPZCyTnSR@R+8QMeu*}7%%3G9?8R^Khzt2lGM3q?%@kU>#X@n!XWV_s21 zwl~K$PUIMUB$tC+s|!cF5-b@;YHMQHLP4!m93~T5E<`N`E%CqFS>cB?So50VK@kfyV8Gi*qX& z8a)d_2<}h6#8E}Ee+PBK&4LC(44>XGykiQ(XhzW2h^8Md*yHCcAuufqBbNtZ7=|sQ!1_Q!5Ky-) zUlhDO0C5f@c6z;3rDx&{oVY66{c7r`Lr`{aBn^ z!T8t!w+ik|z1h=Wwa7c6^ZXvUJQzB6FF1(26Y}ne{}p}%)qcV)H1?D20000EWmrjO hO-%qQ00008000000002eQ Date: Sat, 11 Jan 2025 22:10:20 +0000 Subject: [PATCH 4/8] sent the wrong one! fixed rare_evan version --- .../create/textures/item/package/rare_evan.png | Bin 987 -> 1003 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/create/textures/item/package/rare_evan.png b/src/main/resources/assets/create/textures/item/package/rare_evan.png index 59aecc320cf9b5fb8ab2324e97c279e63dc36b0e..dad9b0bc6a2d5ee6e6cc35c368d150124852d669 100644 GIT binary patch delta 932 zcmV;V16%yt2kQrrRevl7+lnKw000AcNkl`-f z*-q)ThmuoIfznG&|AtbEY006q5HO{OLLj}E{s)DG1pCz9N&+F*oI*^~1PrMi$}ZMw z*SnTRt6BB1kt}IPT01s`zKd2fPnz$2`rbFQ@RnmL{_*7AMt`)mIi#r~uKzHtP5$NQ zKJ(@jYwHFde(~efc>u8DACBYjqCX3O=lS@)Ppwu%N{J8xDJ5OspbI#Td;Sc3zWhNH zcteOHOkr?iyc*-LHRu0;^KVBt9FuV8YF> zKV@#V&i0p2Gk^0>?rlW%dM&x1zO>B#-ajlXUPj3tetSQe^E^NKghu)$OYbiL@aWoo zR2XI!cy#SP0GAgpX)D><9P-=EBbv=7p68=vkD90gFbGvL?z$b)K#ly1d|$$V7}DrpL=7rdm`jJYOP%5W_g`*nELjx&x#3!TOn&fEn$CQeehP6H?HgmW{Zy{4P9;_}==0P%ux zFO>fU;Y0pf@N0000!}n&>7hvvC6pclf%Ibf0SbkL1ozb5N&+F*oC2n_0n^qFWfyC; zo0T=QE3JE2k1T0NT03?reJ@(gywW`Hqvw5Q7XIUy(LY{1x_^DNy)~kh9P#;=v&Q6a z?}RMcGi+>Hy!+wTGZz8C(La3O=Vdq#Kom)&l+^2Wlu`&GP)gC07CpfCg9~H8$==+& zT}_MXe?PP=j$^ zqWZZ!+sToh2jIN*HcuYhqrLic;(_++Q=UAy$L!@5BY%Lh&e1?Luu2WYy;mHx$Eq(z z*xn@;f_}eWDXLHAQq7o(h&^}fmzv`~zP!Rf9TFV0=>$H1zWjYmep{GJb;h zuU{ul5**v6R&%-3^q8M(03MCCbsXC!P7-?Eu5q9E0WCtUf#N5a@PVvK1Vlsuu< zDq(AsBxV5J*Abp~LUq-`WlkvS_30>G7g?qO-}fh+&*Y3%3|O|!C`l$5C{}KC!mNs` z!hg$DU}V5`jg_ZczKH?f_whV0cLprGmNB6o^0LEZF}}I~{EhyqS<~FD qxPMPO6P{}?Fr5j{;)MUp_y-9A(HhYTv<>F~0000 Date: Fri, 6 Dec 2024 15:05:08 -0800 Subject: [PATCH 5/8] Cheap perf - Replace SmartBlockEntity#behaviours with a Reference2ObjectArrayMap for faster iteration and because BehaviorTypes are unique by reference - SmartBlockEntityTicker#tick improvements - Client: 9% of all -> 7% of all - Server: 12% of all -> 10% of all --- .../create/foundation/blockEntity/SmartBlockEntity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntity.java b/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntity.java index c41ee270cd..ff896640c4 100644 --- a/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntity.java +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntity.java @@ -2,7 +2,6 @@ package com.simibubi.create.foundation.blockEntity; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -17,6 +16,7 @@ import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour import com.simibubi.create.foundation.utility.IInteractionChecker; import com.simibubi.create.api.schematic.nbt.IPartialSafeNBT; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.createmod.ponder.api.VirtualBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -31,7 +31,7 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities; public abstract class SmartBlockEntity extends CachedRenderBBBlockEntity implements IPartialSafeNBT, IInteractionChecker, ISpecialBlockEntityItemRequirement, VirtualBlockEntity { - private final Map, BlockEntityBehaviour> behaviours = new HashMap<>(); + private final Map, BlockEntityBehaviour> behaviours = new Reference2ObjectArrayMap<>(); private boolean initialized = false; private boolean firstNbtRead = true; protected int lazyTickRate; From 1fbfeb6f006f1c6ea3b596cd4ff68b668b8bc64d Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sat, 11 Jan 2025 20:33:53 -0800 Subject: [PATCH 6/8] Lily pad manners - Fix the package/rigging initially appearing inside the frog's mouth when it's retrieving a package - Lazily update the body/head/tongue so we don't have to upload it every frame when not animating --- .../packagePort/frogport/FrogportVisual.java | 76 ++++++++++++------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/logistics/packagePort/frogport/FrogportVisual.java b/src/main/java/com/simibubi/create/content/logistics/packagePort/frogport/FrogportVisual.java index 776ea2d2ea..b2a4126b96 100644 --- a/src/main/java/com/simibubi/create/content/logistics/packagePort/frogport/FrogportVisual.java +++ b/src/main/java/com/simibubi/create/content/logistics/packagePort/frogport/FrogportVisual.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.packagePort.frogport; import java.util.function.Consumer; import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; import com.simibubi.create.AllPartialModels; @@ -17,6 +18,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.phys.Vec3; + import net.minecraftforge.registries.ForgeRegistries; public class FrogportVisual extends AbstractBlockEntityVisual implements SimpleDynamicVisual { @@ -26,6 +28,12 @@ public class FrogportVisual extends AbstractBlockEntityVisual 0 ? (float) Math.max(0, 1 - Math.pow((anticipation * 1.25) * 2 - 1, 4)) : 0; + rig.handle() + .setVisible(false); + box.handle() + .setVisible(false); } headPitch *= headPitchModifier; headPitch = Math.max(headPitch, blockEntity.manualOpenAnimationProgress.getValue(partialTicks) * 60); tongueLength = Math.max(tongueLength, blockEntity.manualOpenAnimationProgress.getValue(partialTicks) * 0.25f); - - body.setIdentityTransform() - .translate(getVisualPosition()) - .center() - .rotateYDegrees(yaw) - .uncenter() - .setChanged(); - head.setIdentityTransform() - .translate(getVisualPosition()) - .center() - .rotateYDegrees(yaw) - .uncenter() - .translate(8 / 16f, 10 / 16f, 11 / 16f) - .rotateXDegrees(headPitch) - .translateBack(8 / 16f, 10 / 16f, 11 / 16f) - .setChanged(); + if (yaw != lastYaw) { + body.setIdentityTransform() + .translate(getVisualPosition()) + .center() + .rotateYDegrees(yaw) + .uncenter() + .setChanged(); - tongue.setIdentityTransform() - .translate(getVisualPosition()) - .center() - .rotateYDegrees(yaw) - .uncenter() - .translate(8 / 16f, 10 / 16f, 11 / 16f) - .rotateXDegrees(tonguePitch) - .scale(1f, 1f, tongueLength / (7 / 16f)) - .translateBack(8 / 16f, 10 / 16f, 11 / 16f) - .setChanged(); + // Save the base pose to avoid recalculating it twice every frame + basePose.set(body.pose) + .translate(8 / 16f, 10 / 16f, 11 / 16f); + + // I'm not entirely sure that yaw ever changes + lastYaw = yaw; + + // Force the head and tongue to update + lastTonguePitch = Float.NaN; + lastHeadPitch = Float.NaN; + } + + if (headPitch != lastHeadPitch) { + head.setTransform(basePose) + .rotateXDegrees(headPitch) + .translateBack(8 / 16f, 10 / 16f, 11 / 16f) + .setChanged(); + + lastHeadPitch = headPitch; + } + + if (tonguePitch != lastTonguePitch || tongueLength != lastTongueLength) { + tongue.setTransform(basePose) + .rotateXDegrees(tonguePitch) + .scale(1f, 1f, tongueLength / (7 / 16f)) + .translateBack(8 / 16f, 10 / 16f, 11 / 16f) + .setChanged(); + + lastTonguePitch = tonguePitch; + lastTongueLength = tongueLength; + } } private void renderPackage(Vec3 diff, float scale, float itemDistance) { From b2891263d65ea2cd2a39dd504563a361fd5cb25f Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sat, 11 Jan 2025 23:04:01 -0800 Subject: [PATCH 7/8] Accretion - Combine rotating/actor instance types - Preference towards actor, but the arbitrary pivot was never used - Inline KineticInstance - Remove magic 3/10 constant in rotating shader, instead use renderSeconds and multiply by 6 ahead of time - Now the rotational speed is in degrees per second --- .../base/KineticBlockEntityVisual.java | 10 +-- .../kinetics/base/KineticInstance.java | 69 ------------------ .../kinetics/base/RotatingInstance.java | 73 ++++++++++++++++++- .../content/kinetics/belt/BeltVisual.java | 3 +- .../kinetics/drill/DrillActorVisual.java | 23 +++--- .../kinetics/gearbox/GearboxVisual.java | 2 +- .../content/kinetics/mixer/MixerVisual.java | 2 +- .../foundation/render/AllInstanceTypes.java | 50 +++---------- .../create/flywheel/instance/actor.vert | 13 ---- .../create/flywheel/instance/cull/actor.glsl | 8 -- .../flywheel/instance/cull/rotating.glsl | 2 +- .../create/flywheel/instance/rotating.vert | 20 ++--- 12 files changed, 109 insertions(+), 166 deletions(-) delete mode 100644 src/main/java/com/simibubi/create/content/kinetics/base/KineticInstance.java delete mode 100644 src/main/resources/assets/create/flywheel/instance/actor.vert delete mode 100644 src/main/resources/assets/create/flywheel/instance/cull/actor.glsl diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityVisual.java b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityVisual.java index bbd66e8faf..528aee931b 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityVisual.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityVisual.java @@ -6,9 +6,9 @@ import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock; import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual; -import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Vec3i; import net.minecraft.world.level.block.state.BlockState; public abstract class KineticBlockEntityVisual extends AbstractBlockEntityVisual { @@ -32,7 +32,7 @@ public abstract class KineticBlockEntityVisual ext protected final void updateRotation(RotatingInstance instance, Direction.Axis axis, float speed) { instance.setRotationAxis(axis) .setRotationOffset(getRotationOffset(axis)) - .setRotationalSpeed(speed) + .setRotationalSpeed(speed * RotatingInstance.SPEED_MULTIPLIER) .setColor(blockEntity) .setChanged(); } @@ -51,7 +51,7 @@ public abstract class KineticBlockEntityVisual ext protected final RotatingInstance setup(RotatingInstance key, Direction.Axis axis, float speed) { key.setRotationAxis(axis) - .setRotationalSpeed(speed) + .setRotationalSpeed(speed * RotatingInstance.SPEED_MULTIPLIER) .setRotationOffset(getRotationOffset(axis)) .setColor(blockEntity) .setPosition(getVisualPosition()) @@ -76,7 +76,7 @@ public abstract class KineticBlockEntityVisual ext return shaft(rotationAxis()); } - public static float rotationOffset(BlockState state, Axis axis, BlockPos pos) { + public static float rotationOffset(BlockState state, Axis axis, Vec3i pos) { if (shouldOffset(axis, pos)) { return 22.5f; } else { @@ -84,7 +84,7 @@ public abstract class KineticBlockEntityVisual ext } } - public static boolean shouldOffset(Axis axis, BlockPos pos) { + public static boolean shouldOffset(Axis axis, Vec3i pos) { // Sum the components of the other 2 axes. int x = (axis == Axis.X) ? 0 : pos.getX(); int y = (axis == Axis.Y) ? 0 : pos.getY(); diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/KineticInstance.java b/src/main/java/com/simibubi/create/content/kinetics/base/KineticInstance.java deleted file mode 100644 index 15f8f45ddf..0000000000 --- a/src/main/java/com/simibubi/create/content/kinetics/base/KineticInstance.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.simibubi.create.content.kinetics.base; - -import org.joml.Vector3f; - -import dev.engine_room.flywheel.api.instance.InstanceHandle; -import dev.engine_room.flywheel.api.instance.InstanceType; -import dev.engine_room.flywheel.lib.instance.ColoredLitInstance; -import net.createmod.catnip.utility.theme.Color; -import net.minecraft.core.BlockPos; - -public class KineticInstance extends ColoredLitInstance { - public float x; - public float y; - public float z; - public float rotationalSpeed; - public float rotationOffset; - - protected KineticInstance(InstanceType type, InstanceHandle handle) { - super(type, handle); - } - - public KineticInstance setPosition(BlockPos pos) { - return setPosition(pos.getX(), pos.getY(), pos.getZ()); - } - - public KineticInstance setPosition(Vector3f pos) { - return setPosition(pos.x(), pos.y(), pos.z()); - } - - public KineticInstance setPosition(float x, float y, float z) { - this.x = x; - this.y = y; - this.z = z; - return this; - } - - public KineticInstance nudge(float x, float y, float z) { - this.x += x; - this.y += y; - this.z += z; - return this; - } - - public KineticInstance setColor(KineticBlockEntity blockEntity) { - colorRgb(colorFromBE(blockEntity)); - return this; - } - - public KineticInstance setColor(Color c) { - color(c.getRed(), c.getGreen(), c.getBlue()); - return this; - } - - public KineticInstance setRotationalSpeed(float rotationalSpeed) { - this.rotationalSpeed = rotationalSpeed; - return this; - } - - public KineticInstance setRotationOffset(float rotationOffset) { - this.rotationOffset = rotationOffset; - return this; - } - - public static int colorFromBE(KineticBlockEntity be) { - if (be.hasNetwork()) - return Color.generateFromLong(be.network).getRGB(); - return 0xFFFFFF; - } -} diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/RotatingInstance.java b/src/main/java/com/simibubi/create/content/kinetics/base/RotatingInstance.java index 56d998c008..9569aac356 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/base/RotatingInstance.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/RotatingInstance.java @@ -1,20 +1,48 @@ package com.simibubi.create.content.kinetics.base; +import org.joml.Quaternionf; import org.joml.Vector3f; import dev.engine_room.flywheel.api.instance.InstanceHandle; import dev.engine_room.flywheel.api.instance.InstanceType; +import dev.engine_room.flywheel.lib.instance.ColoredLitInstance; +import net.createmod.catnip.utility.theme.Color; import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; + +public class RotatingInstance extends ColoredLitInstance { + public static final float SPEED_MULTIPLIER = 6; -public class RotatingInstance extends KineticInstance { public byte rotationAxisX; public byte rotationAxisY; public byte rotationAxisZ; + public float x; + public float y; + public float z; + /** + * Speed in degrees per second + */ + public float rotationalSpeed; + /** + * Offset in degrees + */ + public float rotationOffset; - public RotatingInstance(InstanceType type, InstanceHandle handle) { + /** + * Base rotation of the instance, applied before kinetic rotation + */ + public final Quaternionf rotation = new Quaternionf(); + + public RotatingInstance(InstanceType type, InstanceHandle handle) { super(type, handle); } + public static int colorFromBE(KineticBlockEntity be) { + if (be.hasNetwork()) + return Color.generateFromLong(be.network).getRGB(); + return 0xFFFFFF; + } + public RotatingInstance setRotationAxis(Direction.Axis axis) { Direction orientation = Direction.get(Direction.AxisDirection.POSITIVE, axis); return setRotationAxis(orientation.step()); @@ -31,4 +59,45 @@ public class RotatingInstance extends KineticInstance { return this; } + public RotatingInstance setPosition(Vec3i pos) { + return setPosition(pos.getX(), pos.getY(), pos.getZ()); + } + + public RotatingInstance setPosition(Vector3f pos) { + return setPosition(pos.x(), pos.y(), pos.z()); + } + + public RotatingInstance setPosition(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + public RotatingInstance nudge(float x, float y, float z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + public RotatingInstance setColor(KineticBlockEntity blockEntity) { + colorRgb(colorFromBE(blockEntity)); + return this; + } + + public RotatingInstance setColor(Color c) { + color(c.getRed(), c.getGreen(), c.getBlue()); + return this; + } + + public RotatingInstance setRotationalSpeed(float rotationalSpeed) { + this.rotationalSpeed = rotationalSpeed; + return this; + } + + public RotatingInstance setRotationOffset(float rotationOffset) { + this.rotationOffset = rotationOffset; + return this; + } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/BeltVisual.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltVisual.java index 3546a7cf6b..75f8035df8 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/belt/BeltVisual.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltVisual.java @@ -7,7 +7,6 @@ import org.joml.Quaternionf; import com.simibubi.create.AllPartialModels; import com.simibubi.create.content.kinetics.base.KineticBlockEntityVisual; -import com.simibubi.create.content.kinetics.base.KineticInstance; import com.simibubi.create.content.kinetics.base.RotatingInstance; import com.simibubi.create.content.processing.burner.ScrollInstance; import com.simibubi.create.foundation.render.AllInstanceTypes; @@ -158,7 +157,7 @@ public class BeltVisual extends KineticBlockEntityVisual { .rotation(q) .speed(0, speed * MAGIC_SCROLL_MULTIPLIER) .offset(0, bottom ? SCROLL_OFFSET_BOTTOM : SCROLL_OFFSET_OTHERWISE) - .colorRgb(KineticInstance.colorFromBE(blockEntity)) + .colorRgb(RotatingInstance.colorFromBE(blockEntity)) .setChanged(); return key; diff --git a/src/main/java/com/simibubi/create/content/kinetics/drill/DrillActorVisual.java b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillActorVisual.java index c7ac70aacf..ae2acca9d3 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/drill/DrillActorVisual.java +++ b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillActorVisual.java @@ -1,11 +1,9 @@ package com.simibubi.create.content.kinetics.drill; -import org.joml.Quaternionf; - import com.simibubi.create.AllPartialModels; -import com.simibubi.create.content.contraptions.actors.ActorInstance; import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.render.ActorVisual; +import com.simibubi.create.content.kinetics.base.RotatingInstance; import com.simibubi.create.foundation.render.AllInstanceTypes; import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld; @@ -19,7 +17,7 @@ import net.minecraft.world.level.block.state.BlockState; public class DrillActorVisual extends ActorVisual { - ActorInstance drillHead; + RotatingInstance drillHead; private final Direction facing; public DrillActorVisual(VisualizationContext visualizationContext, VirtualRenderWorld contraption, MovementContext context) { @@ -38,21 +36,22 @@ public class DrillActorVisual extends ActorVisual { else eulerY = facing.toYRot() + ((axis == Direction.Axis.X) ? 180 : 0); - drillHead = instancerProvider.instancer(AllInstanceTypes.ACTOR, Models.partial(AllPartialModels.DRILL_HEAD)) + drillHead = instancerProvider.instancer(AllInstanceTypes.ROTATING, Models.partial(AllPartialModels.DRILL_HEAD)) .createInstance(); + drillHead.rotation.rotationXYZ(eulerX * Mth.DEG_TO_RAD, eulerY * Mth.DEG_TO_RAD, 0); + drillHead.setPosition(context.localPos) - .setBlockLight(localBlockLight()) - .setRotationOffset(0) - .setRotationAxis(0, 0, 1) - .setLocalRotation(new Quaternionf().rotationXYZ(eulerX * Mth.DEG_TO_RAD, eulerY * Mth.DEG_TO_RAD, 0)) - .setSpeed(getSpeed(facing)) - .setChanged(); + .setRotationOffset(0) + .setRotationAxis(0, 0, 1) + .setRotationalSpeed(getSpeed(facing)) + .light(localBlockLight(), 0) + .setChanged(); } @Override public void beginFrame() { - drillHead.setSpeed(getSpeed(facing)) + drillHead.setRotationalSpeed(getSpeed(facing)) .setChanged(); } diff --git a/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxVisual.java b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxVisual.java index b9ee456478..3d173b56e6 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxVisual.java +++ b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxVisual.java @@ -45,7 +45,7 @@ public class GearboxVisual extends KineticBlockEntityVisual .createInstance(); key.setRotationAxis(axis) - .setRotationalSpeed(getSpeed(direction)) + .setRotationalSpeed(getSpeed(direction) * RotatingInstance.SPEED_MULTIPLIER) .setRotationOffset(getRotationOffset(axis)).setColor(blockEntity) .setPosition(getVisualPosition()) .light(blockLight, skyLight) diff --git a/src/main/java/com/simibubi/create/content/kinetics/mixer/MixerVisual.java b/src/main/java/com/simibubi/create/content/kinetics/mixer/MixerVisual.java index f229d9d870..1157b7d889 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/mixer/MixerVisual.java +++ b/src/main/java/com/simibubi/create/content/kinetics/mixer/MixerVisual.java @@ -60,7 +60,7 @@ public class MixerVisual extends EncasedCogVisual implements SimpleDynamicVisual mixerHead.setPosition(getVisualPosition()) .nudge(0, -renderedHeadOffset, 0) - .setRotationalSpeed(speed * 2) + .setRotationalSpeed(speed * 2 * RotatingInstance.SPEED_MULTIPLIER) .setChanged(); } diff --git a/src/main/java/com/simibubi/create/foundation/render/AllInstanceTypes.java b/src/main/java/com/simibubi/create/foundation/render/AllInstanceTypes.java index 36b83b0fdf..007e14ff68 100644 --- a/src/main/java/com/simibubi/create/foundation/render/AllInstanceTypes.java +++ b/src/main/java/com/simibubi/create/foundation/render/AllInstanceTypes.java @@ -4,7 +4,6 @@ import static com.simibubi.create.Create.asResource; import org.lwjgl.system.MemoryUtil; -import com.simibubi.create.content.contraptions.actors.ActorInstance; import com.simibubi.create.content.kinetics.base.RotatingInstance; import com.simibubi.create.content.processing.burner.ScrollInstance; @@ -14,6 +13,7 @@ import dev.engine_room.flywheel.api.layout.IntegerRepr; import dev.engine_room.flywheel.api.layout.LayoutBuilder; import dev.engine_room.flywheel.lib.instance.SimpleInstanceType; import dev.engine_room.flywheel.lib.util.ExtraMemoryOps; + import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -26,6 +26,7 @@ public class AllInstanceTypes { .vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4) .vector("light", IntegerRepr.SHORT, 2) .vector("overlay", IntegerRepr.SHORT, 2) + .vector("rotation", FloatRepr.FLOAT, 4) .vector("pos", FloatRepr.FLOAT, 3) .scalar("speed", FloatRepr.FLOAT) .scalar("offset", FloatRepr.FLOAT) @@ -38,14 +39,15 @@ public class AllInstanceTypes { MemoryUtil.memPutByte(ptr + 3, instance.alpha); ExtraMemoryOps.put2x16(ptr + 4, instance.light); ExtraMemoryOps.put2x16(ptr + 8, instance.overlay); - MemoryUtil.memPutFloat(ptr + 12, instance.x); - MemoryUtil.memPutFloat(ptr + 16, instance.y); - MemoryUtil.memPutFloat(ptr + 20, instance.z); - MemoryUtil.memPutFloat(ptr + 24, instance.rotationalSpeed); - MemoryUtil.memPutFloat(ptr + 28, instance.rotationOffset); - MemoryUtil.memPutByte(ptr + 32, instance.rotationAxisX); - MemoryUtil.memPutByte(ptr + 33, instance.rotationAxisY); - MemoryUtil.memPutByte(ptr + 34, instance.rotationAxisZ); + ExtraMemoryOps.putQuaternionf(ptr + 12, instance.rotation); + MemoryUtil.memPutFloat(ptr + 28, instance.x); + MemoryUtil.memPutFloat(ptr + 32, instance.y); + MemoryUtil.memPutFloat(ptr + 36, instance.z); + MemoryUtil.memPutFloat(ptr + 40, instance.rotationalSpeed); + MemoryUtil.memPutFloat(ptr + 44, instance.rotationOffset); + MemoryUtil.memPutByte(ptr + 48, instance.rotationAxisX); + MemoryUtil.memPutByte(ptr + 49, instance.rotationAxisY); + MemoryUtil.memPutByte(ptr + 50, instance.rotationAxisZ); }) .build(); @@ -85,36 +87,6 @@ public class AllInstanceTypes { }) .build(); - public static final InstanceType ACTOR = SimpleInstanceType.builder(ActorInstance::new) - .cullShader(asResource("instance/cull/actor.glsl")) - .vertexShader(asResource("instance/actor.vert")) - .layout(LayoutBuilder.create() - .vector("pos", FloatRepr.FLOAT, 3) - .vector("light", IntegerRepr.SHORT, 2) - .scalar("offset", FloatRepr.FLOAT) - .vector("axis", FloatRepr.NORMALIZED_BYTE, 3) - .vector("rotation", FloatRepr.FLOAT, 4) - .vector("rotationCenter", FloatRepr.NORMALIZED_BYTE, 3) - .scalar("speed", FloatRepr.FLOAT) - .build()) - .writer((ptr, instance) -> { - MemoryUtil.memPutFloat(ptr, instance.x); - MemoryUtil.memPutFloat(ptr + 4, instance.y); - MemoryUtil.memPutFloat(ptr + 8, instance.z); - MemoryUtil.memPutShort(ptr + 12, instance.blockLight); - MemoryUtil.memPutShort(ptr + 14, instance.skyLight); - MemoryUtil.memPutFloat(ptr + 16, instance.rotationOffset); - MemoryUtil.memPutByte(ptr + 20, instance.rotationAxisX); - MemoryUtil.memPutByte(ptr + 21, instance.rotationAxisY); - MemoryUtil.memPutByte(ptr + 22, instance.rotationAxisZ); - ExtraMemoryOps.putQuaternionf(ptr + 24, instance.rotation); - MemoryUtil.memPutByte(ptr + 40, instance.rotationCenterX); - MemoryUtil.memPutByte(ptr + 41, instance.rotationCenterY); - MemoryUtil.memPutByte(ptr + 42, instance.rotationCenterZ); - MemoryUtil.memPutFloat(ptr + 44, instance.speed); - }) - .build(); - public static void init() { // noop } diff --git a/src/main/resources/assets/create/flywheel/instance/actor.vert b/src/main/resources/assets/create/flywheel/instance/actor.vert deleted file mode 100644 index 7c06bd569f..0000000000 --- a/src/main/resources/assets/create/flywheel/instance/actor.vert +++ /dev/null @@ -1,13 +0,0 @@ -#include "flywheel:util/matrix.glsl" -#include "flywheel:util/quaternion.glsl" - -void flw_instanceVertex(in FlwInstance instance) { - float degrees = instance.offset + flw_renderSeconds * instance.speed; - - vec4 kineticRot = quaternionDegrees(instance.axis, degrees); - vec3 rotated = rotateByQuaternion(flw_vertexPos.xyz - instance.rotationCenter, kineticRot) + instance.rotationCenter; - - flw_vertexPos.xyz = rotateByQuaternion(rotated - .5, instance.rotation) + instance.pos + .5; - flw_vertexNormal = rotateByQuaternion(rotateByQuaternion(flw_vertexNormal, kineticRot), instance.rotation); - flw_vertexLight = max(vec2(instance.light) / 256., flw_vertexLight); -} diff --git a/src/main/resources/assets/create/flywheel/instance/cull/actor.glsl b/src/main/resources/assets/create/flywheel/instance/cull/actor.glsl deleted file mode 100644 index 6a0b1d8579..0000000000 --- a/src/main/resources/assets/create/flywheel/instance/cull/actor.glsl +++ /dev/null @@ -1,8 +0,0 @@ -void flw_transformBoundingSphere(in FlwInstance instance, inout vec3 center, inout float radius) { - // The instance will spin about the rotation center, so we need to expand the radius to account for that - float extraForKinetic = length(center - instance.rotationCenter); - float extraForModel = length(center - 0.5); - - radius += extraForKinetic + extraForModel; - center += instance.pos; -} diff --git a/src/main/resources/assets/create/flywheel/instance/cull/rotating.glsl b/src/main/resources/assets/create/flywheel/instance/cull/rotating.glsl index da6118e155..67f3c35fce 100644 --- a/src/main/resources/assets/create/flywheel/instance/cull/rotating.glsl +++ b/src/main/resources/assets/create/flywheel/instance/cull/rotating.glsl @@ -1,5 +1,5 @@ void flw_transformBoundingSphere(in FlwInstance instance, inout vec3 center, inout float radius) { - // The instance will spin about (0.5, 0.5, 0.5), so we need to expand the radius to account for that + // The instance will spin about the rotation center, so we need to expand the radius to account for that radius += length(center - 0.5); center += instance.pos; } diff --git a/src/main/resources/assets/create/flywheel/instance/rotating.vert b/src/main/resources/assets/create/flywheel/instance/rotating.vert index 066ccd071a..747c51cb91 100644 --- a/src/main/resources/assets/create/flywheel/instance/rotating.vert +++ b/src/main/resources/assets/create/flywheel/instance/rotating.vert @@ -1,21 +1,15 @@ -#include "flywheel:util/matrix.glsl" - -const float uTime = 0.; - -mat3 kineticRotation(float offset, float speed, vec3 axis) { - float degrees = offset + flw_renderTicks * speed * 3./10.; - return rotationDegrees(axis, degrees); -} +#include "flywheel:util/quaternion.glsl" void flw_instanceVertex(in FlwInstance instance) { - mat3 spin = kineticRotation(instance.offset, instance.speed, instance.axis); + float degrees = instance.offset + flw_renderSeconds * instance.speed; - vec3 worldPos = spin * (flw_vertexPos.xyz - .5); - flw_vertexPos.xyz = worldPos.xyz + instance.pos + .5; + vec4 kineticRot = quaternionDegrees(instance.axis, degrees); + vec3 rotated = rotateByQuaternion(flw_vertexPos.xyz - .5, instance.rotation); - flw_vertexNormal = spin * flw_vertexNormal; - flw_vertexOverlay = instance.overlay; + flw_vertexPos.xyz = rotateByQuaternion(rotated, kineticRot) + instance.pos + .5; + flw_vertexNormal = rotateByQuaternion(rotateByQuaternion(flw_vertexNormal, instance.rotation), kineticRot); flw_vertexLight = max(vec2(instance.light) / 256., flw_vertexLight); + flw_vertexOverlay = instance.overlay; #if defined(DEBUG_RAINBOW) flw_vertexColor = instance.color; From 316e3728945ed98d8a0abd3354a99510c40c94f7 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Sun, 12 Jan 2025 14:50:39 +0100 Subject: [PATCH 8/8] Your storage is showing - Depots are now viable as Mounted Storage and dynamically display their contents --- .../java/com/simibubi/create/AllBlocks.java | 2 + .../java/com/simibubi/create/AllPackets.java | 2 + .../content/contraptions/Contraption.java | 8 ++ .../content/contraptions/MountedStorage.java | 78 ++++++++++++++++++- .../contraptions/MountedStorageManager.java | 62 ++++++++++----- .../sync/ContraptionItemPacket.java | 60 ++++++++++++++ .../logistics/depot/DepotBlockEntity.java | 9 +++ .../MountedDepotInteractionBehaviour.java | 51 ++++++++++++ .../trains/entity/CarriageContraption.java | 5 ++ .../content/trains/station/GlobalStation.java | 62 +++++++-------- 10 files changed, 289 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionItemPacket.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/depot/MountedDepotInteractionBehaviour.java diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index a528a6c3c2..2fcb8f773c 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -169,6 +169,7 @@ import com.simibubi.create.content.logistics.crate.CreativeCrateBlock; import com.simibubi.create.content.logistics.depot.DepotBlock; import com.simibubi.create.content.logistics.depot.EjectorBlock; import com.simibubi.create.content.logistics.depot.EjectorItem; +import com.simibubi.create.content.logistics.depot.MountedDepotInteractionBehaviour; import com.simibubi.create.content.logistics.factoryBoard.FactoryPanelBlock; import com.simibubi.create.content.logistics.factoryBoard.FactoryPanelBlockItem; import com.simibubi.create.content.logistics.factoryBoard.FactoryPanelModel; @@ -793,6 +794,7 @@ public class AllBlocks { .transform(axeOrPickaxe()) .blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p))) .onRegister(assignDataBehaviour(new ItemNameDisplaySource(), "combine_item_names")) + .onRegister(interactionBehaviour(new MountedDepotInteractionBehaviour())) .item() .transform(customItemModel("_", "block")) .register(); diff --git a/src/main/java/com/simibubi/create/AllPackets.java b/src/main/java/com/simibubi/create/AllPackets.java index bf7ea041b5..bc2ae469f4 100644 --- a/src/main/java/com/simibubi/create/AllPackets.java +++ b/src/main/java/com/simibubi/create/AllPackets.java @@ -32,6 +32,7 @@ import com.simibubi.create.content.contraptions.minecart.capability.MinecartCont import com.simibubi.create.content.contraptions.sync.ClientMotionPacket; import com.simibubi.create.content.contraptions.sync.ContraptionFluidPacket; import com.simibubi.create.content.contraptions.sync.ContraptionInteractionPacket; +import com.simibubi.create.content.contraptions.sync.ContraptionItemPacket; import com.simibubi.create.content.contraptions.sync.ContraptionSeatMappingPacket; import com.simibubi.create.content.contraptions.sync.LimbSwingUpdatePacket; import com.simibubi.create.content.contraptions.wrench.RadialWrenchMenuSubmitPacket; @@ -218,6 +219,7 @@ public enum AllPackets { MINECART_CONTROLLER(MinecartControllerUpdatePacket.class, MinecartControllerUpdatePacket::new, PLAY_TO_CLIENT), FLUID_SPLASH(FluidSplashPacket.class, FluidSplashPacket::new, PLAY_TO_CLIENT), CONTRAPTION_FLUID(ContraptionFluidPacket.class, ContraptionFluidPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_ITEM(ContraptionItemPacket.class, ContraptionItemPacket::new, PLAY_TO_CLIENT), GANTRY_UPDATE(GantryContraptionUpdatePacket.class, GantryContraptionUpdatePacket::new, PLAY_TO_CLIENT), BLOCK_HIGHLIGHT(HighlightPacket.class, HighlightPacket::new, PLAY_TO_CLIENT), TUNNEL_FLAP(TunnelFlapPacket.class, TunnelFlapPacket::new, PLAY_TO_CLIENT), diff --git a/src/main/java/com/simibubi/create/content/contraptions/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/Contraption.java index 693ccdd9e1..a769bd1693 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/Contraption.java @@ -1459,6 +1459,10 @@ public abstract class Contraption { public IFluidHandler getSharedFluidTanks() { return storage.getFluids(); } + + public MountedStorageManager getStorageManager() { + return storage; + } public RenderedBlocks getRenderedBlocks() { return new RenderedBlocks(pos -> { @@ -1485,6 +1489,10 @@ public abstract class Contraption { public void handleContraptionFluidPacket(BlockPos localPos, FluidStack containedFluid) { storage.updateContainedFluid(localPos, containedFluid); } + + public void handleContraptionItemPacket(BlockPos localPos, List containedItems) { + storage.updateContainedItem(localPos, containedItems); + } public static class ContraptionInvWrapper extends CombinedInvWrapper { protected final boolean isExternal; diff --git a/src/main/java/com/simibubi/create/content/contraptions/MountedStorage.java b/src/main/java/com/simibubi/create/content/contraptions/MountedStorage.java index 424e192c15..b6a1db3c39 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/MountedStorage.java +++ b/src/main/java/com/simibubi/create/content/contraptions/MountedStorage.java @@ -1,16 +1,26 @@ package com.simibubi.create.content.contraptions; +import java.util.List; + import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllPackets; import com.simibubi.create.AllTags.AllBlockTags; +import com.simibubi.create.content.contraptions.sync.ContraptionItemPacket; import com.simibubi.create.content.equipment.toolbox.ToolboxInventory; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlockEntity; import com.simibubi.create.content.logistics.crate.BottomlessItemHandler; +import com.simibubi.create.content.logistics.depot.DepotBehaviour; +import com.simibubi.create.content.logistics.depot.DepotBlockEntity; import com.simibubi.create.content.logistics.vault.ItemVaultBlockEntity; import com.simibubi.create.content.processing.recipe.ProcessingInventory; + import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.ContainerHelper; +import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BarrelBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; @@ -22,6 +32,7 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.registries.ForgeRegistries; public class MountedStorage { @@ -31,8 +42,11 @@ public class MountedStorage { ItemStackHandler handler; boolean noFuel; boolean valid; + + private int packetCooldown = 0; + private boolean sendPacket = false; - private BlockEntity blockEntity; + BlockEntity blockEntity; public static boolean canUseAsStorage(BlockEntity be) { if (be == null) @@ -49,6 +63,8 @@ public class MountedStorage { return true; if (be instanceof ItemVaultBlockEntity) return true; + if (be instanceof DepotBlockEntity) + return true; try { LazyOptional capability = be.getCapability(ForgeCapabilities.ITEM_HANDLER); @@ -85,9 +101,17 @@ public class MountedStorage { public void removeStorageFromWorld() { valid = false; + sendPacket = false; if (blockEntity == null) return; + if (blockEntity instanceof DepotBlockEntity depot) { + handler = new SyncedMountedItemStackHandler(1); + handler.setStackInSlot(0, depot.getHeldItem()); + valid = true; + return; + } + if (blockEntity instanceof ChestBlockEntity) { CompoundTag tag = blockEntity.saveWithFullMetadata(); if (tag.contains("LootTable", 8)) @@ -140,6 +164,13 @@ public class MountedStorage { if (handler instanceof BottomlessItemHandler) return; + if (be instanceof DepotBlockEntity depot) { + if (handler.getSlots() > 0) + depot.getBehaviour(DepotBehaviour.TYPE) + .setCenteredHeldItem(new TransportedItemStack(handler.getStackInSlot(0))); + return; + } + if (be instanceof ChestBlockEntity) { CompoundTag tag = be.saveWithFullMetadata(); tag.remove("Items"); @@ -166,6 +197,29 @@ public class MountedStorage { inv.setStackInSlot(slot, handler.getStackInSlot(slot)); } + public void tick(Entity entity, BlockPos pos, boolean isRemote) { + if (isRemote) + return; + if (packetCooldown > 0) { + packetCooldown--; + return; + } + if (sendPacket) { + sendPacket = false; + AllPackets.getChannel() + .send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), + new ContraptionItemPacket(entity.getId(), pos, handler)); + packetCooldown = 8; + } + } + + public void updateItems(List containedItems) { + for (int i = 0; i < Math.min(containedItems.size(), handler.getSlots()); i++) + handler.setStackInSlot(i, containedItems.get(i)); + if (blockEntity instanceof DepotBlockEntity depot) + depot.setHeldItem(handler.getStackInSlot(0)); + } + public IItemHandlerModifiable getItemHandler() { return handler; } @@ -179,6 +233,9 @@ public class MountedStorage { NBTHelper.putMarker(tag, "NoFuel"); if (handler instanceof ToolboxInventory) NBTHelper.putMarker(tag, "Toolbox"); + if (needsSync()) + NBTHelper.putMarker(tag, "Synced"); + if (!(handler instanceof BottomlessItemHandler)) return tag; @@ -195,6 +252,8 @@ public class MountedStorage { return storage; if (nbt.contains("Toolbox")) storage.handler = new ToolboxInventory(null); + if (nbt.contains("Synced")) + storage.handler = storage.new SyncedMountedItemStackHandler(1); storage.valid = true; storage.noFuel = nbt.contains("NoFuel"); @@ -216,5 +275,22 @@ public class MountedStorage { public boolean canUseForFuel() { return !noFuel; } + + public boolean needsSync() { + return handler instanceof SyncedMountedItemStackHandler; + } + + public class SyncedMountedItemStackHandler extends ItemStackHandler { + + public SyncedMountedItemStackHandler(int i) { + super(i); + } + + @Override + protected void onContentsChanged(int slot) { + sendPacket = true; + } + + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/MountedStorageManager.java b/src/main/java/com/simibubi/create/content/contraptions/MountedStorageManager.java index 2decc9c531..71809cc994 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/MountedStorageManager.java +++ b/src/main/java/com/simibubi/create/content/contraptions/MountedStorageManager.java @@ -5,12 +5,14 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.TreeMap; import java.util.function.Supplier; import java.util.stream.Collectors; import com.simibubi.create.content.contraptions.Contraption.ContraptionInvWrapper; import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; +import com.simibubi.create.content.logistics.depot.DepotBlockEntity; import com.simibubi.create.foundation.fluid.CombinedTankWrapper; import net.createmod.catnip.utility.NBTHelper; @@ -53,7 +55,9 @@ public class MountedStorageManager { } public void entityTick(AbstractContraptionEntity entity) { - fluidStorage.forEach((pos, mfs) -> mfs.tick(entity, pos, entity.level().isClientSide)); + boolean isClientSide = entity.level().isClientSide; + storage.forEach((pos, mfs) -> mfs.tick(entity, pos, isClientSide)); + fluidStorage.forEach((pos, mfs) -> mfs.tick(entity, pos, isClientSide)); } public void createHandlers() { @@ -99,7 +103,7 @@ public class MountedStorageManager { .put(NbtUtils.readBlockPos(c.getCompound("Pos")), MountedFluidStorage.deserialize(c.getCompound("Data")))); if (clientPacket && presentBlockEntities != null) - bindTanks(presentBlockEntities); + bindTanksAndDepots(presentBlockEntities); List handlers = new ArrayList<>(); List fuelHandlers = new ArrayList<>(); @@ -118,33 +122,41 @@ public class MountedStorageManager { .toList()); } - public void bindTanks(Map presentBlockEntities) { - fluidStorage.forEach((pos, mfs) -> { - BlockEntity blockEntity = presentBlockEntities.get(pos); - if (!(blockEntity instanceof FluidTankBlockEntity)) + public void bindTanksAndDepots(Map presentBlockEntities) { + for (Entry entry : storage.entrySet()) { + BlockEntity blockEntity = presentBlockEntities.get(entry.getKey()); + if (!(blockEntity instanceof DepotBlockEntity depot)) + return; + depot.setHeldItem(entry.getValue().handler.getStackInSlot(0)); + entry.getValue().blockEntity = depot; + } + for (Entry entry : fluidStorage.entrySet()) { + BlockEntity blockEntity = presentBlockEntities.get(entry.getKey()); + if (!(blockEntity instanceof FluidTankBlockEntity tank)) return; - FluidTankBlockEntity tank = (FluidTankBlockEntity) blockEntity; IFluidTank tankInventory = tank.getTankInventory(); + MountedFluidStorage mfs = entry.getValue(); if (tankInventory instanceof FluidTank) ((FluidTank) tankInventory).setFluid(mfs.tank.getFluid()); tank.getFluidLevel() .startWithValue(tank.getFillState()); mfs.assignBlockEntity(tank); - }); + } } public void write(CompoundTag nbt, boolean clientPacket) { ListTag storageNBT = new ListTag(); - if (!clientPacket) - for (BlockPos pos : storage.keySet()) { - CompoundTag c = new CompoundTag(); - MountedStorage mountedStorage = storage.get(pos); - if (!mountedStorage.isValid()) - continue; - c.put("Pos", NbtUtils.writeBlockPos(pos)); - c.put("Data", mountedStorage.serialize()); - storageNBT.add(c); - } + for (BlockPos pos : storage.keySet()) { + CompoundTag c = new CompoundTag(); + MountedStorage mountedStorage = storage.get(pos); + if (!mountedStorage.isValid()) + continue; + if (clientPacket && !mountedStorage.needsSync()) + continue; + c.put("Pos", NbtUtils.writeBlockPos(pos)); + c.put("Data", mountedStorage.serialize()); + storageNBT.add(c); + } ListTag fluidStorageNBT = new ListTag(); for (BlockPos pos : fluidStorage.keySet()) { @@ -196,6 +208,12 @@ public class MountedStorageManager { mountedFluidStorage.updateFluid(containedFluid); } + public void updateContainedItem(BlockPos localPos, List containedItems) { + MountedStorage mountedStorage = storage.get(localPos); + if (mountedStorage != null) + mountedStorage.updateItems(containedItems); + } + public void attachExternal(IItemHandlerModifiable externalStorage) { inventory = new ContraptionInvWrapper(externalStorage, inventory); fuelInventory = new ContraptionInvWrapper(externalStorage, fuelInventory); @@ -212,6 +230,14 @@ public class MountedStorageManager { public IFluidHandler getFluids() { return fluidInventory; } + + public Map getMountedItemStorage() { + return storage; + } + + public Map getMountedFluidStorage() { + return fluidStorage; + } public boolean handlePlayerStorageInteraction(Contraption contraption, Player player, BlockPos localPos) { if (player.level().isClientSide()) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionItemPacket.java b/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionItemPacket.java new file mode 100644 index 0000000000..6f18fc1e58 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionItemPacket.java @@ -0,0 +1,60 @@ +package com.simibubi.create.content.contraptions.sync; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ContraptionItemPacket extends SimplePacketBase { + + private int entityId; + private BlockPos localPos; + private List containedItems; + + public ContraptionItemPacket(int entityId, BlockPos localPos, ItemStackHandler handler) { + this.entityId = entityId; + this.localPos = localPos; + this.containedItems = new ArrayList<>(handler.getSlots()); + for (int i = 0; i < handler.getSlots(); i++) + containedItems.add(handler.getStackInSlot(i)); + } + + public ContraptionItemPacket(FriendlyByteBuf buffer) { + entityId = buffer.readInt(); + localPos = buffer.readBlockPos(); + int count = buffer.readVarInt(); + containedItems = new ArrayList<>(); + for (int i = 0; i < count; i++) + containedItems.add(buffer.readItem()); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityId); + buffer.writeBlockPos(localPos); + buffer.writeVarInt(containedItems.size()); + for (ItemStack stack : containedItems) + buffer.writeItem(stack); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + Entity entityByID = Minecraft.getInstance().level.getEntity(entityId); + if (!(entityByID instanceof AbstractContraptionEntity)) + return; + AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID; + contraptionEntity.getContraption().handleContraptionItemPacket(localPos, containedItems); + }); + return true; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlockEntity.java index c054f9204a..fa715ccb1e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlockEntity.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.depot; import java.util.List; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; @@ -38,4 +39,12 @@ public class DepotBlockEntity extends SmartBlockEntity { public ItemStack getHeldItem() { return depotBehaviour.getHeldItemStack(); } + + public void setHeldItem(ItemStack item) { + TransportedItemStack newStack = new TransportedItemStack(item); + if (depotBehaviour.heldItem != null) + newStack.angle = depotBehaviour.heldItem.angle; + depotBehaviour.setHeldItem(newStack); + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/MountedDepotInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/depot/MountedDepotInteractionBehaviour.java new file mode 100644 index 0000000000..e4ebc9ad01 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/MountedDepotInteractionBehaviour.java @@ -0,0 +1,51 @@ +package com.simibubi.create.content.logistics.depot; + +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.MountedStorage; +import com.simibubi.create.content.contraptions.MountedStorageManager; +import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.items.IItemHandlerModifiable; + +public class MountedDepotInteractionBehaviour extends MovingInteractionBehaviour { + + @Override + public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, + AbstractContraptionEntity contraptionEntity) { + ItemStack itemInHand = player.getItemInHand(activeHand); + if (activeHand == InteractionHand.OFF_HAND) + return false; + if (player.level().isClientSide) + return true; + + MountedStorageManager storageManager = contraptionEntity.getContraption() + .getStorageManager(); + if (storageManager == null) + return false; + + MountedStorage mountedStorage = storageManager.getMountedItemStorage() + .get(localPos); + if (mountedStorage == null) + return false; + + IItemHandlerModifiable itemHandler = mountedStorage.getItemHandler(); + ItemStack itemOnDepot = itemHandler.getStackInSlot(0); + + if (itemOnDepot.isEmpty() && itemInHand.isEmpty()) + return true; + + itemHandler.setStackInSlot(0, itemInHand.copy()); + player.setItemInHand(activeHand, itemOnDepot.copy()); + AllSoundEvents.DEPOT_PLOP.playOnServer(player.level(), + BlockPos.containing(contraptionEntity.toGlobalVector(Vec3.atCenterOf(localPos), 0))); + + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraption.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraption.java index 3123e1ae8f..f44f40b93d 100644 --- a/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraption.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraption.java @@ -333,6 +333,11 @@ public class CarriageContraption extends Contraption { public void handleContraptionFluidPacket(BlockPos localPos, FluidStack containedFluid) { storage.updateContainedFluid(localPos, containedFluid); } + + @Override + public MountedStorageManager getStorageManager() { + return storageProxy; + } @Override public void tickStorage(AbstractContraptionEntity entity) { diff --git a/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java b/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java index e4ca488a85..6e711304fd 100644 --- a/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java +++ b/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java @@ -186,6 +186,37 @@ public class GlobalStation extends SingleBlockEntityEdgePoint { if (carriageInventory == null) continue; + // Import from station + for (Entry entry : connectedPorts.entrySet()) { + GlobalPackagePort port = entry.getValue(); + BlockPos pos = entry.getKey(); + PostboxBlockEntity box = null; + + IItemHandlerModifiable postboxInventory = port.offlineBuffer; + if (level != null && level.isLoaded(pos) + && level.getBlockEntity(pos) instanceof PostboxBlockEntity ppbe) { + postboxInventory = ppbe.inventory; + box = ppbe; + } + + for (int slot = 0; slot < postboxInventory.getSlots(); slot++) { + ItemStack stack = postboxInventory.getStackInSlot(slot); + if (!PackageItem.isPackage(stack)) + continue; + if (PackageItem.matchAddress(stack, port.address)) + continue; + + ItemStack result = ItemHandlerHelper.insertItemStacked(carriageInventory, stack, false); + if (!result.isEmpty()) + continue; + + postboxInventory.setStackInSlot(slot, ItemStack.EMPTY); + Create.RAILWAYS.markTracksDirty(); + if (box != null) + box.spawnParticles(); + } + } + // Export to station for (int slot = 0; slot < carriageInventory.getSlots(); slot++) { ItemStack stack = carriageInventory.getStackInSlot(slot); @@ -220,37 +251,6 @@ public class GlobalStation extends SingleBlockEntityEdgePoint { } } - // Import from station - for (Entry entry : connectedPorts.entrySet()) { - GlobalPackagePort port = entry.getValue(); - BlockPos pos = entry.getKey(); - PostboxBlockEntity box = null; - - IItemHandlerModifiable postboxInventory = port.offlineBuffer; - if (level != null && level.isLoaded(pos) - && level.getBlockEntity(pos) instanceof PostboxBlockEntity ppbe) { - postboxInventory = ppbe.inventory; - box = ppbe; - } - - for (int slot = 0; slot < postboxInventory.getSlots(); slot++) { - ItemStack stack = postboxInventory.getStackInSlot(slot); - if (!PackageItem.isPackage(stack)) - continue; - if (PackageItem.matchAddress(stack, port.address)) - continue; - - ItemStack result = ItemHandlerHelper.insertItemStacked(carriageInventory, stack, false); - if (!result.isEmpty()) - continue; - - postboxInventory.setStackInSlot(slot, ItemStack.EMPTY); - Create.RAILWAYS.markTracksDirty(); - if (box != null) - box.spawnParticles(); - } - } - } }