Skip to content

Commit

Permalink
Reworked Part Placement & Part/Facade Placement Previews (#5853)
Browse files Browse the repository at this point in the history
Fixes #5842
Fixes #5831
  • Loading branch information
shartte committed Dec 23, 2021
1 parent a0af648 commit d96f836
Show file tree
Hide file tree
Showing 13 changed files with 402 additions and 422 deletions.
7 changes: 7 additions & 0 deletions src/main/java/appeng/api/parts/IFacadeContainer.java
Expand Up @@ -36,6 +36,13 @@
*/
public interface IFacadeContainer {

/**
* Checks if the {@link IFacadePart} can be added to the given side.
*
* @return true if the facade can be successfully added.
*/
boolean canAddFacade(IFacadePart a);

/**
* Attempts to add the {@link IFacadePart} to the given side.
*
Expand Down
74 changes: 52 additions & 22 deletions src/main/java/appeng/api/parts/PartHelper.java
Expand Up @@ -30,11 +30,9 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.DirectionalPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;

Expand All @@ -52,16 +50,11 @@ private PartHelper() {
* {@link net.minecraft.world.item.Item#useOn} of your parts item (if you're not using AE2s internal PartItem class)
* to implement part placement.
*
* @param is ItemStack of an item which implements {@link IPartItem}
* @param pos pos of part
* @param side side which the part should be on
* @param player player placing part
* @param level part in level
* @return true if placing was successful
* @return The result of placement suitable for returning from
* {@link net.minecraft.world.item.Item#useOn(UseOnContext)}.
*/
public static InteractionResult usePartItem(ItemStack is, BlockPos pos, Direction side,
Player player, InteractionHand hand, Level level) {
return PartPlacement.place(is, pos, side, player, hand, level, PartPlacement.PlaceType.PLACE_ITEM, 0);
public static InteractionResult usePartItem(UseOnContext context) {
return PartPlacement.place(context);
}

/**
Expand Down Expand Up @@ -109,7 +102,7 @@ public static <T extends IPart> T setPart(ServerLevel level, BlockPos pos, @Null
Objects.requireNonNull(level, "level");
Objects.requireNonNull(pos, "pos");

var host = getOrPlacePartHost(level, pos, true);
var host = getOrPlacePartHost(level, pos, true, null);
if (host == null) {
return null;
}
Expand All @@ -128,28 +121,65 @@ public static <T extends IPart> T setPart(ServerLevel level, BlockPos pos, @Null
* <p/>
* Use {@link IPartHost#isEmpty()} and {@link IPartHost#cleanup()}.
*
* @param force If true, an existing non-cable-bus block will be unconditionally replaced.
* @param force If true, an existing non-cable-bus block will be unconditionally replaced.
* @param player The player trying to place the cable bus. Will be used to check if the player can actually place it
* if force is not true.
*/
@Nullable
public static IPartHost getOrPlacePartHost(ServerLevel level, BlockPos pos, boolean force) {
public static IPartHost getOrPlacePartHost(Level level, BlockPos pos, boolean force, @Nullable Player player) {
// Get or place part host
var blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof IPartHost partHost) {
return partHost;
} else {
if (!force) {
var whatToPlace = AEBlocks.CABLE_BUS.stack();
var ctx = new DirectionalPlaceContext(level, pos, Direction.DOWN, whatToPlace, Direction.UP);
if (!level.getBlockState(pos).canBeReplaced(ctx)) {
return null;
}
if (!force && !canPlacePartHost(player, level, pos)) {
return null;
}

level.setBlockAndUpdate(pos, AEBlocks.CABLE_BUS.block().defaultBlockState());
var state = AEBlocks.CABLE_BUS.block().getStateForPlacement(level, pos);
level.setBlockAndUpdate(pos, state);
return level.getBlockEntity(pos, AEBlockEntities.CABLE_BUS).orElse(null);
}
}

/**
* Tries placing a new part host at the given location as a player.
*
* @return null if placing a new bus fails (even if a bus already is at that location)
*/
@Nullable
public static IPartHost placePartHost(@Nullable Player player, Level level, BlockPos pos) {
// Get or place part host
if (!canPlacePartHost(player, level, pos)) {
return null;
}

var state = AEBlocks.CABLE_BUS.block().getStateForPlacement(level, pos);
level.setBlockAndUpdate(pos, state);
return level.getBlockEntity(pos, AEBlockEntities.CABLE_BUS).orElse(null);
}

public static boolean canPlacePartHost(@Nullable Player player, Level level, BlockPos pos) {
if (player != null && !level.mayInteract(player, pos)) {
return false;
}

return level.isEmptyBlock(pos) || level.getBlockState(pos).getMaterial().isReplaceable();
}

/**
* Gets a part host at the given position.
*/
@Nullable
public static IPartHost getPartHost(Level level, BlockPos pos) {
var blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof IPartHost partHost) {
return partHost;
}

return null;
}

/**
* @return the render mode
*/
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/appeng/block/networking/CableBusBlock.java
Expand Up @@ -300,12 +300,12 @@ protected BlockState updateBlockStateFromBlockEntity(BlockState currentState, Ca
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockPos pos = context.getClickedPos();
FluidState fluidState = context.getLevel().getFluidState(pos);
BlockState blockState = this.defaultBlockState()
.setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER);
return getStateForPlacement(context.getLevel(), context.getClickedPos());
}

return blockState;
public BlockState getStateForPlacement(Level level, BlockPos pos) {
var fluidState = level.getFluidState(pos);
return this.defaultBlockState().setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER);
}

@Override
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/appeng/core/AEConfig.java
Expand Up @@ -418,6 +418,13 @@ public int getPathfindingStepsPerTick() {
return COMMON.pathfindingStepsPerTick.get();
}

/**
* @return True if an in-world preview of parts and facade placement should be shown when holding one in hand.
*/
public boolean isPlacementPreviewEnabled() {
return CLIENT.showPlacementPreview.get();
}

// Setters keep visibility as low as possible.

private static class ClientConfig {
Expand All @@ -429,6 +436,7 @@ private static class ClientConfig {
public final BooleanOption disableColoredCableRecipesInJEI;
public final EnumOption<PowerUnits> selectedPowerUnit;
public final BooleanOption debugGuiOverlays;
public final BooleanOption showPlacementPreview;

// Terminal Settings
public final EnumOption<YesNo> searchTooltips;
Expand All @@ -443,6 +451,8 @@ public ClientConfig(ConfigSection root) {
this.useColoredCraftingStatus = client.addBoolean("useColoredCraftingStatus", true);
this.selectedPowerUnit = client.addEnum("PowerUnit", PowerUnits.AE, "Power unit shown in AE UIs");
this.debugGuiOverlays = client.addBoolean("showDebugGuiOverlays", false, "Show debugging GUI overlays");
this.showPlacementPreview = client.addBoolean("showPlacementPreview", true,
"Show a preview of part and facade placement");

ConfigSection terminals = root.subsection("terminals");
this.searchTooltips = terminals.addEnum("searchTooltips", YesNo.YES,
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/appeng/core/AppEngBase.java
Expand Up @@ -80,7 +80,6 @@
import appeng.init.worldgen.InitFeatures;
import appeng.init.worldgen.InitStructures;
import appeng.items.tools.NetworkToolItem;
import appeng.parts.PartPlacement;
import appeng.server.AECommand;
import appeng.server.testworld.GameTestPlotAdapter;
import appeng.services.ChunkLoadingService;
Expand Down Expand Up @@ -154,7 +153,6 @@ public AppEngBase() {

UseBlockCallback.EVENT.register(WrenchHook::onPlayerUseBlock);
UseBlockCallback.EVENT.register(ToolItemHook::onPlayerUseBlock);
UseBlockCallback.EVENT.register(PartPlacement::onPlayerUseBlock);
InitBiomeModifications.init();
}

Expand Down
2 changes: 0 additions & 2 deletions src/main/java/appeng/core/sync/BasePacketHandler.java
Expand Up @@ -44,8 +44,6 @@ public enum PacketTypes {

CONFIG_BUTTON(ConfigButtonPacket.class, ConfigButtonPacket::new),

PART_PLACEMENT(PartPlacementPacket.class, PartPlacementPacket::new),

LIGHTNING(LightningPacket.class, LightningPacket::new),

MATTER_CANNON(MatterCannonPacket.class, MatterCannonPacket::new),
Expand Down
80 changes: 0 additions & 80 deletions src/main/java/appeng/core/sync/packets/PartPlacementPacket.java

This file was deleted.

7 changes: 6 additions & 1 deletion src/main/java/appeng/facade/FacadeContainer.java
Expand Up @@ -42,9 +42,14 @@ public FacadeContainer(CableBusStorage cbs, Runnable changeCallback) {
this.changeCallback = changeCallback;
}

@Override
public boolean canAddFacade(IFacadePart a) {
return this.getFacade(a.getSide()) == null;
}

@Override
public boolean addFacade(IFacadePart a) {
if (this.getFacade(a.getSide()) == null) {
if (canAddFacade(a)) {
this.storage.setFacade(a.getSide(), a);
this.notifyChange();
return true;
Expand Down

0 comments on commit d96f836

Please sign in to comment.