mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-28 16:06:48 +01:00
Mechanical Arm Implementation
- The arm blockitem can now be used to select inputs & outputs - Arms now transfer items between inputs and outputs - Arm support for Belts, Depots and Funnels - Some safety checks in net code - Minor refactor to NBTHelper
This commit is contained in:
parent
5411bc3565
commit
f820e2be27
44 changed files with 1104 additions and 129 deletions
|
@ -29,7 +29,7 @@ public class AllBlockPartials {
|
|||
private static List<AllBlockPartials> all = new ArrayList<>();
|
||||
|
||||
public static final AllBlockPartials
|
||||
SCHEMATICANNON_CONNECTOR = get("schematicannon/connector"),
|
||||
SCHEMATICANNON_CONNECTOR = get("schematicannon/connector"),
|
||||
SCHEMATICANNON_PIPE = get("schematicannon/pipe"),
|
||||
|
||||
SHAFTLESS_COGWHEEL = get("cogwheel_shaftless"),
|
||||
|
@ -92,6 +92,11 @@ public class AllBlockPartials {
|
|||
ARM_CLAW_BASE = get("mechanical_arm/claw_base"),
|
||||
ARM_CLAW_GRIP = get("mechanical_arm/claw_grip"),
|
||||
|
||||
FLAG_SHORT_IN = get("mechanical_arm/flag/short_in"),
|
||||
FLAG_SHORT_OUT = get("mechanical_arm/flag/short_out"),
|
||||
FLAG_LONG_IN = get("mechanical_arm/flag/long_in"),
|
||||
FLAG_LONG_OUT = get("mechanical_arm/flag/long_out"),
|
||||
|
||||
MECHANICAL_PUMP_ARROW = get("mechanical_pump/arrow"),
|
||||
MECHANICAL_PUMP_COG = get("mechanical_pump/cog"),
|
||||
FLUID_PIPE_CASING = get("fluid_pipe/casing");
|
||||
|
|
|
@ -96,6 +96,7 @@ import com.simibubi.create.content.logistics.block.funnel.VerticalFunnelGenerato
|
|||
import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateBlock;
|
||||
import com.simibubi.create.content.logistics.block.inventories.CreativeCrateBlock;
|
||||
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmBlock;
|
||||
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmItem;
|
||||
import com.simibubi.create.content.logistics.block.packager.PackagerBlock;
|
||||
import com.simibubi.create.content.logistics.block.realityFunnel.BeltFunnelBlock;
|
||||
import com.simibubi.create.content.logistics.block.realityFunnel.BeltFunnelGenerator;
|
||||
|
@ -781,7 +782,7 @@ public class AllBlocks {
|
|||
.initialProperties(SharedProperties::softMetal)
|
||||
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
|
||||
.transform(StressConfigDefaults.setImpact(8.0))
|
||||
.item()
|
||||
.item(ArmItem::new)
|
||||
.transform(customItemModel())
|
||||
.register();
|
||||
|
||||
|
|
|
@ -109,7 +109,6 @@ public class ClientEvents {
|
|||
return;
|
||||
|
||||
double delta = event.getScrollDelta();
|
||||
|
||||
boolean cancelled = CreateClient.schematicHandler.mouseScrolled(delta)
|
||||
|| CreateClient.schematicAndQuillHandler.mouseScrolled(delta) || FilteringHandler.onScroll(delta)
|
||||
|| ScrollValueHandler.onScroll(delta);
|
||||
|
|
|
@ -14,6 +14,7 @@ import com.simibubi.create.content.curiosities.tools.ExtendoGripRenderHandler;
|
|||
import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler;
|
||||
import com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperRenderHandler;
|
||||
import com.simibubi.create.content.curiosities.zapper.terrainzapper.WorldshaperRenderHandler;
|
||||
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPointHandler;
|
||||
import com.simibubi.create.content.schematics.ClientSchematicLoader;
|
||||
import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler;
|
||||
import com.simibubi.create.content.schematics.client.SchematicHandler;
|
||||
|
@ -109,6 +110,7 @@ public class CreateClient {
|
|||
KineticDebugger.tick();
|
||||
ZapperRenderHandler.tick();
|
||||
ExtendoGripRenderHandler.tick();
|
||||
ArmInteractionPointHandler.tick();
|
||||
outliner.tickOutlines();
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ public class CuckooClockRenderer extends KineticTileEntityRenderer {
|
|||
.renderInto(ms, vb);
|
||||
|
||||
// Figure
|
||||
if (clock.animationType != null) {
|
||||
if (clock.animationType != Animation.NONE) {
|
||||
offset = -(angle / 135) * 1 / 2f + 10 / 16f;
|
||||
SuperByteBuffer figure =
|
||||
(clock.animationType == Animation.PIG ? AllBlockPartials.CUCKOO_PIG : AllBlockPartials.CUCKOO_CREEPER)
|
||||
|
|
|
@ -32,17 +32,18 @@ public class CuckooClockTileEntity extends KineticTileEntity {
|
|||
private boolean sendAnimationUpdate;
|
||||
|
||||
enum Animation {
|
||||
PIG, CREEPER, SURPRISE;
|
||||
PIG, CREEPER, SURPRISE, NONE;
|
||||
}
|
||||
|
||||
public CuckooClockTileEntity(TileEntityType<? extends CuckooClockTileEntity> type) {
|
||||
super(type);
|
||||
animationType = Animation.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
||||
if (sendAnimationUpdate)
|
||||
compound.putString("Animation", animationType == null ? "none" : NBTHelper.writeEnum(animationType));
|
||||
NBTHelper.writeEnum(compound, "Animation", animationType);
|
||||
sendAnimationUpdate = false;
|
||||
return super.writeToClient(compound);
|
||||
}
|
||||
|
@ -50,11 +51,7 @@ public class CuckooClockTileEntity extends KineticTileEntity {
|
|||
@Override
|
||||
public void readClientUpdate(CompoundNBT tag) {
|
||||
if (tag.contains("Animation")) {
|
||||
String string = tag.getString("Animation");
|
||||
if ("none".equals(string))
|
||||
animationType = null;
|
||||
else
|
||||
animationType = NBTHelper.readEnum(string, Animation.class);
|
||||
animationType = NBTHelper.readEnum(tag, "Animation", Animation.class);
|
||||
animationProgress.lastValue = 0;
|
||||
animationProgress.value = 0;
|
||||
}
|
||||
|
@ -72,7 +69,7 @@ public class CuckooClockTileEntity extends KineticTileEntity {
|
|||
int minutes = (dayTime % 1000) * 60 / 1000;
|
||||
|
||||
if (!world.isRemote) {
|
||||
if (animationType == null) {
|
||||
if (animationType == Animation.NONE) {
|
||||
if (hours == 12 && minutes < 5)
|
||||
startAnimation(Animation.PIG);
|
||||
if (hours == 18 && minutes < 36 && minutes > 31)
|
||||
|
@ -81,13 +78,13 @@ public class CuckooClockTileEntity extends KineticTileEntity {
|
|||
float value = animationProgress.value;
|
||||
animationProgress.set(value + 1);
|
||||
if (value > 100)
|
||||
animationType = null;
|
||||
animationType = Animation.NONE;
|
||||
|
||||
if (animationType == Animation.SURPRISE && animationProgress.value == 50) {
|
||||
Vec3d center = VecHelper.getCenterOf(pos);
|
||||
world.destroyBlock(pos, false);
|
||||
world.createExplosion(null, CUCKOO_SURPRISE, center.x, center.y, center.z, 3, false,
|
||||
Explosion.Mode.BREAK);
|
||||
Explosion.Mode.BREAK);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -96,7 +93,7 @@ public class CuckooClockTileEntity extends KineticTileEntity {
|
|||
if (world.isRemote) {
|
||||
moveHands(hours, minutes);
|
||||
|
||||
if (animationType == null) {
|
||||
if (animationType == Animation.NONE) {
|
||||
if (AnimationTickHolder.ticks % 32 == 0)
|
||||
playSound(SoundEvents.BLOCK_NOTE_BLOCK_HAT, 1 / 16f, 2f);
|
||||
else if (AnimationTickHolder.ticks % 16 == 0)
|
||||
|
|
|
@ -162,7 +162,7 @@ public class DeployerMovementBehaviour extends MovementBehaviour {
|
|||
}
|
||||
|
||||
private Mode getMode(MovementContext context) {
|
||||
return NBTHelper.readEnum(context.tileData.getString("Mode"), Mode.class);
|
||||
return NBTHelper.readEnum(context.tileData, "Mode", Mode.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -160,7 +160,7 @@ public class DeployerRenderer extends SafeTileEntityRenderer<DeployerTileEntity>
|
|||
IVertexBuilder builder = buffer.getBuffer(RenderType.getSolid());
|
||||
BlockState blockState = context.state;
|
||||
BlockPos pos = BlockPos.ZERO;
|
||||
Mode mode = NBTHelper.readEnum(context.tileData.getString("Mode"), Mode.class);
|
||||
Mode mode = NBTHelper.readEnum(context.tileData, "Mode", Mode.class);
|
||||
World world = context.world;
|
||||
AllBlockPartials handPose =
|
||||
mode == Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING : AllBlockPartials.DEPLOYER_HAND_POINTING;
|
||||
|
|
|
@ -333,8 +333,8 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
|
||||
@Override
|
||||
public void read(CompoundNBT compound) {
|
||||
state = NBTHelper.readEnum(compound.getString("State"), State.class);
|
||||
mode = NBTHelper.readEnum(compound.getString("Mode"), Mode.class);
|
||||
state = NBTHelper.readEnum(compound, "State", State.class);
|
||||
mode = NBTHelper.readEnum(compound, "Mode", Mode.class);
|
||||
timer = compound.getInt("Timer");
|
||||
deferredInventoryList = compound.getList("Inventory", NBT.TAG_COMPOUND);
|
||||
overflowItems = NBTHelper.readItemList(compound.getList("Overflow", NBT.TAG_COMPOUND));
|
||||
|
@ -345,8 +345,8 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT compound) {
|
||||
compound.putString("Mode", NBTHelper.writeEnum(mode));
|
||||
compound.putString("State", NBTHelper.writeEnum(state));
|
||||
NBTHelper.writeEnum(compound, "Mode", mode);
|
||||
NBTHelper.writeEnum(compound, "State", state);
|
||||
compound.putInt("Timer", timer);
|
||||
if (player != null) {
|
||||
compound.put("HeldItem", player.getHeldItemMainhand().serializeNBT());
|
||||
|
|
|
@ -24,6 +24,8 @@ public class CancelPlayerFallPacket extends SimplePacketBase {
|
|||
public void handle(Supplier<Context> context) {
|
||||
context.get().enqueueWork(() -> {
|
||||
ServerPlayerEntity sender = context.get().getSender();
|
||||
if (sender == null)
|
||||
return;
|
||||
sender.handleFallDamage(sender.fallDistance, 1.0F);
|
||||
sender.fallDistance = 0;
|
||||
sender.onGround = true;
|
||||
|
|
|
@ -98,14 +98,14 @@ public class ClockworkContraption extends Contraption {
|
|||
CompoundNBT tag = super.writeNBT();
|
||||
tag.putInt("facing", facing.getIndex());
|
||||
tag.putInt("offset", offset);
|
||||
tag.putString("HandType", NBTHelper.writeEnum(handType));
|
||||
NBTHelper.writeEnum(tag, "HandType", handType);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNBT(World world, CompoundNBT tag) {
|
||||
facing = Direction.byIndex(tag.getInt("Facing"));
|
||||
handType = NBTHelper.readEnum(tag.getString("HandType"), HandType.class);
|
||||
handType = NBTHelper.readEnum(tag, "HandType", HandType.class);
|
||||
offset = tag.getInt("offset");
|
||||
super.readNBT(world, tag);
|
||||
}
|
||||
|
|
|
@ -80,13 +80,13 @@ public class MountedContraption extends Contraption {
|
|||
@Override
|
||||
public CompoundNBT writeNBT() {
|
||||
CompoundNBT writeNBT = super.writeNBT();
|
||||
writeNBT.putString("RotationMode", NBTHelper.writeEnum(rotationMode));
|
||||
NBTHelper.writeEnum(writeNBT, "RotationMode", rotationMode);
|
||||
return writeNBT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNBT(World world, CompoundNBT nbt) {
|
||||
rotationMode = NBTHelper.readEnum(nbt.getString("RotationMode"), CartMovementMode.class);
|
||||
rotationMode = NBTHelper.readEnum(nbt, "RotationMode", CartMovementMode.class);
|
||||
super.readNBT(world, nbt);
|
||||
}
|
||||
|
||||
|
|
|
@ -88,16 +88,16 @@ public class Instruction {
|
|||
|
||||
CompoundNBT serialize() {
|
||||
CompoundNBT tag = new CompoundNBT();
|
||||
tag.putString("Type", NBTHelper.writeEnum(instruction));
|
||||
tag.putString("Modifier", NBTHelper.writeEnum(speedModifier));
|
||||
NBTHelper.writeEnum(tag, "Type", instruction);
|
||||
NBTHelper.writeEnum(tag, "Modifier", speedModifier);
|
||||
tag.putInt("Value", value);
|
||||
return tag;
|
||||
}
|
||||
|
||||
static Instruction deserialize(CompoundNBT tag) {
|
||||
Instruction instruction =
|
||||
new Instruction(NBTHelper.readEnum(tag.getString("Type"), SequencerInstructions.class));
|
||||
instruction.speedModifier = NBTHelper.readEnum(tag.getString("Modifier"), InstructionSpeedModifiers.class);
|
||||
new Instruction(NBTHelper.readEnum(tag, "Type", SequencerInstructions.class));
|
||||
instruction.speedModifier = NBTHelper.readEnum(tag, "Modifier", InstructionSpeedModifiers.class);
|
||||
instruction.value = tag.getInt("Value");
|
||||
return instruction;
|
||||
}
|
||||
|
|
|
@ -352,8 +352,8 @@ public class BeltInventory {
|
|||
}
|
||||
|
||||
public TransportedItemStack getStackAtOffset(int offset) {
|
||||
float min = offset + .5f - (SEGMENT_WINDOW / 2);
|
||||
float max = offset + .5f + (SEGMENT_WINDOW / 2);
|
||||
float min = offset;
|
||||
float max = offset + 1;
|
||||
for (TransportedItemStack stack : items) {
|
||||
if (stack.beltPosition > max)
|
||||
continue;
|
||||
|
|
|
@ -57,6 +57,8 @@ public class ExtendoGripInteractionPacket extends SimplePacketBase {
|
|||
.enqueueWork(() -> {
|
||||
ServerPlayerEntity sender = context.get()
|
||||
.getSender();
|
||||
if (sender == null)
|
||||
return;
|
||||
Entity entityByID = sender.getServerWorld()
|
||||
.getEntityByID(target);
|
||||
if (entityByID != null && ExtendoGripItem.isHoldingExtendoGrip(sender)) {
|
||||
|
|
|
@ -351,17 +351,16 @@ public class BlockzapperItem extends ZapperItem {
|
|||
.contains(component.name()))
|
||||
stack.getOrCreateTag()
|
||||
.putString(component.name(), ComponentTier.None.name());
|
||||
return NBTHelper.readEnum(stack.getTag()
|
||||
.getString(component.name()), ComponentTier.class);
|
||||
return NBTHelper.readEnum(stack.getTag(), component.name(), ComponentTier.class);
|
||||
}
|
||||
|
||||
public static void setTier(Components component, ComponentTier tier, ItemStack stack) {
|
||||
stack.getOrCreateTag()
|
||||
.putString(component.name(), NBTHelper.writeEnum(tier));
|
||||
NBTHelper.writeEnum(stack.getOrCreateTag(), component.name(), tier);
|
||||
}
|
||||
|
||||
public static enum ComponentTier {
|
||||
None(TextFormatting.DARK_GRAY), Brass(TextFormatting.GOLD), Chromatic(TextFormatting.LIGHT_PURPLE);
|
||||
|
||||
public TextFormatting color;
|
||||
|
||||
private ComponentTier(TextFormatting color) {
|
||||
|
|
|
@ -53,7 +53,7 @@ public class WorldshaperItem extends ZapperItem {
|
|||
@Override
|
||||
protected boolean canActivateWithoutSelectedBlock(ItemStack stack) {
|
||||
CompoundNBT tag = stack.getOrCreateTag();
|
||||
TerrainTools tool = NBTHelper.readEnum(tag.getString("Tool"), TerrainTools.class);
|
||||
TerrainTools tool = NBTHelper.readEnum(tag, "Tool", TerrainTools.class);
|
||||
return !tool.requiresSelectedBlock();
|
||||
}
|
||||
|
||||
|
@ -65,11 +65,11 @@ public class WorldshaperItem extends ZapperItem {
|
|||
List<BlockPos> affectedPositions = new ArrayList<>();
|
||||
|
||||
CompoundNBT tag = stack.getOrCreateTag();
|
||||
Brush brush = NBTHelper.readEnum(tag.getString("Brush"), TerrainBrushes.class)
|
||||
Brush brush = NBTHelper.readEnum(tag, "Brush", TerrainBrushes.class)
|
||||
.get();
|
||||
BlockPos params = NBTUtil.readBlockPos(tag.getCompound("BrushParams"));
|
||||
PlacementOptions option = NBTHelper.readEnum(tag.getString("Placement"), PlacementOptions.class);
|
||||
TerrainTools tool = NBTHelper.readEnum(tag.getString("Tool"), TerrainTools.class);
|
||||
PlacementOptions option = NBTHelper.readEnum(tag, "Placement", PlacementOptions.class);
|
||||
TerrainTools tool = NBTHelper.readEnum(tag, "Tool", TerrainTools.class);
|
||||
|
||||
brush.set(params.getX(), params.getY(), params.getZ());
|
||||
targetPos = targetPos.add(brush.getOffset(player.getLookVec(), raytrace.getFace(), option));
|
||||
|
|
|
@ -69,9 +69,9 @@ public class WorldshaperRenderHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
Brush brush = NBTHelper.readEnum(tag.getString("Brush"), TerrainBrushes.class)
|
||||
Brush brush = NBTHelper.readEnum(tag, "Brush", TerrainBrushes.class)
|
||||
.get();
|
||||
PlacementOptions placement = NBTHelper.readEnum(tag.getString("Placement"), PlacementOptions.class);
|
||||
PlacementOptions placement = NBTHelper.readEnum(tag, "Placement", PlacementOptions.class);
|
||||
BlockPos params = NBTUtil.readBlockPos(tag.getCompound("BrushParams"));
|
||||
brush.set(params.getX(), params.getY(), params.getZ());
|
||||
renderedShape = brush.getIncludedPositions();
|
||||
|
|
|
@ -53,9 +53,12 @@ public class WorldshaperScreen extends ZapperScreen {
|
|||
|
||||
brushLabel = new Label(i + 58, j + 28, "").withShadow();
|
||||
brushInput = new SelectionScrollInput(i + 55, j + 25, 78, 14).forOptions(brushOptions)
|
||||
.titled(Lang.translate("gui.terrainzapper.brush")).writingTo(brushLabel).calling(this::brushChanged);
|
||||
.titled(Lang.translate("gui.terrainzapper.brush"))
|
||||
.writingTo(brushLabel)
|
||||
.calling(this::brushChanged);
|
||||
if (nbt.contains("Brush"))
|
||||
brushInput.setState(NBTHelper.readEnum(nbt.getString("Brush"), TerrainBrushes.class).ordinal());
|
||||
brushInput.setState(NBTHelper.readEnum(nbt, "Brush", TerrainBrushes.class)
|
||||
.ordinal());
|
||||
|
||||
widgets.add(brushLabel);
|
||||
widgets.add(brushInput);
|
||||
|
@ -66,11 +69,13 @@ public class WorldshaperScreen extends ZapperScreen {
|
|||
for (int id = 0; id < toolValues.length; id++) {
|
||||
TerrainTools tool = toolValues[id];
|
||||
toolButtons.add(new IconButton(i + 8 + id * 18, j + 76, tool.icon));
|
||||
toolButtons.get(id).setToolTip(Lang.translate("gui.terrainzapper.tool." + tool.translationKey));
|
||||
toolButtons.get(id)
|
||||
.setToolTip(Lang.translate("gui.terrainzapper.tool." + tool.translationKey));
|
||||
}
|
||||
|
||||
if (nbt.contains("Tool"))
|
||||
toolButtons.get(NBTHelper.readEnum(nbt.getString("Tool"), TerrainTools.class).ordinal()).active = false;
|
||||
toolButtons.get(NBTHelper.readEnum(nbt, "Tool", TerrainTools.class)
|
||||
.ordinal()).active = false;
|
||||
widgets.addAll(toolButtons);
|
||||
|
||||
placementButtons = new Vector<>(3);
|
||||
|
@ -78,21 +83,25 @@ public class WorldshaperScreen extends ZapperScreen {
|
|||
for (int id = 0; id < placementValues.length; id++) {
|
||||
PlacementOptions option = placementValues[id];
|
||||
placementButtons.add(new IconButton(i + 147 + id * 18, j + 76, option.icon));
|
||||
placementButtons.get(id).setToolTip(Lang.translate("gui.terrainzapper.placement." + option.translationKey));
|
||||
placementButtons.get(id)
|
||||
.setToolTip(Lang.translate("gui.terrainzapper.placement." + option.translationKey));
|
||||
}
|
||||
|
||||
if (nbt.contains("Placement"))
|
||||
placementButtons
|
||||
.get(NBTHelper.readEnum(nbt.getString("Placement"), PlacementOptions.class).ordinal()).active =
|
||||
false;
|
||||
placementButtons.get(NBTHelper.readEnum(nbt, "Placement", PlacementOptions.class)
|
||||
.ordinal()).active = false;
|
||||
widgets.addAll(placementButtons);
|
||||
|
||||
}
|
||||
|
||||
public void initBrushParams() {
|
||||
if (brushParams != null) {
|
||||
nbt.put("BrushParams", NBTUtil.writeBlockPos(new BlockPos(brushParams.get(0).getState(),
|
||||
brushParams.get(1).getState(), brushParams.get(2).getState())));
|
||||
nbt.put("BrushParams", NBTUtil.writeBlockPos(new BlockPos(brushParams.get(0)
|
||||
.getState(),
|
||||
brushParams.get(1)
|
||||
.getState(),
|
||||
brushParams.get(2)
|
||||
.getState())));
|
||||
|
||||
widgets.removeAll(brushParamLabels);
|
||||
widgets.removeAll(brushParams);
|
||||
|
@ -109,10 +118,12 @@ public class WorldshaperScreen extends ZapperScreen {
|
|||
brushParamLabels.add(label);
|
||||
int indexFinal = index;
|
||||
ScrollInput input = new ScrollInput(i + 55 + 18 * index, j + 43, 14, 14)
|
||||
.withRange(currentBrush.getMin(index), currentBrush.getMax(index) + 1).writingTo(label)
|
||||
.titled(currentBrush.getParamLabel(index)).calling(state -> {
|
||||
label.x = i + 62 + 18 * indexFinal - font.getStringWidth(label.text) / 2;
|
||||
});
|
||||
.withRange(currentBrush.getMin(index), currentBrush.getMax(index) + 1)
|
||||
.writingTo(label)
|
||||
.titled(currentBrush.getParamLabel(index))
|
||||
.calling(state -> {
|
||||
label.x = i + 62 + 18 * indexFinal - font.getStringWidth(label.text) / 2;
|
||||
});
|
||||
input.setState(params[index]);
|
||||
input.onChanged();
|
||||
if (index >= currentBrush.amtParams) {
|
||||
|
@ -140,7 +151,8 @@ public class WorldshaperScreen extends ZapperScreen {
|
|||
if (placementButton.isHovered()) {
|
||||
placementButtons.forEach(b -> b.active = true);
|
||||
placementButton.active = false;
|
||||
placementButton.playDownSound(Minecraft.getInstance().getSoundHandler());
|
||||
placementButton.playDownSound(Minecraft.getInstance()
|
||||
.getSoundHandler());
|
||||
nbt.putString("Placement", PlacementOptions.values()[placementButtons.indexOf(placementButton)].name());
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +161,8 @@ public class WorldshaperScreen extends ZapperScreen {
|
|||
if (toolButton.isHovered()) {
|
||||
toolButtons.forEach(b -> b.active = true);
|
||||
toolButton.active = false;
|
||||
toolButton.playDownSound(Minecraft.getInstance().getSoundHandler());
|
||||
toolButton.playDownSound(Minecraft.getInstance()
|
||||
.getSoundHandler());
|
||||
nbt.putString("Tool", TerrainTools.values()[toolButtons.indexOf(toolButton)].name());
|
||||
}
|
||||
}
|
||||
|
@ -173,9 +186,13 @@ public class WorldshaperScreen extends ZapperScreen {
|
|||
@Override
|
||||
protected void writeAdditionalOptions(CompoundNBT nbt) {
|
||||
super.writeAdditionalOptions(nbt);
|
||||
nbt.putString("Brush", NBTHelper.writeEnum(TerrainBrushes.values()[brushInput.getState()]));
|
||||
nbt.put("BrushParams", NBTUtil.writeBlockPos(new BlockPos(brushParams.get(0).getState(),
|
||||
brushParams.get(1).getState(), brushParams.get(2).getState())));
|
||||
NBTHelper.writeEnum(nbt, "Brush", TerrainBrushes.values()[brushInput.getState()]);
|
||||
nbt.put("BrushParams", NBTUtil.writeBlockPos(new BlockPos(brushParams.get(0)
|
||||
.getState(),
|
||||
brushParams.get(1)
|
||||
.getState(),
|
||||
brushParams.get(2)
|
||||
.getState())));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,12 +39,12 @@ public class DepotRenderer extends SafeTileEntityRenderer<DepotTileEntity> {
|
|||
msr.nudge(0);
|
||||
float offset = MathHelper.lerp(partialTicks, transported.prevBeltPosition, transported.beltPosition);
|
||||
float sideOffset = MathHelper.lerp(partialTicks, transported.prevSideOffset, transported.sideOffset);
|
||||
Vec3d offsetVec = new Vec3d(transported.insertedFrom.getOpposite()
|
||||
.getDirectionVec()).scale(.5f - offset);
|
||||
ms.translate(offsetVec.x, offsetVec.y, offsetVec.z);
|
||||
|
||||
if (transported.insertedFrom.getAxis()
|
||||
.isHorizontal()) {
|
||||
Vec3d offsetVec = new Vec3d(transported.insertedFrom.getOpposite()
|
||||
.getDirectionVec()).scale(.5f - offset);
|
||||
ms.translate(offsetVec.x, offsetVec.y, offsetVec.z);
|
||||
boolean alongX = transported.insertedFrom.rotateY()
|
||||
.getAxis() == Axis.X;
|
||||
if (!alongX)
|
||||
|
|
|
@ -84,6 +84,13 @@ public class DepotTileEntity extends SmartTileEntity {
|
|||
if (heldItem.locked != wasLocked || !previousItem.equals(heldItem.stack, false))
|
||||
sendData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
if (lazyItemHandler != null)
|
||||
lazyItemHandler.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT compound) {
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package com.simibubi.create.content.logistics.block.mechanicalArm;
|
||||
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class ArmAngleTarget {
|
||||
|
||||
static ArmAngleTarget NO_TARGET = new ArmAngleTarget();
|
||||
|
||||
float baseAngle;
|
||||
float lowerArmAngle;
|
||||
float upperArmAngle;
|
||||
float headAngle;
|
||||
|
||||
private ArmAngleTarget() {
|
||||
lowerArmAngle = 155;
|
||||
upperArmAngle = 60;
|
||||
headAngle = -15;
|
||||
}
|
||||
|
||||
public ArmAngleTarget(BlockPos armPos, Vec3d pointTarget, Direction clawFacing) {
|
||||
Vec3d target = pointTarget;
|
||||
Vec3d origin = VecHelper.getCenterOf(armPos)
|
||||
.add(0, 4 / 16f, 0);
|
||||
Vec3d clawTarget = target;
|
||||
target = target.add(new Vec3d(clawFacing.getOpposite()
|
||||
.getDirectionVec()).scale(.5f));
|
||||
|
||||
Vec3d diff = target.subtract(origin);
|
||||
float horizontalDistance = (float) diff.mul(1, 0, 1)
|
||||
.length();
|
||||
|
||||
float baseAngle = AngleHelper.deg(MathHelper.atan2(diff.x, diff.z)) + 180;
|
||||
float alphaOffset = AngleHelper.deg(MathHelper.atan2(diff.y, horizontalDistance));
|
||||
|
||||
float a = 18 / 16f; // lower arm length
|
||||
float a2 = a * a;
|
||||
float b = 17 / 16f; // upper arm length
|
||||
float b2 = b * b;
|
||||
float diffLength =
|
||||
MathHelper.clamp(MathHelper.sqrt(diff.y * diff.y + horizontalDistance * horizontalDistance), 1 / 8f, a + b);
|
||||
float diffLength2 = diffLength * diffLength;
|
||||
|
||||
float alphaRatio = (-b2 + a2 + diffLength2) / (2 * a * diffLength);
|
||||
float alpha = AngleHelper.deg(Math.acos(alphaRatio)) + alphaOffset;
|
||||
float betaRatio = (-diffLength2 + a2 + b2) / (2 * b * a);
|
||||
float beta = AngleHelper.deg(Math.acos(betaRatio));
|
||||
|
||||
if (Float.isNaN(alpha))
|
||||
alpha = 0;
|
||||
if (Float.isNaN(beta))
|
||||
beta = 0;
|
||||
|
||||
Vec3d headPos = new Vec3d(0, 0, 0);
|
||||
headPos = VecHelper.rotate(headPos.add(0, b, 0), beta + 180, Axis.X);
|
||||
headPos = VecHelper.rotate(headPos.add(0, a, 0), alpha - 90, Axis.X);
|
||||
headPos = VecHelper.rotate(headPos, baseAngle, Axis.Y);
|
||||
headPos = headPos.add(origin);
|
||||
Vec3d headDiff = clawTarget.subtract(headPos);
|
||||
float horizontalHeadDistance = (float) headDiff.mul(1, 0, 1)
|
||||
.length();
|
||||
float headAngle =
|
||||
(float) (alpha + beta + 135 - AngleHelper.deg(MathHelper.atan2(headDiff.y, horizontalHeadDistance)));
|
||||
|
||||
this.lowerArmAngle = alpha;
|
||||
this.upperArmAngle = beta;
|
||||
this.headAngle = -headAngle;
|
||||
this.baseAngle = baseAngle;
|
||||
}
|
||||
|
||||
}
|
|
@ -6,18 +6,13 @@ import com.simibubi.create.content.contraptions.base.KineticBlock;
|
|||
import com.simibubi.create.foundation.block.ITE;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.shapes.ISelectionContext;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.IWorldReader;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
|
||||
|
||||
|
@ -30,14 +25,6 @@ public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResultType onUse(BlockState p_225533_1_, World p_225533_2_, BlockPos p_225533_3_,
|
||||
PlayerEntity p_225533_4_, Hand p_225533_5_, BlockRayTraceResult p_225533_6_) {
|
||||
withTileEntityDo(p_225533_2_, p_225533_3_, ArmTileEntity::toggleRave);
|
||||
return ActionResultType.SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState p_220053_1_, IBlockReader p_220053_2_, BlockPos p_220053_3_,
|
||||
ISelectionContext p_220053_4_) {
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
package com.simibubi.create.content.logistics.block.mechanicalArm;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.simibubi.create.AllBlockPartials;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.logistics.block.realityFunnel.RealityFunnelBlock;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InsertingBehaviour;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
public abstract class ArmInteractionPoint {
|
||||
|
||||
static enum Mode {
|
||||
DEPOSIT, TAKE
|
||||
}
|
||||
|
||||
BlockPos pos;
|
||||
BlockState state;
|
||||
Mode mode;
|
||||
|
||||
private LazyOptional<IItemHandler> cachedHandler;
|
||||
private ArmAngleTarget cachedAngles;
|
||||
|
||||
public ArmInteractionPoint() {
|
||||
cachedHandler = LazyOptional.empty();
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
void transformFlag(MatrixStack stack) {}
|
||||
|
||||
AllBlockPartials getFlagType() {
|
||||
return mode == Mode.TAKE ? AllBlockPartials.FLAG_LONG_OUT : AllBlockPartials.FLAG_LONG_IN;
|
||||
}
|
||||
|
||||
void cycleMode() {
|
||||
mode = mode == Mode.DEPOSIT ? Mode.TAKE : Mode.DEPOSIT;
|
||||
}
|
||||
|
||||
Vec3d getInteractionPositionVector() {
|
||||
return VecHelper.getCenterOf(pos);
|
||||
}
|
||||
|
||||
Direction getInteractionDirection() {
|
||||
return Direction.DOWN;
|
||||
}
|
||||
|
||||
abstract boolean isValid(BlockState state);
|
||||
|
||||
static boolean isInteractable(BlockState state) {
|
||||
return AllBlocks.DEPOT.has(state) || AllBlocks.BELT.has(state) || AllBlocks.CHUTE.has(state)
|
||||
|| AllBlocks.REALITY_FUNNEL.has(state);
|
||||
}
|
||||
|
||||
ArmAngleTarget getTargetAngles(BlockPos armPos) {
|
||||
if (cachedAngles == null)
|
||||
cachedAngles = new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection());
|
||||
return cachedAngles;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
IItemHandler getHandler(World world) {
|
||||
if (!cachedHandler.isPresent()) {
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
if (te == null)
|
||||
return null;
|
||||
cachedHandler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP);
|
||||
}
|
||||
return cachedHandler.orElse(null);
|
||||
}
|
||||
|
||||
ItemStack insert(World world, ItemStack stack, boolean simulate) {
|
||||
IItemHandler handler = getHandler(world);
|
||||
if (handler == null)
|
||||
return stack;
|
||||
return ItemHandlerHelper.insertItem(handler, stack, simulate);
|
||||
}
|
||||
|
||||
ItemStack extract(World world, int slot, int amount, boolean simulate) {
|
||||
IItemHandler handler = getHandler(world);
|
||||
if (handler == null)
|
||||
return ItemStack.EMPTY;
|
||||
return handler.extractItem(slot, amount, simulate);
|
||||
}
|
||||
|
||||
ItemStack extract(World world, int slot, boolean simulate) {
|
||||
return extract(world, slot, 64, simulate);
|
||||
}
|
||||
|
||||
int getSlotCount(World world) {
|
||||
IItemHandler handler = getHandler(world);
|
||||
if (handler == null)
|
||||
return 0;
|
||||
return handler.getSlots();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ArmInteractionPoint createAt(IBlockReader world, BlockPos pos) {
|
||||
BlockState state = world.getBlockState(pos);
|
||||
ArmInteractionPoint point = null;
|
||||
|
||||
if (AllBlocks.DEPOT.has(state))
|
||||
point = new Depot();
|
||||
if (AllBlocks.BELT.has(state))
|
||||
point = new Belt();
|
||||
if (AllBlocks.CHUTE.has(state))
|
||||
point = new Chute();
|
||||
if (AllBlocks.REALITY_FUNNEL.has(state))
|
||||
point = new Funnel();
|
||||
|
||||
if (point != null) {
|
||||
point.state = state;
|
||||
point.pos = pos;
|
||||
point.mode = Mode.DEPOSIT;
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
CompoundNBT serialize() {
|
||||
CompoundNBT nbt = new CompoundNBT();
|
||||
nbt.put("Pos", NBTUtil.writeBlockPos(pos));
|
||||
NBTHelper.writeEnum(nbt, "Mode", mode);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
static ArmInteractionPoint deserialize(IBlockReader world, CompoundNBT nbt) {
|
||||
BlockPos pos = NBTUtil.readBlockPos(nbt.getCompound("Pos"));
|
||||
ArmInteractionPoint interactionPoint = createAt(world, pos);
|
||||
interactionPoint.mode = NBTHelper.readEnum(nbt, "Mode", Mode.class);
|
||||
return interactionPoint;
|
||||
}
|
||||
|
||||
static class Depot extends ArmInteractionPoint {
|
||||
|
||||
@Override
|
||||
Vec3d getInteractionPositionVector() {
|
||||
return new Vec3d(pos).add(.5f, 14 / 16f, .5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isValid(BlockState state) {
|
||||
return AllBlocks.DEPOT.has(state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Belt extends Depot {
|
||||
|
||||
@Override
|
||||
boolean isValid(BlockState state) {
|
||||
return AllBlocks.BELT.has(state);
|
||||
}
|
||||
}
|
||||
|
||||
static class Chute extends ArmInteractionPoint {
|
||||
|
||||
@Override
|
||||
Vec3d getInteractionPositionVector() {
|
||||
return new Vec3d(pos).add(.5f, 1, .5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isValid(BlockState state) {
|
||||
return AllBlocks.CHUTE.has(state);
|
||||
}
|
||||
}
|
||||
|
||||
static class Funnel extends ArmInteractionPoint {
|
||||
|
||||
@Override
|
||||
Vec3d getInteractionPositionVector() {
|
||||
return VecHelper.getCenterOf(pos)
|
||||
.add(new Vec3d(RealityFunnelBlock.getFunnelFacing(state)
|
||||
.getDirectionVec()).scale(.5f));
|
||||
}
|
||||
|
||||
@Override
|
||||
int getSlotCount(World world) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
ItemStack extract(World world, int slot, int amount, boolean simulate) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
Direction getInteractionDirection() {
|
||||
return RealityFunnelBlock.getFunnelFacing(state).getOpposite();
|
||||
}
|
||||
|
||||
@Override
|
||||
ItemStack insert(World world, ItemStack stack, boolean simulate) {
|
||||
FilteringBehaviour filtering = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE);
|
||||
InsertingBehaviour inserter = TileEntityBehaviour.get(world, pos, InsertingBehaviour.TYPE);
|
||||
if (inserter == null)
|
||||
return stack;
|
||||
if (filtering != null && !filtering.test(stack))
|
||||
return stack;
|
||||
return inserter.insert(stack, simulate);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isValid(BlockState state) {
|
||||
return AllBlocks.REALITY_FUNNEL.has(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
void cycleMode() {}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package com.simibubi.create.content.logistics.block.mechanicalArm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber(value = Dist.CLIENT)
|
||||
public class ArmInteractionPointHandler {
|
||||
|
||||
static Map<BlockPos, ArmInteractionPoint> currentSelection = new HashMap<>();
|
||||
static ItemStack currentItem;
|
||||
|
||||
@SubscribeEvent
|
||||
public static void rightClickingBlocksSelectsThem(PlayerInteractEvent.RightClickBlock event) {
|
||||
if (currentItem == null)
|
||||
return;
|
||||
BlockPos pos = event.getPos();
|
||||
World world = event.getWorld();
|
||||
if (!world.isRemote)
|
||||
return;
|
||||
|
||||
if (!currentSelection.containsKey(pos)) {
|
||||
ArmInteractionPoint point = ArmInteractionPoint.createAt(world, pos);
|
||||
if (point == null)
|
||||
return;
|
||||
currentSelection.put(pos, point);
|
||||
}
|
||||
|
||||
currentSelection.get(pos)
|
||||
.cycleMode();
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(ActionResultType.SUCCESS);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void leftClickingBlocksDeselectsThem(PlayerInteractEvent.LeftClickBlock event) {
|
||||
if (currentItem == null)
|
||||
return;
|
||||
if (!event.getWorld().isRemote)
|
||||
return;
|
||||
BlockPos pos = event.getPos();
|
||||
if (currentSelection.remove(pos) != null) {
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(ActionResultType.SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
public static void flushSettings(BlockPos pos) {
|
||||
if (currentItem == null)
|
||||
return;
|
||||
AllPackets.channel.sendToServer(new ArmPlacementPacket(currentSelection.values(), pos));
|
||||
currentSelection.clear();
|
||||
currentItem = null;
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
PlayerEntity player = Minecraft.getInstance().player;
|
||||
World world = Minecraft.getInstance().world;
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
ItemStack heldItemMainhand = player.getHeldItemMainhand();
|
||||
if (!AllBlocks.MECHANICAL_ARM.isIn(heldItemMainhand)) {
|
||||
currentItem = null;
|
||||
return;
|
||||
}
|
||||
if (heldItemMainhand != currentItem) {
|
||||
currentSelection.clear();
|
||||
currentItem = heldItemMainhand;
|
||||
}
|
||||
|
||||
for (Iterator<Entry<BlockPos, ArmInteractionPoint>> iterator = currentSelection.entrySet()
|
||||
.iterator(); iterator.hasNext();) {
|
||||
Entry<BlockPos, ArmInteractionPoint> entry = iterator.next();
|
||||
BlockPos pos = entry.getKey();
|
||||
BlockState state = world.getBlockState(pos);
|
||||
ArmInteractionPoint point = entry.getValue();
|
||||
|
||||
if (!point.isValid(state)) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
VoxelShape shape = state.getShape(world, pos);
|
||||
if (shape.isEmpty())
|
||||
continue;
|
||||
|
||||
int color = point.mode == Mode.DEPOSIT ? 0xffcb74 : 0x4f8a8b;
|
||||
CreateClient.outliner.showAABB(point, shape.getBoundingBox()
|
||||
.offset(pos))
|
||||
.colored(color)
|
||||
.lineWidth(1 / 16f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.simibubi.create.content.logistics.block.mechanicalArm;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUseContext;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber
|
||||
public class ArmItem extends BlockItem {
|
||||
|
||||
public ArmItem(Block p_i48527_1_, Properties p_i48527_2_) {
|
||||
super(p_i48527_1_, p_i48527_2_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResultType onItemUse(ItemUseContext ctx) {
|
||||
if (ArmInteractionPoint.isInteractable(ctx.getWorld()
|
||||
.getBlockState(ctx.getPos())))
|
||||
return ActionResultType.SUCCESS;
|
||||
return super.onItemUse(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onBlockPlaced(BlockPos pos, World world, PlayerEntity p_195943_3_, ItemStack p_195943_4_,
|
||||
BlockState p_195943_5_) {
|
||||
if (world.isRemote)
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> ArmInteractionPointHandler.flushSettings(pos));
|
||||
return super.onBlockPlaced(pos, world, p_195943_3_, p_195943_4_, p_195943_5_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayerBreakBlockWhileHolding(BlockState state, World p_195938_2_, BlockPos p_195938_3_,
|
||||
PlayerEntity p_195938_4_) {
|
||||
return !ArmInteractionPoint.isInteractable(state);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.simibubi.create.content.logistics.block.mechanicalArm;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||
|
||||
public class ArmPlacementPacket extends SimplePacketBase {
|
||||
|
||||
private Collection<ArmInteractionPoint> points;
|
||||
private ListNBT receivedTag;
|
||||
private BlockPos pos;
|
||||
|
||||
public ArmPlacementPacket(Collection<ArmInteractionPoint> points, BlockPos pos) {
|
||||
this.points = points;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public ArmPlacementPacket(PacketBuffer buffer) {
|
||||
CompoundNBT nbt = buffer.readCompoundTag();
|
||||
receivedTag = nbt.getList("Points", NBT.TAG_COMPOUND);
|
||||
pos = buffer.readBlockPos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketBuffer buffer) {
|
||||
CompoundNBT nbt = new CompoundNBT();
|
||||
ListNBT pointsNBT = new ListNBT();
|
||||
points.stream()
|
||||
.map(ArmInteractionPoint::serialize)
|
||||
.forEach(pointsNBT::add);
|
||||
nbt.put("Points", pointsNBT);
|
||||
buffer.writeCompoundTag(nbt);
|
||||
buffer.writeBlockPos(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Supplier<Context> context) {
|
||||
context.get()
|
||||
.enqueueWork(() -> {
|
||||
ServerPlayerEntity player = context.get()
|
||||
.getSender();
|
||||
if (player == null)
|
||||
return;
|
||||
World world = player.world;
|
||||
if (world == null)
|
||||
return;
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
if (tileEntity == null || !(tileEntity instanceof ArmTileEntity))
|
||||
return;
|
||||
|
||||
ArmTileEntity arm = (ArmTileEntity) tileEntity;
|
||||
arm.interactionPointTag = receivedTag;
|
||||
});
|
||||
context.get()
|
||||
.setPacketHandled(true);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -5,17 +5,19 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
|
|||
import com.simibubi.create.AllBlockPartials;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.ColorHelper;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.MatrixStacker;
|
||||
import com.simibubi.create.foundation.utility.SuperByteBuffer;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class ArmRenderer extends KineticTileEntityRenderer {
|
||||
|
||||
|
@ -24,25 +26,15 @@ public class ArmRenderer extends KineticTileEntityRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
|
||||
int light, int overlay) {
|
||||
super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
|
||||
protected void renderSafe(KineticTileEntity te, float pt, MatrixStack ms, IRenderTypeBuffer buffer, int light,
|
||||
int overlay) {
|
||||
super.renderSafe(te, pt, ms, buffer, light, overlay);
|
||||
ArmTileEntity arm = (ArmTileEntity) te;
|
||||
IVertexBuilder builder = buffer.getBuffer(RenderType.getSolid());
|
||||
BlockState blockState = te.getBlockState();
|
||||
MatrixStacker msr = MatrixStacker.of(ms);
|
||||
|
||||
float angle = 0;
|
||||
float clawAngle = -25;
|
||||
float otherAngle = 0;
|
||||
int color = 0xFFFFFF;
|
||||
|
||||
boolean rave = te instanceof ArmTileEntity && ((ArmTileEntity) te).debugRave;
|
||||
if (rave) {
|
||||
clawAngle = angle = MathHelper.lerp((MathHelper.sin(AnimationTickHolder.getRenderTick() / 2) + 1) / 2, -45, 15);
|
||||
otherAngle = MathHelper.lerp((MathHelper.sin(AnimationTickHolder.getRenderTick() / 4) + 1) / 2, -95, 95);
|
||||
color = ColorHelper.rainbowColor(AnimationTickHolder.ticks * 100);
|
||||
}
|
||||
|
||||
|
||||
ms.push();
|
||||
|
||||
SuperByteBuffer base = AllBlockPartials.ARM_BASE.renderOn(blockState);
|
||||
|
@ -55,33 +47,51 @@ public class ArmRenderer extends KineticTileEntityRenderer {
|
|||
msr.centre();
|
||||
|
||||
ms.translate(0, 4 / 16d, 0);
|
||||
msr.rotateY(rave ? AnimationTickHolder.getRenderTick() * 10 : 0);
|
||||
msr.rotateY(arm.baseAngle.get(pt));
|
||||
base.renderInto(ms, builder);
|
||||
|
||||
ms.translate(0, 1 / 16d, -2 / 16d);
|
||||
msr.rotateX(angle);
|
||||
msr.rotateX(arm.lowerArmAngle.get(pt) - 135);
|
||||
ms.translate(0, -1 / 16d, 0);
|
||||
lowerBody.color(color).renderInto(ms, builder);
|
||||
|
||||
lowerBody.color(color)
|
||||
.renderInto(ms, builder);
|
||||
|
||||
ms.translate(0, 12 / 16d, 12 / 16d);
|
||||
msr.rotateX(-otherAngle / 2f);
|
||||
upperBody.color(color).renderInto(ms, builder);
|
||||
|
||||
msr.rotateX(arm.upperArmAngle.get(pt) - 90);
|
||||
upperBody.color(color)
|
||||
.renderInto(ms, builder);
|
||||
|
||||
ms.translate(0, 11 / 16d, -11 / 16d);
|
||||
msr.rotateX(-angle);
|
||||
msr.rotateX(arm.headAngle.get(pt));
|
||||
head.renderInto(ms, builder);
|
||||
|
||||
|
||||
ms.translate(0, 0, -4 / 16d);
|
||||
claw.renderInto(ms, builder);
|
||||
ItemStack item = arm.heldItem;
|
||||
ItemRenderer itemRenderer = Minecraft.getInstance()
|
||||
.getItemRenderer();
|
||||
boolean hasItem = !item.isEmpty();
|
||||
boolean isBlockItem = hasItem && (item.getItem() instanceof BlockItem)
|
||||
&& itemRenderer.getItemModelWithOverrides(item, Minecraft.getInstance().world, null)
|
||||
.isGui3d();
|
||||
|
||||
for (int flip : Iterate.positiveAndNegative) {
|
||||
ms.push();
|
||||
ms.translate(0, flip * 3 / 16d, -1 / 16d);
|
||||
msr.rotateX(flip * clawAngle);
|
||||
msr.rotateX(flip * (hasItem ? isBlockItem ? 0 : -35 : 0));
|
||||
clawGrip.renderInto(ms, builder);
|
||||
ms.pop();
|
||||
}
|
||||
|
||||
if (hasItem) {
|
||||
float itemScale = isBlockItem ? .5f : .625f;
|
||||
msr.rotateX(90);
|
||||
ms.translate(0, -4 / 16f, 0);
|
||||
ms.scale(itemScale, itemScale, itemScale);
|
||||
itemRenderer
|
||||
.renderItem(item, TransformType.FIXED, light, overlay, ms, buffer);
|
||||
}
|
||||
|
||||
ms.pop();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,45 +1,297 @@
|
|||
package com.simibubi.create.content.logistics.block.mechanicalArm;
|
||||
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode;
|
||||
import com.simibubi.create.foundation.gui.widgets.InterpolatedAngle;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.INBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
|
||||
public class ArmTileEntity extends KineticTileEntity {
|
||||
|
||||
boolean debugRave;
|
||||
|
||||
public ArmTileEntity(TileEntityType<?> typeIn) {
|
||||
super(typeIn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lazyTick() {
|
||||
if (hasWorld())
|
||||
if (world.rand.nextInt(100) == 0)
|
||||
toggleRave();
|
||||
super.lazyTick();
|
||||
// Server
|
||||
List<ArmInteractionPoint> inputs;
|
||||
List<ArmInteractionPoint> outputs;
|
||||
ListNBT interactionPointTag;
|
||||
|
||||
// Both
|
||||
float chasedPointProgress;
|
||||
int chasedPointIndex;
|
||||
ItemStack heldItem;
|
||||
Phase phase;
|
||||
|
||||
// Client
|
||||
ArmAngleTarget previousTarget;
|
||||
InterpolatedAngle lowerArmAngle;
|
||||
InterpolatedAngle upperArmAngle;
|
||||
InterpolatedAngle baseAngle;
|
||||
InterpolatedAngle headAngle;
|
||||
InterpolatedAngle clawAngle;
|
||||
float previousBaseAngle;
|
||||
boolean updateInteractionPoints;
|
||||
|
||||
enum Phase {
|
||||
SEARCH_INPUTS, MOVE_TO_INPUT, SEARCH_OUTPUTS, MOVE_TO_OUTPUT, IDLE
|
||||
}
|
||||
|
||||
public void toggleRave() {
|
||||
public ArmTileEntity(TileEntityType<?> typeIn) {
|
||||
super(typeIn);
|
||||
inputs = new ArrayList<>();
|
||||
outputs = new ArrayList<>();
|
||||
heldItem = ItemStack.EMPTY;
|
||||
phase = Phase.SEARCH_INPUTS;
|
||||
baseAngle = new InterpolatedAngle();
|
||||
lowerArmAngle = new InterpolatedAngle();
|
||||
upperArmAngle = new InterpolatedAngle();
|
||||
headAngle = new InterpolatedAngle();
|
||||
clawAngle = new InterpolatedAngle();
|
||||
previousTarget = ArmAngleTarget.NO_TARGET;
|
||||
previousBaseAngle = previousTarget.baseAngle;
|
||||
updateInteractionPoints = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
initInteractionPoints();
|
||||
tickMovementProgress();
|
||||
|
||||
if (world.isRemote)
|
||||
return;
|
||||
debugRave = !debugRave;
|
||||
if (chasedPointProgress < 1)
|
||||
return;
|
||||
if (phase == Phase.MOVE_TO_INPUT)
|
||||
collectItem();
|
||||
if (phase == Phase.MOVE_TO_OUTPUT)
|
||||
depositItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lazyTick() {
|
||||
super.lazyTick();
|
||||
|
||||
if (world.isRemote)
|
||||
return;
|
||||
if (chasedPointProgress < .5f)
|
||||
return;
|
||||
if (phase == Phase.SEARCH_INPUTS)
|
||||
searchForItem();
|
||||
if (phase == Phase.SEARCH_OUTPUTS)
|
||||
searchForDestination();
|
||||
}
|
||||
|
||||
private void tickMovementProgress() {
|
||||
chasedPointProgress += Math.min(256, Math.abs(getSpeed())) / 1024f;
|
||||
if (chasedPointProgress > 1)
|
||||
chasedPointProgress = 1;
|
||||
if (!world.isRemote)
|
||||
return;
|
||||
|
||||
ArmInteractionPoint targetedInteractionPoint = getTargetedInteractionPoint();
|
||||
ArmAngleTarget previousTarget = this.previousTarget;
|
||||
ArmAngleTarget target =
|
||||
targetedInteractionPoint == null ? ArmAngleTarget.NO_TARGET : targetedInteractionPoint.getTargetAngles(pos);
|
||||
|
||||
baseAngle.set(AngleHelper.angleLerp(chasedPointProgress, previousBaseAngle,
|
||||
target == ArmAngleTarget.NO_TARGET ? previousBaseAngle : target.baseAngle));
|
||||
|
||||
// Arm's angles first backup to resting position and then continue
|
||||
if (chasedPointProgress < .5f)
|
||||
target = ArmAngleTarget.NO_TARGET;
|
||||
else
|
||||
previousTarget = ArmAngleTarget.NO_TARGET;
|
||||
float progress = chasedPointProgress == 1 ? 1 : (chasedPointProgress % .5f) * 2;
|
||||
|
||||
lowerArmAngle.set(MathHelper.lerp(progress, previousTarget.lowerArmAngle, target.lowerArmAngle));
|
||||
upperArmAngle.set(MathHelper.lerp(progress, previousTarget.upperArmAngle, target.upperArmAngle));
|
||||
headAngle.set(AngleHelper.angleLerp(progress, previousTarget.headAngle, target.headAngle));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ArmInteractionPoint getTargetedInteractionPoint() {
|
||||
if (chasedPointIndex == -1)
|
||||
return null;
|
||||
if (phase == Phase.MOVE_TO_INPUT && chasedPointIndex < inputs.size())
|
||||
return inputs.get(chasedPointIndex);
|
||||
if (phase == Phase.MOVE_TO_OUTPUT && chasedPointIndex < outputs.size())
|
||||
return outputs.get(chasedPointIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void searchForItem() {
|
||||
for (int index = 0; index < inputs.size(); index++) {
|
||||
ArmInteractionPoint armInteractionPoint = inputs.get(index);
|
||||
for (int i = 0; i < armInteractionPoint.getSlotCount(world); i++) {
|
||||
if (getDistributableAmount(armInteractionPoint, i) == 0)
|
||||
continue;
|
||||
|
||||
phase = Phase.MOVE_TO_INPUT;
|
||||
chasedPointIndex = index;
|
||||
chasedPointProgress = 0;
|
||||
sendData();
|
||||
markDirty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void searchForDestination() {
|
||||
ItemStack held = heldItem.copy();
|
||||
for (int index = 0; index < outputs.size(); index++) {
|
||||
ArmInteractionPoint armInteractionPoint = outputs.get(index);
|
||||
ItemStack remainder = armInteractionPoint.insert(world, held, true);
|
||||
if (remainder.equals(heldItem, false))
|
||||
continue;
|
||||
|
||||
phase = Phase.MOVE_TO_OUTPUT;
|
||||
chasedPointIndex = index;
|
||||
chasedPointProgress = 0;
|
||||
sendData();
|
||||
markDirty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected int getDistributableAmount(ArmInteractionPoint armInteractionPoint, int i) {
|
||||
ItemStack stack = armInteractionPoint.extract(world, i, true);
|
||||
ItemStack remainder = simulateInsertion(stack);
|
||||
return stack.getCount() - remainder.getCount();
|
||||
}
|
||||
|
||||
protected void depositItem() {
|
||||
ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint();
|
||||
ItemStack toInsert = heldItem.copy();
|
||||
ItemStack remainder = armInteractionPoint.insert(world, toInsert, false);
|
||||
heldItem = remainder;
|
||||
phase = heldItem.isEmpty() ? Phase.SEARCH_INPUTS : Phase.SEARCH_OUTPUTS;
|
||||
chasedPointProgress = 0;
|
||||
chasedPointIndex = -1;
|
||||
sendData();
|
||||
markDirty();
|
||||
}
|
||||
|
||||
protected void collectItem() {
|
||||
ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint();
|
||||
for (int i = 0; i < armInteractionPoint.getSlotCount(world); i++) {
|
||||
int amountExtracted = getDistributableAmount(armInteractionPoint, i);
|
||||
if (amountExtracted == 0)
|
||||
continue;
|
||||
|
||||
heldItem = armInteractionPoint.extract(world, i, amountExtracted, false);
|
||||
phase = Phase.SEARCH_OUTPUTS;
|
||||
chasedPointProgress = 0;
|
||||
chasedPointIndex = -1;
|
||||
sendData();
|
||||
markDirty();
|
||||
return;
|
||||
}
|
||||
|
||||
phase = Phase.SEARCH_INPUTS;
|
||||
chasedPointProgress = 0;
|
||||
chasedPointIndex = -1;
|
||||
sendData();
|
||||
markDirty();
|
||||
}
|
||||
|
||||
private ItemStack simulateInsertion(ItemStack stack) {
|
||||
for (ArmInteractionPoint armInteractionPoint : outputs) {
|
||||
stack = armInteractionPoint.insert(world, stack, true);
|
||||
if (stack.isEmpty())
|
||||
break;
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
protected void initInteractionPoints() {
|
||||
if (interactionPointTag == null)
|
||||
return;
|
||||
inputs.clear();
|
||||
outputs.clear();
|
||||
for (INBT inbt : interactionPointTag) {
|
||||
ArmInteractionPoint point = ArmInteractionPoint.deserialize(world, (CompoundNBT) inbt);
|
||||
if (point.mode == Mode.DEPOSIT)
|
||||
outputs.add(point);
|
||||
if (point.mode == Mode.TAKE)
|
||||
inputs.add(point);
|
||||
}
|
||||
interactionPointTag = null;
|
||||
markDirty();
|
||||
sendData();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT compound) {
|
||||
super.write(compound);
|
||||
compound.putBoolean("DebugRave", debugRave);
|
||||
|
||||
ListNBT pointsNBT = new ListNBT();
|
||||
inputs.stream()
|
||||
.map(ArmInteractionPoint::serialize)
|
||||
.forEach(pointsNBT::add);
|
||||
outputs.stream()
|
||||
.map(ArmInteractionPoint::serialize)
|
||||
.forEach(pointsNBT::add);
|
||||
|
||||
NBTHelper.writeEnum(compound, "Phase", phase);
|
||||
compound.put("InterationPoints", pointsNBT);
|
||||
compound.put("HeldItem", heldItem.serializeNBT());
|
||||
compound.putInt("TargetPointIndex", chasedPointIndex);
|
||||
compound.putFloat("MovementProgress", chasedPointProgress);
|
||||
return compound;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
||||
super.writeToClient(compound);
|
||||
if (interactionPointTag != null)
|
||||
compound.put("InitialInterationPoints", interactionPointTag);
|
||||
return compound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundNBT compound) {
|
||||
super.read(compound);
|
||||
debugRave = compound.getBoolean("DebugRave");
|
||||
heldItem = ItemStack.read(compound.getCompound("HeldItem"));
|
||||
phase = NBTHelper.readEnum(compound, "Phase", Phase.class);
|
||||
chasedPointIndex = compound.getInt("TargetPointIndex");
|
||||
chasedPointProgress = compound.getFloat("MovementProgress");
|
||||
|
||||
if (!hasWorld() || !world.isRemote || updateInteractionPoints)
|
||||
interactionPointTag = compound.getList("InterationPoints", NBT.TAG_COMPOUND);
|
||||
updateInteractionPoints = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readClientUpdate(CompoundNBT tag) {
|
||||
int previousIndex = chasedPointIndex;
|
||||
Phase previousPhase = phase;
|
||||
|
||||
super.readClientUpdate(tag);
|
||||
|
||||
if (previousIndex != chasedPointIndex || (previousPhase != phase)) {
|
||||
ArmInteractionPoint previousPoint = null;
|
||||
if (previousPhase == Phase.MOVE_TO_INPUT && previousIndex < inputs.size())
|
||||
previousPoint = inputs.get(previousIndex);
|
||||
if (previousPhase == Phase.MOVE_TO_OUTPUT && previousIndex < outputs.size())
|
||||
previousPoint = outputs.get(previousIndex);
|
||||
previousTarget = previousPoint == null ? ArmAngleTarget.NO_TARGET : previousPoint.getTargetAngles(pos);
|
||||
if (previousPoint != null)
|
||||
previousBaseAngle = previousPoint.getTargetAngles(pos).baseAngle;
|
||||
}
|
||||
|
||||
if (tag.contains("InitialInterationPoints"))
|
||||
interactionPointTag = tag.getList("InitialInterationPoints", NBT.TAG_COMPOUND);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,9 @@ public class FilterScreenPacket extends SimplePacketBase {
|
|||
public void handle(Supplier<Context> context) {
|
||||
context.get().enqueueWork(() -> {
|
||||
ServerPlayerEntity player = context.get().getSender();
|
||||
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
if (player.openContainer instanceof AbstractFilterContainer) {
|
||||
AbstractFilterContainer c = (AbstractFilterContainer) player.openContainer;
|
||||
if (option == Option.CLEAR) {
|
||||
|
|
|
@ -49,6 +49,8 @@ public class ConfigureSchematicannonPacket extends SimplePacketBase {
|
|||
public void handle(Supplier<Context> context) {
|
||||
context.get().enqueueWork(() -> {
|
||||
ServerPlayerEntity player = context.get().getSender();
|
||||
if (player == null)
|
||||
return;
|
||||
World world = player.world;
|
||||
if (world == null)
|
||||
return;
|
||||
|
|
|
@ -32,6 +32,8 @@ public class SchematicPlacePacket extends SimplePacketBase {
|
|||
public void handle(Supplier<Context> context) {
|
||||
context.get().enqueueWork(() -> {
|
||||
ServerPlayerEntity player = context.get().getSender();
|
||||
if (player == null)
|
||||
return;
|
||||
Template t = SchematicItem.loadSchematic(stack);
|
||||
PlacementSettings settings = SchematicItem.getSettings(stack);
|
||||
settings.setIgnoreEntities(false);
|
||||
|
|
|
@ -68,6 +68,8 @@ public class SchematicUploadPacket extends SimplePacketBase {
|
|||
.enqueueWork(() -> {
|
||||
ServerPlayerEntity player = context.get()
|
||||
.getSender();
|
||||
if (player == null)
|
||||
return;
|
||||
if (code == BEGIN) {
|
||||
BlockPos pos = ((SchematicTableContainer) player.openContainer).getTileEntity()
|
||||
.getPos();
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package com.simibubi.create.foundation.gui.widgets;
|
||||
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
|
||||
public class InterpolatedAngle extends InterpolatedValue {
|
||||
|
||||
public float get(float partialTicks) {
|
||||
return AngleHelper.angleLerp(partialTicks, lastValue, value);
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,10 @@ import com.simibubi.create.foundation.utility.AngleHelper;
|
|||
|
||||
public class InterpolatedChasingAngle extends InterpolatedChasingValue {
|
||||
|
||||
public float get(float partialTicks) {
|
||||
return AngleHelper.angleLerp(partialTicks, lastValue, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getCurrentDiff() {
|
||||
return AngleHelper.getShortestAngleDiff(value, getTarget());
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.simibubi.create.content.contraptions.relays.advanced.sequencer.Config
|
|||
import com.simibubi.create.content.curiosities.symmetry.SymmetryEffectPacket;
|
||||
import com.simibubi.create.content.curiosities.tools.ExtendoGripInteractionPacket;
|
||||
import com.simibubi.create.content.curiosities.zapper.ZapperBeamPacket;
|
||||
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmPlacementPacket;
|
||||
import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket;
|
||||
import com.simibubi.create.content.logistics.packet.ConfigureFlexcratePacket;
|
||||
import com.simibubi.create.content.logistics.packet.ConfigureStockswitchPacket;
|
||||
|
@ -44,6 +45,7 @@ public enum AllPackets {
|
|||
CONFIGURE_SCROLLABLE(ScrollValueUpdatePacket.class, ScrollValueUpdatePacket::new),
|
||||
CANCEL_FALL(CancelPlayerFallPacket.class, CancelPlayerFallPacket::new),
|
||||
EXTENDO_INTERACT(ExtendoGripInteractionPacket.class, ExtendoGripInteractionPacket::new),
|
||||
PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new),
|
||||
|
||||
// Server to Client
|
||||
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new),
|
||||
|
|
|
@ -40,6 +40,8 @@ public class NbtPacket extends SimplePacketBase {
|
|||
public void handle(Supplier<Context> context) {
|
||||
context.get().enqueueWork(() -> {
|
||||
ServerPlayerEntity player = context.get().getSender();
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
if (slot == -1) {
|
||||
ItemStack heldItem = player.getHeldItem(hand);
|
||||
|
|
|
@ -35,6 +35,8 @@ public abstract class TileEntityConfigurationPacket<TE extends SyncedTileEntity>
|
|||
public void handle(Supplier<Context> context) {
|
||||
context.get().enqueueWork(() -> {
|
||||
ServerPlayerEntity player = context.get().getSender();
|
||||
if (player == null)
|
||||
return;
|
||||
World world = player.world;
|
||||
|
||||
if (world == null || world.getTileEntity(pos) == null)
|
||||
|
|
|
@ -12,8 +12,9 @@ import net.minecraft.util.math.AxisAlignedBB;
|
|||
|
||||
public class NBTHelper {
|
||||
|
||||
public static <T extends Enum<?>> T readEnum(String name, Class<T> enumClass) {
|
||||
public static <T extends Enum<?>> T readEnum(CompoundNBT nbt, String key, Class<T> enumClass) {
|
||||
T[] enumConstants = enumClass.getEnumConstants();
|
||||
String name = nbt.getString(key);
|
||||
if (enumConstants == null)
|
||||
throw new IllegalArgumentException("Non-Enum class passed to readEnum(): " + enumClass.getName());
|
||||
for (T t : enumConstants) {
|
||||
|
@ -22,11 +23,11 @@ public class NBTHelper {
|
|||
}
|
||||
return enumConstants[0];
|
||||
}
|
||||
|
||||
public static <T extends Enum<?>> String writeEnum(T enumConstant) {
|
||||
return enumConstant.name();
|
||||
|
||||
public static <T extends Enum<?>> void writeEnum(CompoundNBT nbt, String key, T enumConstant) {
|
||||
nbt.putString(key, enumConstant.name());
|
||||
}
|
||||
|
||||
|
||||
public static <T> ListNBT writeCompoundList(List<T> list, Function<T, CompoundNBT> serializer) {
|
||||
ListNBT listNBT = new ListNBT();
|
||||
list.forEach(t -> listNBT.add(serializer.apply(t)));
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"4": "create:block/marker_flag"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [1, 16, 1],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 0, 2, 16], "texture": "#4"},
|
||||
"east": {"uv": [0, 0, 1, 16], "texture": "#4"},
|
||||
"south": {"uv": [1, 0, 2, 16], "texture": "#4"},
|
||||
"west": {"uv": [0, 0, 1, 16], "texture": "#4"},
|
||||
"up": {"uv": [0, 0, 1, 1], "texture": "#4"},
|
||||
"down": {"uv": [0, 0, 1, 1], "texture": "#4"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0.4, 7.5, 1],
|
||||
"to": [0.4, 15.5, 9],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]},
|
||||
"faces": {
|
||||
"east": {"uv": [16, 0, 8, 8], "texture": "#4", "tintindex": 0},
|
||||
"west": {"uv": [8, 0, 16, 8], "texture": "#4", "tintindex": 0}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"4": "create:block/marker_flag"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [1, 16, 1],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 0, 2, 16], "texture": "#4"},
|
||||
"east": {"uv": [0, 0, 1, 16], "texture": "#4"},
|
||||
"south": {"uv": [1, 0, 2, 16], "texture": "#4"},
|
||||
"west": {"uv": [0, 0, 1, 16], "texture": "#4"},
|
||||
"up": {"uv": [0, 0, 1, 1], "texture": "#4"},
|
||||
"down": {"uv": [0, 0, 1, 1], "texture": "#4"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0.4, 7.5, 1],
|
||||
"to": [0.4, 15.5, 9],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]},
|
||||
"faces": {
|
||||
"east": {"uv": [16, 8, 8, 16], "texture": "#4", "tintindex": 0},
|
||||
"west": {"uv": [8, 8, 16, 16], "texture": "#4", "tintindex": 0}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"4": "create:block/marker_flag"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [1, 8, 1],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 8, 2, 16], "texture": "#4"},
|
||||
"east": {"uv": [0, 0, 1, 8], "texture": "#4"},
|
||||
"south": {"uv": [1, 0, 2, 8], "texture": "#4"},
|
||||
"west": {"uv": [0, 0, 1, 8], "texture": "#4"},
|
||||
"up": {"uv": [0, 0, 1, 1], "texture": "#4"},
|
||||
"down": {"uv": [0, 0, 1, 1], "texture": "#4"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0.4, -0.5, 1],
|
||||
"to": [0.4, 7.5, 9],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]},
|
||||
"faces": {
|
||||
"east": {"uv": [16, 0, 8, 8], "texture": "#4", "tintindex": 0},
|
||||
"west": {"uv": [8, 0, 16, 8], "texture": "#4", "tintindex": 0}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"4": "create:block/marker_flag"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [1, 8, 1],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 8, 2, 16], "texture": "#4"},
|
||||
"east": {"uv": [0, 0, 1, 8], "texture": "#4"},
|
||||
"south": {"uv": [1, 0, 2, 8], "texture": "#4"},
|
||||
"west": {"uv": [0, 0, 1, 8], "texture": "#4"},
|
||||
"up": {"uv": [0, 0, 1, 1], "texture": "#4"},
|
||||
"down": {"uv": [0, 0, 1, 1], "texture": "#4"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0.4, -0.5, 1],
|
||||
"to": [0.4, 7.5, 9],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]},
|
||||
"faces": {
|
||||
"east": {"uv": [16, 8, 8, 16], "texture": "#4", "tintindex": 0},
|
||||
"west": {"uv": [8, 8, 16, 16], "texture": "#4", "tintindex": 0}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
BIN
src/main/resources/assets/create/textures/block/marker_flag.png
Normal file
BIN
src/main/resources/assets/create/textures/block/marker_flag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 324 B |
Loading…
Reference in a new issue