Funnel Fantasy VII

- Finished ponder entries about funnels
- Smart TEs can now enter "virtual mode" to run both client and server code (support for it needs individual adjustment)
- Removed obsolete quads from the andesite funnels' model
- Not enough ponder instructions
- Fixed upright belt items in ponder UI
This commit is contained in:
simibubi 2021-02-28 23:49:51 +01:00
parent 43f0ad1c78
commit 0a1be94cbb
30 changed files with 558 additions and 76 deletions

View file

@ -16,7 +16,7 @@ a579c40c43dc2174afb66f42d00d0c4a0efaaeee assets/create/blockstates/andesite_bric
96b5284693da168ab8e0809d86515b5f1a7e763f assets/create/blockstates/andesite_cobblestone_stairs.json
82bd82270aff7d51e9239680ef4dd7b5c899ceb0 assets/create/blockstates/andesite_cobblestone_wall.json
9639b901ffdd2ecccab5575c5c9e6c7b5c901e02 assets/create/blockstates/andesite_encased_shaft.json
53cf4cfd94db1f44e9865b9fe5db383d01a12671 assets/create/blockstates/andesite_funnel.json
ca9a629472625abf741f02b94ce4578292fb14a7 assets/create/blockstates/andesite_funnel.json
398922758a6219544e5b85c91c9cf8a543b437e5 assets/create/blockstates/andesite_pillar.json
1d2d8081581e07d9be4b382aede4f2de4401cc6b assets/create/blockstates/andesite_tunnel.json
e555e3c2b2d3f01440e48db4ba88f7e00fd99b6f assets/create/blockstates/basin.json
@ -465,10 +465,10 @@ a033fbac3129bba9211c6c4a0e16c905643afa39 assets/create/models/block/andesite_cob
9841d6a09a09bf4d5d6a39bdc4904d86b3a825f8 assets/create/models/block/andesite_funnel_horizontal_pull_powered.json
86d5df6e365d9b2e9682f0839f61058360828ba2 assets/create/models/block/andesite_funnel_horizontal_push.json
50af1ff6ce9af162d4e438f21952c7215608dc8e assets/create/models/block/andesite_funnel_horizontal_push_powered.json
618d6ca90addb5913c72789f6188c957afa503f3 assets/create/models/block/andesite_funnel_vertical_pull.json
45365708fa75e2cd3d0702fb0e4960861ada27ab assets/create/models/block/andesite_funnel_vertical_pull_powered.json
53bdeba42894242088e8f7e7734a101fa998d0e4 assets/create/models/block/andesite_funnel_vertical_push.json
3e88fa45e22868dae92a014e589585d37eb465ad assets/create/models/block/andesite_funnel_vertical_push_powered.json
75c914bf9448e25fd01d597de48375a9782bef36 assets/create/models/block/andesite_funnel_vertical_filterless_pull.json
4d70a221809f5bc598a0a0e98bd152e9ab7a2f7f assets/create/models/block/andesite_funnel_vertical_filterless_pull_powered.json
a41c7351513a9514dfdc0fc552b646b1d715c977 assets/create/models/block/andesite_funnel_vertical_filterless_push.json
e7931f28887baadd52ac988fc8eeeb84ee6f0d27 assets/create/models/block/andesite_funnel_vertical_filterless_push_powered.json
b1d0bb538fc8285b7d3fd77a977d78a104b83b62 assets/create/models/block/andesite_pillar.json
aaf2e4259bcfcedd3400e9acb2d64c0cf06f7fb1 assets/create/models/block/andesite_tunnel/cross.json
75f628178fa21a2bd301eea8d1cebf7e94f7d5cc assets/create/models/block/andesite_tunnel/straight.json
@ -1579,7 +1579,7 @@ d080b1b25e5bc8baf5aee68691b08c7f12ece3b0 assets/create/models/item/windmill_bear
9f9455ccb5fc9e3cbfce73862b46078346a522a5 assets/create/models/item/zinc_nugget.json
b1689617190c05ef34bd18456b0c7ae09bb3210f assets/create/models/item/zinc_ore.json
e76041b7ae829fdd7dc0524f6ca4d2f89fca51bb assets/create/sounds.json
0f1b4b980afba9bf2caf583b88e261bba8b10313 data/create/advancements/aesthetics.json
5d0cc4c0255dc241e61c173b31ddca70c88d08e4 data/create/advancements/aesthetics.json
187921fa131b06721bfaf63f2623a28c141aae9a data/create/advancements/andesite_alloy.json
0ea2db7173b5be28b289ea7c9a6a0cf5805c60c7 data/create/advancements/andesite_casing.json
356f4855a2a6c65be3fb51d7d1aabf2ca6034d42 data/create/advancements/arm_blaze_burner.json

View file

@ -1,21 +1,21 @@
{
"variants": {
"extracting=false,facing=down,powered=false": {
"model": "create:block/andesite_funnel_vertical_pull",
"model": "create:block/andesite_funnel_vertical_filterless_pull",
"x": 180,
"y": 180
},
"extracting=true,facing=down,powered=false": {
"model": "create:block/andesite_funnel_vertical_push",
"model": "create:block/andesite_funnel_vertical_filterless_push",
"x": 180,
"y": 180
},
"extracting=false,facing=up,powered=false": {
"model": "create:block/andesite_funnel_vertical_pull",
"model": "create:block/andesite_funnel_vertical_filterless_pull",
"y": 180
},
"extracting=true,facing=up,powered=false": {
"model": "create:block/andesite_funnel_vertical_push",
"model": "create:block/andesite_funnel_vertical_filterless_push",
"y": 180
},
"extracting=false,facing=north,powered=false": {
@ -49,21 +49,21 @@
"y": 90
},
"extracting=false,facing=down,powered=true": {
"model": "create:block/andesite_funnel_vertical_pull_powered",
"model": "create:block/andesite_funnel_vertical_filterless_pull_powered",
"x": 180,
"y": 180
},
"extracting=true,facing=down,powered=true": {
"model": "create:block/andesite_funnel_vertical_push_powered",
"model": "create:block/andesite_funnel_vertical_filterless_push_powered",
"x": 180,
"y": 180
},
"extracting=false,facing=up,powered=true": {
"model": "create:block/andesite_funnel_vertical_pull_powered",
"model": "create:block/andesite_funnel_vertical_filterless_pull_powered",
"y": 180
},
"extracting=true,facing=up,powered=true": {
"model": "create:block/andesite_funnel_vertical_push_powered",
"model": "create:block/andesite_funnel_vertical_filterless_push_powered",
"y": 180
},
"extracting=false,facing=north,powered=true": {

View file

@ -1,5 +1,5 @@
{
"parent": "create:block/funnel/block_vertical",
"parent": "create:block/funnel/block_vertical_filterless",
"textures": {
"particle": "create:block/andesite_casing",
"7": "create:block/andesite_funnel_plating",

View file

@ -1,5 +1,5 @@
{
"parent": "create:block/funnel/block_vertical",
"parent": "create:block/funnel/block_vertical_filterless",
"textures": {
"particle": "create:block/andesite_casing",
"7": "create:block/andesite_funnel_plating",

View file

@ -1,5 +1,5 @@
{
"parent": "create:block/funnel/block_vertical",
"parent": "create:block/funnel/block_vertical_filterless",
"textures": {
"particle": "create:block/andesite_casing",
"7": "create:block/andesite_funnel_plating",

View file

@ -1,5 +1,5 @@
{
"parent": "create:block/funnel/block_vertical",
"parent": "create:block/funnel/block_vertical_filterless",
"textures": {
"particle": "create:block/andesite_casing",
"7": "create:block/andesite_funnel_plating",

View file

@ -28,8 +28,8 @@
"trigger": "create:bracket_apply",
"conditions": {
"accepted_entries": [
"create:cogwheel",
"create:large_cogwheel"
"create:large_cogwheel",
"create:cogwheel"
]
}
},

View file

@ -1083,7 +1083,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::stone)
.tag(AllBlockTags.SAFE_NBT.tag)
.onRegister(addMovementBehaviour(FunnelMovementBehaviour.andesite()))
.blockstate(new FunnelGenerator("andesite")::generate)
.blockstate(new FunnelGenerator("andesite", false)::generate)
.item(FunnelItem::new)
.model(FunnelGenerator.itemModel("andesite"))
.build()
@ -1102,7 +1102,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::softMetal)
.tag(AllBlockTags.SAFE_NBT.tag)
.onRegister(addMovementBehaviour(FunnelMovementBehaviour.brass()))
.blockstate(new FunnelGenerator("brass")::generate)
.blockstate(new FunnelGenerator("brass", true)::generate)
.item(FunnelItem::new)
.model(FunnelGenerator.itemModel("brass"))
.build()

View file

@ -187,10 +187,10 @@ public class AllShapes {
TANK_TOP_BOTTOM = shape(TANK_BOTTOM_LID).add(TANK_TOP_LID)
.add(TANK)
.build(),
FUNNEL_FLOOR = shape(2, -2, 2, 14, 8, 14).add(1, 2, 1, 15, 8, 15)
FUNNEL_FLOOR = shape(2, -2, 2, 14, 8, 14).add(1, 1, 1, 15, 8, 15)
.add(0, 4, 0, 16, 10, 16)
.build(),
FUNNEL_CEILING = shape(2, 8, 2, 14, 18, 14).add(1, 8, 1, 15, 14, 15)
FUNNEL_CEILING = shape(2, 8, 2, 14, 18, 14).add(1, 8, 1, 15, 15, 15)
.add(0, 6, 0, 16, 12, 16)
.build(),
DEPOT = shape(CASING_11PX.get(Direction.UP)).add(1, 11, 1, 15, 13, 15)

View file

@ -15,7 +15,6 @@ import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel;
import com.simibubi.create.content.contraptions.base.IRotate.StressImpact;
import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.item.TooltipHelper;
import com.simibubi.create.foundation.render.backend.FastRenderDispatcher;

View file

@ -129,7 +129,7 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
if (inventory.remainingTime > 0)
spawnParticles(inventory.getStackInSlot(0));
if (world.isRemote)
if (world.isRemote && !isVirtual())
return;
if (inventory.remainingTime < 20 && !inventory.appliedRecipe) {
@ -317,7 +317,7 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
return;
if (inventory.isEmpty())
return;
if (world.isRemote)
if (world.isRemote && !isVirtual())
return;
List<? extends IRecipe<?>> recipes = getRecipes();

View file

@ -95,10 +95,12 @@ public class ItemDrainTileEntity extends SmartTileEntity {
return;
}
boolean onClient = world.isRemote && !isVirtual();
if (processingTicks > 0) {
heldItem.prevBeltPosition = .5f;
boolean wasAtBeginning = processingTicks == FILLING_TIME;
if (!world.isRemote || processingTicks < FILLING_TIME)
if (!onClient || processingTicks < FILLING_TIME)
processingTicks--;
if (!continueProcessing()) {
processingTicks = 0;
@ -117,7 +119,7 @@ public class ItemDrainTileEntity extends SmartTileEntity {
if (heldItem.beltPosition > 1) {
heldItem.beltPosition = 1;
if (world.isRemote)
if (onClient)
return;
Direction side = heldItem.insertedFrom;
@ -183,7 +185,7 @@ public class ItemDrainTileEntity extends SmartTileEntity {
if (!EmptyingByBasin.canItemBeEmptied(world, heldItem.stack))
return;
heldItem.beltPosition = .5f;
if (world.isRemote)
if (onClient)
return;
processingTicks = FILLING_TIME;
sendData();
@ -192,7 +194,7 @@ public class ItemDrainTileEntity extends SmartTileEntity {
}
protected boolean continueProcessing() {
if (world.isRemote)
if (world.isRemote && !isVirtual())
return true;
if (processingTicks < 5)
return true;

View file

@ -38,7 +38,6 @@ public class BeltInventory {
final List<TransportedItemStack> toInsert;
final List<TransportedItemStack> toRemove;
boolean beltMovementPositive;
boolean virtualMode;
final float SEGMENT_WINDOW = .75f;
public BeltInventory(BeltTileEntity te) {
@ -46,7 +45,6 @@ public class BeltInventory {
items = new LinkedList<>();
toInsert = new LinkedList<>();
toRemove = new LinkedList<>();
virtualMode = false;
}
public void tick() {
@ -84,7 +82,7 @@ public class BeltInventory {
.get(BeltBlock.SLOPE) == BeltSlope.HORIZONTAL;
float spacing = 1;
World world = belt.getWorld();
boolean onClient = world.isRemote && !virtualMode;
boolean onClient = world.isRemote && !belt.isVirtual();
// resolve ending only when items will reach it this tick
Ending ending = Ending.UNRESOLVED;
@ -439,9 +437,4 @@ public class BeltInventory {
return items;
}
// Simulating belt interactions in a client-only world
public void enableVirtualMode() {
virtualMode = true;
}
}

View file

@ -19,9 +19,11 @@ public class FunnelGenerator extends SpecialBlockStateGen {
private String type;
private ResourceLocation particleTexture;
private boolean hasFilter;
public FunnelGenerator(String type) {
public FunnelGenerator(String type, boolean hasFilter) {
this.type = type;
this.hasFilter = hasFilter;
this.particleTexture = Create.asResource("block/" + type + "_casing");
}
@ -44,7 +46,7 @@ public class FunnelGenerator extends SpecialBlockStateGen {
Direction facing = s.get(FunnelBlock.FACING);
boolean horizontal = facing.getAxis()
.isHorizontal();
String parent = horizontal ? "horizontal" : "vertical";
String parent = horizontal ? "horizontal" : hasFilter ? "vertical" : "vertical_filterless";
BlockModelBuilder model = p.models()
.withExistingParent("block/" + type + "_funnel_" + parent + extracting + powered,

View file

@ -36,6 +36,7 @@ import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.Vector4f;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ArmorStandEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
@ -66,6 +67,7 @@ public class PonderScene {
Vec3d pointOfInterest;
Vec3d chasingPointOfInterest;
WorldSectionElement baseWorldSection;
Entity renderViewEntity;
int offsetX;
int offsetZ;
@ -90,6 +92,7 @@ public class PonderScene {
size = getBounds().getXSize();
info = new SceneRenderInfo();
baseWorldSection = new WorldSectionElement();
renderViewEntity = new ArmorStandEntity(world, 0, 0, 0);
PonderLocalization.registerSpecific(component, sceneIndex, "title", "Untitled Scene");
setPointOfInterest(new Vec3d(0, 4, 0));
@ -198,7 +201,13 @@ public class PonderScene {
public void renderScene(SuperRenderTypeBuffer buffer, MatrixStack ms, float pt) {
ms.push();
Minecraft mc = Minecraft.getInstance();
Entity prevRVE = mc.renderViewEntity;
mc.renderViewEntity = this.renderViewEntity;
forEachVisible(PonderSceneElement.class, e -> e.renderFirst(world, buffer, ms, pt));
mc.renderViewEntity = prevRVE;
for (RenderType type : RenderType.getBlockLayers())
forEachVisible(PonderSceneElement.class, e -> e.renderLayer(world, buffer, type, ms, pt));
forEachVisible(PonderSceneElement.class, e -> e.renderLast(world, buffer, ms, pt));
@ -379,6 +388,11 @@ public class PonderScene {
return ms;
}
public void updateSceneRVE() {
Vec3d v = screenToScene(width / 2, height / 2, 500);
renderViewEntity.setPosition(v.x, v.y, v.z);
}
public Vec3d screenToScene(double x, double y, int depth) {
refreshMatrix();
float pt = AnimationTickHolder.getPartialTicks();

View file

@ -221,6 +221,7 @@ public class PonderUI extends AbstractSimiScreen {
ms.push();
story.transform.updateScreenParams(width, height, slide);
story.transform.apply(ms, partialTicks);
story.transform.updateSceneRVE();
story.renderScene(buffer, ms, partialTicks);
buffer.draw();

View file

@ -13,6 +13,7 @@ import com.simibubi.create.content.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.schematics.SchematicWorld;
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
@ -198,14 +199,17 @@ public class PonderWorld extends SchematicWorld {
public void fixVirtualTileEntities() {
for (TileEntity tileEntity : tileEntities.values()) {
if (!(tileEntity instanceof BeltTileEntity))
if (!(tileEntity instanceof SmartTileEntity))
continue;
BeltTileEntity beltTileEntity = (BeltTileEntity) tileEntity;
SmartTileEntity smartTileEntity = (SmartTileEntity) tileEntity;
smartTileEntity.markVirtual();
if (!(smartTileEntity instanceof BeltTileEntity))
continue;
BeltTileEntity beltTileEntity = (BeltTileEntity) smartTileEntity;
if (!beltTileEntity.isController())
continue;
BlockPos controllerPos = tileEntity.getPos();
beltTileEntity.getInventory()
.enableVirtualMode();
for (BlockPos blockPos : BeltBlock.getBeltChain(this, controllerPos)) {
TileEntity tileEntity2 = getTileEntity(blockPos);
if (!(tileEntity2 instanceof BeltTileEntity))

View file

@ -34,6 +34,7 @@ import com.simibubi.create.foundation.ponder.instructions.RotateSceneInstruction
import com.simibubi.create.foundation.ponder.instructions.ShowInputInstruction;
import com.simibubi.create.foundation.ponder.instructions.TextInstruction;
import com.simibubi.create.foundation.ponder.instructions.TileEntityDataInstruction;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult;
@ -44,6 +45,7 @@ import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.particles.RedstoneParticleData;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
@ -245,27 +247,37 @@ public class SceneBuilder {
public void showTargetedText(PonderPalette color, Vec3d position, String key, String defaultText,
int duration) {
PonderLocalization.registerSpecific(scene.component, scene.sceneIndex, key, defaultText);
registerText(key, defaultText);
addInstruction(new TextInstruction(color.getColor(), scene.textGetter(key), duration, position, false));
}
public void showTargetedTextNearScene(PonderPalette color, Vec3d position, String key, String defaultText,
int duration) {
PonderLocalization.registerSpecific(scene.component, scene.sceneIndex, key, defaultText);
registerText(key, defaultText);
addInstruction(new TextInstruction(color.getColor(), scene.textGetter(key), duration, position, true));
}
public void showSelectionWithText(PonderPalette color, Selection selection, String key, String defaultText,
int duration) {
PonderLocalization.registerSpecific(scene.component, scene.sceneIndex, key, defaultText);
addInstruction(new TextInstruction(color.getColor(), scene.textGetter(key), duration, selection));
registerText(key, defaultText);
addInstruction(new TextInstruction(color.getColor(), scene.textGetter(key), duration, selection, false));
}
public void showSelectionWithTextNearScene(PonderPalette color, Selection selection, String key,
String defaultText, int duration) {
registerText(key, defaultText);
addInstruction(new TextInstruction(color.getColor(), scene.textGetter(key), duration, selection, true));
}
public void showText(PonderPalette color, int y, String key, String defaultText, int duration) {
PonderLocalization.registerSpecific(scene.component, scene.sceneIndex, key, defaultText);
registerText(key, defaultText);
addInstruction(new TextInstruction(color.getColor(), scene.textGetter(key), duration, y));
}
private void registerText(String key, String defaultText) {
PonderLocalization.registerSpecific(scene.component, scene.sceneIndex, key, defaultText);
}
public void showControls(InputWindowElement element, int duration) {
addInstruction(new ShowInputInstruction(element.clone(), duration));
}
@ -431,6 +443,21 @@ public class SceneBuilder {
});
}
public void createItemOnBeltLike(BlockPos location, Direction insertionSide, ItemStack stack) {
addInstruction(scene -> {
PonderWorld world = scene.getWorld();
TileEntity tileEntity = world.getTileEntity(location);
if (!(tileEntity instanceof SmartTileEntity))
return;
SmartTileEntity beltTileEntity = (SmartTileEntity) tileEntity;
DirectBeltInputBehaviour behaviour = beltTileEntity.getBehaviour(DirectBeltInputBehaviour.TYPE);
if (behaviour == null)
return;
behaviour.handleInsertion(stack, insertionSide.getOpposite(), false);
});
flapFunnels(scene.getSceneBuildingUtil().select.position(location.up()), true);
}
public ElementLink<BeltItemElement> createItemOnBelt(BlockPos beltLocation, Direction insertionSide,
ItemStack stack) {
ElementLink<BeltItemElement> link = new ElementLink<>(BeltItemElement.class);
@ -492,15 +519,32 @@ public class SceneBuilder {
}
public void modifyKineticSpeed(Selection selection, UnaryOperator<Float> speedFunc) {
addInstruction(new TileEntityDataInstruction(selection, SpeedGaugeTileEntity.class, nbt -> {
modifyTileNBT(selection, SpeedGaugeTileEntity.class, nbt -> {
float newSpeed = speedFunc.apply(nbt.getFloat("Speed"));
nbt.putFloat("Value", SpeedGaugeTileEntity.getDialTarget(newSpeed));
return nbt;
}, false));
addInstruction(new TileEntityDataInstruction(selection, KineticTileEntity.class, nbt -> {
});
modifyTileNBT(selection, KineticTileEntity.class, nbt -> {
nbt.putFloat("Speed", speedFunc.apply(nbt.getFloat("Speed")));
});
}
public void setFilterData(Selection selection, Class<? extends TileEntity> teType, ItemStack filter) {
modifyTileNBT(selection, teType, nbt -> {
nbt.put("Filter", filter.serializeNBT());
});
}
public void modifyTileNBT(Selection selection, Class<? extends TileEntity> teType,
Consumer<CompoundNBT> consumer) {
modifyTileNBT(selection, teType, consumer, false);
}
public void modifyTileNBT(Selection selection, Class<? extends TileEntity> teType,
Consumer<CompoundNBT> consumer, boolean reDrawBlocks) {
addInstruction(new TileEntityDataInstruction(selection, teType, nbt -> {
consumer.accept(nbt);
return nbt;
}, false));
}, reDrawBlocks));
}
public void flapFunnels(Selection selection, boolean outward) {

View file

@ -1,7 +1,10 @@
package com.simibubi.create.foundation.ponder.content;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.FunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity;
import com.simibubi.create.foundation.ponder.ElementLink;
import com.simibubi.create.foundation.ponder.SceneBuilder;
import com.simibubi.create.foundation.ponder.SceneBuildingUtil;
@ -12,12 +15,18 @@ import com.simibubi.create.foundation.ponder.elements.WorldSectionElement;
import com.simibubi.create.foundation.utility.Pointing;
import net.minecraft.block.Blocks;
import net.minecraft.block.LeverBlock;
import net.minecraft.block.RedstoneWireBlock;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.items.ItemHandlerHelper;
public class FunnelScenes {
@ -120,7 +129,7 @@ public class FunnelScenes {
// Placing funnels without sneak
scene.world.showSection(topFunnelSelection, Direction.DOWN);
scene.overlay.showTargetedTextNearScene(PonderPalette.WHITE, topCenter, "regular_place",
"Placed normally, it pull items from the inventory.", 80);
"Placed normally, it pulls items from the inventory.", 80);
scene.idle(45);
ElementLink<EntityElement> itemLink =
@ -138,7 +147,7 @@ public class FunnelScenes {
scene.world.showSection(topFunnelSelection, Direction.DOWN);
scene.overlay.showControls(controlsSneak, 35);
scene.overlay.showTargetedTextNearScene(PonderPalette.WHITE, topCenter, "sneak_place",
"Placed while sneaking, it will put items into the inventory.", 80);
"Placed while sneaking, it puts items into the inventory.", 80);
scene.idle(45);
itemLink = scene.world.createItemEntity(topCenter.add(0, 3, 0), util.vector.of(0, -0.2, 0), itemStack);
@ -197,7 +206,7 @@ public class FunnelScenes {
BlockPos cogPos = util.grid.at(1, 1, 3);
scene.world.showSection(beltFunnelSetup, Direction.DOWN);
scene.overlay.showTargetedText(PonderPalette.WHITE, topOfBeltFunnel, "belt_funnel",
scene.overlay.showTargetedText(PonderPalette.WHITE, topOfBeltFunnel, "belt_funnel_direction",
"Funnels on belts will extract/insert depending on its movement direction.", 140);
scene.idle(15);
@ -224,11 +233,238 @@ public class FunnelScenes {
}
}
public static void mounting(SceneBuilder scene, SceneBuildingUtil util) {
public static void compat(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("Funnel compatibility");
scene.configureBasePlate(0, 0, 5);
BlockPos sawFunnel = util.grid.at(4, 2, 1);
BlockPos depotFunnel = util.grid.at(2, 2, 2);
BlockPos drainFunnel = util.grid.at(0, 2, 3);
scene.world.showSection(util.select.layer(0), Direction.UP);
Selection firstShow = util.select.layer(1)
.add(util.select.position(sawFunnel.south()))
.add(util.select.position(depotFunnel.south()))
.add(util.select.position(drainFunnel.south()));
scene.idle(5);
scene.world.showSection(firstShow, Direction.DOWN);
scene.idle(8);
scene.overlay.showText(PonderPalette.WHITE, 0, "funnels_compat",
"Funnels should also interact nicely with a handful of other components.", 360);
scene.idle(40);
scene.world.showSection(util.select.position(sawFunnel), Direction.DOWN);
scene.overlay.showTargetedTextNearScene(PonderPalette.BLUE, util.vector.centerOf(sawFunnel.down()), "saws",
"Vertical Saws", 40);
scene.idle(8);
scene.world.createItemOnBeltLike(sawFunnel.down(), Direction.SOUTH, new ItemStack(Blocks.OAK_LOG));
scene.idle(40);
scene.world.showSection(util.select.position(depotFunnel), Direction.DOWN);
scene.overlay.showTargetedTextNearScene(PonderPalette.BLUE, util.vector.centerOf(depotFunnel.down()), "depots",
"Depots", 40);
scene.idle(8);
scene.world.createItemOnBeltLike(depotFunnel.down(), Direction.SOUTH, new ItemStack(Items.GOLDEN_PICKAXE));
scene.idle(40);
scene.world.showSection(util.select.position(drainFunnel), Direction.DOWN);
scene.overlay.showTargetedTextNearScene(PonderPalette.BLUE, util.vector.centerOf(drainFunnel.down()), "drains",
"Item Drains", 40);
scene.idle(8);
scene.world.createItemOnBeltLike(drainFunnel.down(), Direction.SOUTH, new ItemStack(Items.WATER_BUCKET));
scene.idle(40);
scene.markAsFinished();
}
public static void redstone(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("Redstone control");
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
scene.idle(5);
scene.world.showSection(util.select.layersFrom(1), Direction.DOWN);
ItemStack itemStack = AllBlocks.BRASS_BLOCK.asStack();
Vec3d topItemSpawn = util.vector.centerOf(3, 6, 2);
ElementLink<EntityElement> lastItemEntity = null;
BlockPos lever = util.grid.at(1, 2, 2);
BlockPos redstone = util.grid.at(2, 2, 2);
BlockPos funnel = util.grid.at(3, 2, 2);
AxisAlignedBB redstoneBB = new AxisAlignedBB(funnel).grow(-1 / 16f, -6 / 16f, -1 / 16f)
.offset(0, -5 / 16f, 0);
for (int i = 0; i < 4; i++) {
if (lastItemEntity != null)
scene.world.modifyEntity(lastItemEntity, Entity::remove);
lastItemEntity = scene.world.createItemEntity(topItemSpawn, util.vector.of(0, -0.2, 0), itemStack);
scene.idle(8);
if (i == 3) {
scene.world.modifyBlock(lever, s -> s.cycle(LeverBlock.POWERED), false);
scene.world.modifyBlock(redstone, s -> s.with(RedstoneWireBlock.POWER, 15), false);
scene.world.modifyBlock(funnel, s -> s.cycle(FunnelBlock.POWERED), false);
scene.effects.indicateRedstone(lever);
scene.idle(4);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.RED, funnel, redstoneBB, 80);
scene.overlay.showTargetedText(PonderPalette.RED, util.vector.blockSurface(funnel, Direction.DOWN),
"redstone_prevents", "Redstone power will prevent any funnel from acting.", 80);
} else {
scene.idle(4);
}
}
}
public static void brass(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("The Brass Funnel");
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
scene.idle(5);
BlockPos firstDepot = util.grid.at(3, 1, 1);
BlockPos secondDepot = util.grid.at(1, 1, 1);
Selection depots = util.select.fromTo(firstDepot, secondDepot);
Selection beltAndStuff = util.select.fromTo(0, 1, 2, 4, 1, 2)
.add(util.select.fromTo(0, 1, 3, 0, 2, 5));
Selection withoutBelt = util.select.layersFrom(1)
.substract(beltAndStuff)
.substract(depots);
scene.world.showSection(withoutBelt, Direction.DOWN);
ElementLink<WorldSectionElement> independentSection =
scene.world.showIndependentSection(depots, Direction.DOWN);
scene.world.moveSection(independentSection, util.vector.of(0, 0, 1), 0);
BlockPos andesiteFunnel = util.grid.at(3, 2, 2);
BlockPos brassFunnel = util.grid.at(1, 2, 2);
ItemStack itemStack = AllItems.BRASS_INGOT.asStack();
scene.idle(10);
scene.overlay.showTargetedTextNearScene(PonderPalette.WHITE, util.vector.topOf(andesiteFunnel), "andesite",
"Andesite Funnels can only ever extract single items.", 60);
scene.idle(10);
scene.world.createItemOnBeltLike(andesiteFunnel.down()
.north(), Direction.SOUTH, itemStack);
scene.world.flapFunnels(util.select.position(andesiteFunnel), true);
scene.idle(60);
scene.overlay.showTargetedTextNearScene(PonderPalette.WHITE, util.vector.topOf(brassFunnel), "brass",
"Brass Funnels can extract up to a full stack.", 60);
scene.idle(10);
scene.world.createItemOnBeltLike(brassFunnel.down()
.north(), Direction.SOUTH, ItemHandlerHelper.copyStackWithSize(itemStack, 64));
scene.world.flapFunnels(util.select.position(brassFunnel), true);
scene.idle(60);
AxisAlignedBB filterSlot = new AxisAlignedBB(brassFunnel).grow(-.35, -.35, -.35)
.offset(0, 0.2, 0);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.WHITE, filterSlot, filterSlot, 80);
scene.overlay.showControls(new InputWindowElement(util.vector.topOf(brassFunnel), Pointing.DOWN).scroll(), 60);
scene.idle(10);
scene.overlay.showTargetedTextNearScene(PonderPalette.WHITE, filterSlot.getCenter(), "scroll_filter",
"Scrolling on the filter slot allows for precise control over the extracted stack size.", 80);
scene.idle(90);
// belt
scene.world.hideIndependentSection(independentSection, Direction.NORTH);
scene.world.hideSection(util.select.position(brassFunnel), Direction.UP);
scene.idle(20);
scene.world.modifyBlock(brassFunnel, s -> s.cycle(BeltFunnelBlock.SHAPE), false);
scene.world.showSection(util.select.position(brassFunnel), Direction.DOWN);
scene.world.showSection(beltAndStuff, Direction.SOUTH);
scene.idle(10);
ItemStack dirt = new ItemStack(Items.DIRT);
ItemStack gravel = new ItemStack(Items.GRAVEL);
ItemStack emerald = new ItemStack(Items.EMERALD);
for (int i = 0; i < 14; i++) {
if (i < 12)
scene.world.createItemOnBelt(andesiteFunnel.down(), Direction.SOUTH,
i % 3 == 0 ? dirt : i % 3 == 1 ? gravel : emerald);
scene.idle(10);
if (i > 0 && (i < 3 || i % 3 == 0)) {
scene.world.removeItemsFromBelt(brassFunnel.down());
scene.world.flapFunnels(util.select.position(brassFunnel), false);
}
scene.world.modifyEntities(ItemEntity.class, e -> {
if (e.getY() < 1)
e.remove();
});
if (i == 2) {
scene.overlay.chaseBoundingBoxOutline(PonderPalette.WHITE, filterSlot, filterSlot, 80);
scene.overlay
.showControls(new InputWindowElement(util.vector.topOf(brassFunnel), Pointing.DOWN).rightClick()
.withItem(emerald), 60);
scene.idle(10);
scene.overlay.showTargetedTextNearScene(PonderPalette.WHITE, filterSlot.getCenter(), "item_filter",
"Using items on the filter slot will restrict the funnel to only transfer matching stacks.", 80);
scene.world.setFilterData(util.select.position(brassFunnel), FunnelTileEntity.class, emerald);
} else
scene.idle(10);
if (i == 8)
scene.markAsFinished();
}
}
public static void transposer(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("Direct transfer");
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
scene.idle(5);
BlockPos funnelPos = util.grid.at(2, 2, 2);
Selection funnelSelect = util.select.position(funnelPos);
ElementLink<WorldSectionElement> rightChest =
scene.world.showIndependentSection(util.select.position(0, 2, 2), Direction.DOWN);
ElementLink<WorldSectionElement> leftChest =
scene.world.showIndependentSection(util.select.position(4, 2, 2), Direction.DOWN);
scene.world.moveSection(rightChest, util.vector.of(2, 1, 0), 0);
scene.world.moveSection(leftChest, util.vector.of(-2, -1, 0), 0);
scene.idle(5);
scene.world.showSection(funnelSelect, Direction.DOWN);
scene.idle(20);
scene.overlay.showSelectionWithTextNearScene(PonderPalette.RED, funnelSelect, "cant_transpose",
"Funnels cannot ever transfer between closed inventories directly.", 40);
scene.idle(50);
scene.world.hideSection(funnelSelect, Direction.SOUTH);
scene.idle(20);
scene.world.setBlocks(funnelSelect, AllBlocks.CHUTE.getDefaultState(), false);
scene.world.showSection(funnelSelect, Direction.NORTH);
scene.idle(10);
scene.overlay.showTargetedTextNearScene(PonderPalette.GREEN, util.vector.centerOf(funnelPos), "chute_is_better",
"Chutes or Smart chutes might be more suitable for such purposes.", 40);
scene.idle(50);
scene.world.hideSection(funnelSelect, Direction.UP);
scene.world.hideIndependentSection(leftChest, Direction.UP);
scene.world.hideIndependentSection(rightChest, Direction.UP);
scene.idle(20);
Selection belt = util.select.layer(1);
scene.world.setBlocks(funnelSelect, Blocks.AIR.getDefaultState(), false);
scene.world.showSection(belt, Direction.DOWN);
scene.world.showSection(util.select.fromTo(0, 2, 2, 4, 2, 2), Direction.DOWN);
scene.overlay.showTargetedTextNearScene(PonderPalette.GREEN, util.vector.topOf(1, 2, 2), "belt_is_better",
"Same applies for horizontal movement.\nA mechanical belt should help here.", 120);
scene.markAsFinished();
}
}

View file

@ -16,13 +16,15 @@ public class PonderIndex {
.addStoryBoard("shaft/relay", KineticsScenes::shaftAsRelay)
.addStoryBoard("shaft/encasing", KineticsScenes::shaftsCanBeEncased);
// Funnels
PonderRegistry.addStoryBoard(AllBlocks.BRASS_FUNNEL, "funnels/brass", FunnelScenes::brass);
PonderRegistry.forComponents(AllBlocks.ANDESITE_FUNNEL, AllBlocks.BRASS_FUNNEL)
.addStoryBoard("funnels/intro", FunnelScenes::intro)
.addStoryBoard("funnels/direction", FunnelScenes::directionality)
.addStoryBoard("funnels/mounting", FunnelScenes::mounting);
// redstone
// brass vs andesite
// arm compat?
.addStoryBoard("funnels/compat", FunnelScenes::compat)
.addStoryBoard("funnels/redstone", FunnelScenes::redstone)
.addStoryBoard("funnels/transposer", FunnelScenes::transposer);
PonderRegistry.addStoryBoard(AllBlocks.ANDESITE_FUNNEL, "funnels/brass", FunnelScenes::brass);
// Debug scenes, can be found in game via the Brass Hand
if (EDITOR_MODE)

View file

@ -134,16 +134,20 @@ public class WorldSectionElement extends AnimatedSceneElement {
section = null;
}
public void setAnimatedRotation(Vec3d eulerAngles) {
public void setAnimatedRotation(Vec3d eulerAngles, boolean force) {
this.animatedRotation = eulerAngles;
if (force)
prevAnimatedRotation = animatedRotation;
}
public Vec3d getAnimatedRotation() {
return animatedRotation;
}
public void setAnimatedOffset(Vec3d offset) {
public void setAnimatedOffset(Vec3d offset, boolean force) {
this.animatedOffset = offset;
if (force)
prevAnimatedOffset = animatedOffset;
}
public Vec3d getAnimatedOffset() {

View file

@ -22,12 +22,12 @@ public class AnimateWorldSectionInstruction extends TickingInstruction {
public static AnimateWorldSectionInstruction rotate(ElementLink<WorldSectionElement> link, Vec3d rotation,
int ticks) {
return new AnimateWorldSectionInstruction(link, rotation, ticks, WorldSectionElement::setAnimatedRotation,
WorldSectionElement::getAnimatedRotation);
return new AnimateWorldSectionInstruction(link, rotation, ticks,
(wse, v) -> wse.setAnimatedRotation(v, ticks == 0), WorldSectionElement::getAnimatedRotation);
}
public static AnimateWorldSectionInstruction move(ElementLink<WorldSectionElement> link, Vec3d offset, int ticks) {
return new AnimateWorldSectionInstruction(link, offset, ticks, WorldSectionElement::setAnimatedOffset,
return new AnimateWorldSectionInstruction(link, offset, ticks, (wse, v) -> wse.setAnimatedOffset(v, ticks == 0),
WorldSectionElement::getAnimatedOffset);
}

View file

@ -18,13 +18,15 @@ public class TextInstruction extends FadeInOutInstruction {
super(duration);
}
public TextInstruction(int color, Supplier<String> text, int duration, Selection selection) {
public TextInstruction(int color, Supplier<String> text, int duration, Selection selection, boolean near) {
this(color, text, duration);
element = new TextWindowElement(text).pointAt(selection.getCenter());
element.colored(color);
outline = new OutlinerElement(o -> selection.makeOutline(o)
.lineWidth(1 / 16f)
.colored(color));
if (near)
element.placeNearTarget();
}
public TextInstruction(int color, Supplier<String> text, int duration, Vec3d position, boolean near) {

View file

@ -23,6 +23,9 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
private int lazyTickRate;
private int lazyTickCounter;
// Used for simulating this TE in a client-only setting
private boolean virtualMode;
public SmartTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
behaviours = new HashMap<>();
@ -157,4 +160,12 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
return cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY;
}
public void markVirtual() {
virtualMode = true;
}
public boolean isVirtual() {
return virtualMode;
}
}

View file

@ -0,0 +1,168 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"3": "create:block/brass_funnel_back",
"5": "create:block/brass_funnel_tall",
"7": "create:block/brass_funnel_plating",
"8": "create:block/brass_storage_block",
"9": "create:block/brass_funnel_slope",
"10": "create:block/funnel_closed",
"2_2": "create:block/brass_funnel_pull"
},
"elements": [
{
"name": "LeftWall",
"from": [0, 4, 0],
"to": [2, 10, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 2]},
"faces": {
"north": {"uv": [14, 0, 16, 6], "texture": "#2_2"},
"south": {"uv": [0, 0, 2, 6], "texture": "#2_2"},
"west": {"uv": [0, 0, 16, 6], "texture": "#2_2"},
"up": {"uv": [0, 0, 2, 16], "texture": "#8"},
"down": {"uv": [0, 0, 16, 2], "rotation": 270, "texture": "#8"}
}
},
{
"name": "LeftWall",
"from": [14, 4, 0],
"to": [16, 10, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 2]},
"faces": {
"north": {"uv": [2, 0, 0, 6], "rotation": 180, "texture": "#2_2"},
"east": {"uv": [0, 6, 16, 0], "rotation": 180, "texture": "#2_2"},
"south": {"uv": [14, 0, 16, 6], "texture": "#2_2"},
"up": {"uv": [14, 0, 16, 16], "texture": "#8"},
"down": {"uv": [0, 14, 16, 16], "rotation": 270, "texture": "#8"}
}
},
{
"name": "Top",
"from": [2, 4, 0],
"to": [14, 10, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 2]},
"faces": {
"north": {"uv": [2, 0, 14, 6], "texture": "#2_2"},
"up": {"uv": [2, 0, 14, 2], "texture": "#8"},
"down": {"uv": [0, 2, 2, 14], "rotation": 270, "texture": "#8"}
}
},
{
"name": "Top",
"from": [2, 4, 14],
"to": [14, 10, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 18]},
"faces": {
"south": {"uv": [14, 0, 2, 6], "texture": "#2_2"},
"up": {"uv": [2, 16, 14, 14], "rotation": 180, "texture": "#8"},
"down": {"uv": [14, 14, 16, 2], "rotation": 270, "texture": "#8"}
}
},
{
"from": [1, 1, 1],
"to": [15, 4, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [7, -6, 10]},
"faces": {
"north": {"uv": [1, 0, 15, 3], "texture": "#5"},
"east": {"uv": [1, 0, 15, 3], "texture": "#5"},
"south": {"uv": [1, 0, 15, 3], "texture": "#5"},
"west": {"uv": [1, 0, 15, 3], "texture": "#5"},
"down": {"uv": [2, 2, 14, 14], "rotation": 270, "texture": "#8"}
}
},
{
"from": [1, 5, 2],
"to": [2, 10, 14],
"rotation": {"angle": 22.5, "axis": "z", "origin": [2, 10, 8]},
"faces": {
"east": {"uv": [2, 2, 14, 7], "texture": "#9"}
}
},
{
"from": [14, 5, 2],
"to": [15, 10, 14],
"rotation": {"angle": -22.5, "axis": "z", "origin": [14, 10, 8]},
"faces": {
"west": {"uv": [2, 2, 14, 7], "texture": "#9"}
}
},
{
"from": [2, 5, 14],
"to": [14, 10, 15],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 10, 14]},
"faces": {
"north": {"uv": [2, 2, 14, 7], "texture": "#9"}
}
},
{
"from": [2, 5, 1],
"to": [14, 10, 2],
"rotation": {"angle": -22.5, "axis": "x", "origin": [8, 10, 2]},
"faces": {
"south": {"uv": [2, 2, 14, 7], "texture": "#9"}
}
},
{
"from": [3, 5, 3],
"to": [13, 6, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [11, 13, 11]},
"faces": {
"up": {"uv": [3, 3, 13, 13], "texture": "#10"}
}
},
{
"name": "Back",
"from": [1.95, -1.95, 1.95],
"to": [14.05, 2, 14.05],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0.025, 8]},
"faces": {
"north": {"uv": [2, 12, 14, 16], "texture": "#9"},
"east": {"uv": [2, 12, 14, 16], "texture": "#9"},
"south": {"uv": [2, 12, 14, 16], "texture": "#9"},
"west": {"uv": [2, 12, 14, 16], "texture": "#9"},
"down": {"uv": [6, 8, 12, 14], "rotation": 180, "texture": "#3"}
}
},
{
"name": "Back",
"from": [2.1, 2, 2.05],
"to": [13.9, 4.1, 13.1],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -6, 24.1]},
"faces": {
"east": {"uv": [2.5, 1.5, 8, 0.5], "texture": "#5"},
"west": {"uv": [2.5, 0.5, 8, 1.5], "rotation": 180, "texture": "#5"}
}
}
],
"display": {},
"groups": [
{
"name": "block_retracted",
"origin": [8, 8, 8],
"children": [
{
"name": "BeltFunnel",
"origin": [9, -4, 8],
"children": [
{
"name": "FrontSection",
"origin": [9, -4, 8],
"children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
},
{
"name": "Base",
"origin": [9, -4, 8],
"children": [10, 11]
}
]
}
]
},
{
"name": "Item Filter",
"origin": [8, 0, 8],
"children": [12, 13, 14, 15]
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.