-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
271 additions
and
0 deletions.
There are no files selected for viewing
19 changes: 19 additions & 0 deletions
19
common/src/main/java/com/yogpc/qp/machine/placer/AbstractPlacerBlock.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.yogpc.qp.machine.placer; | ||
|
||
import com.yogpc.qp.machine.QpEntityBlock; | ||
import net.minecraft.world.item.BlockItem; | ||
import net.minecraft.world.item.Item; | ||
import net.minecraft.world.level.material.MapColor; | ||
import net.minecraft.world.level.material.PushReaction; | ||
|
||
public abstract class AbstractPlacerBlock extends QpEntityBlock { | ||
public AbstractPlacerBlock(String name) { | ||
super( | ||
Properties.of() | ||
.mapColor(MapColor.METAL) | ||
.pushReaction(PushReaction.BLOCK).strength(1.2f), | ||
name, | ||
b -> new BlockItem(b, new Item.Properties()) | ||
); | ||
} | ||
} |
252 changes: 252 additions & 0 deletions
252
common/src/main/java/com/yogpc/qp/machine/placer/AbstractPlacerTile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
package com.yogpc.qp.machine.placer; | ||
|
||
import com.yogpc.qp.PlatformAccess; | ||
import com.yogpc.qp.machine.QpEntity; | ||
import com.yogpc.qp.packet.ClientSync; | ||
import net.minecraft.core.BlockPos; | ||
import net.minecraft.core.Direction; | ||
import net.minecraft.core.registries.Registries; | ||
import net.minecraft.server.level.ServerLevel; | ||
import net.minecraft.world.Container; | ||
import net.minecraft.world.InteractionHand; | ||
import net.minecraft.world.SimpleContainer; | ||
import net.minecraft.world.entity.player.Player; | ||
import net.minecraft.world.item.BlockItem; | ||
import net.minecraft.world.item.Item; | ||
import net.minecraft.world.item.ItemStack; | ||
import net.minecraft.world.item.Items; | ||
import net.minecraft.world.item.context.BlockPlaceContext; | ||
import net.minecraft.world.item.context.UseOnContext; | ||
import net.minecraft.world.item.enchantment.Enchantments; | ||
import net.minecraft.world.level.block.Block; | ||
import net.minecraft.world.level.block.state.BlockState; | ||
import net.minecraft.world.phys.BlockHitResult; | ||
import net.minecraft.world.phys.Vec3; | ||
|
||
import java.util.*; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import java.util.function.BooleanSupplier; | ||
import java.util.function.Predicate; | ||
|
||
public abstract class AbstractPlacerTile extends QpEntity | ||
implements ClientSync, Container { | ||
|
||
public static final Map<Direction, Vec3> DIRECTION_VEC3D_MAP; | ||
|
||
static { | ||
EnumMap<Direction, Vec3> map = new EnumMap<>(Direction.class); | ||
map.put(Direction.DOWN, new Vec3(0.5, 0, 0.5)); | ||
map.put(Direction.UP, new Vec3(0.5, 1, 0.5)); | ||
map.put(Direction.NORTH, new Vec3(0.5, 0.5, 0)); | ||
map.put(Direction.SOUTH, new Vec3(0.5, 0.5, 1)); | ||
map.put(Direction.EAST, new Vec3(1, 0.5, 0.5)); | ||
map.put(Direction.WEST, new Vec3(0, 0.5, 0.5)); | ||
DIRECTION_VEC3D_MAP = Collections.unmodifiableMap(map); | ||
} | ||
|
||
private final SimpleContainer container = new PlacerContainer(this, getContainerSize()); | ||
private int lastPlacedIndex = 0; | ||
public RedStoneMode redstoneMode = RedStoneMode.PULSE; | ||
|
||
protected AbstractPlacerTile(BlockPos pos, BlockState blockState) { | ||
super(pos, blockState); | ||
} | ||
|
||
protected abstract BlockPos getTargetPos(); | ||
|
||
protected abstract Direction getMachineFacing(); | ||
|
||
protected boolean isPowered() { | ||
assert level != null; | ||
return Arrays.stream(Direction.values()).filter(Predicate.isEqual(getMachineFacing()).negate()) | ||
.anyMatch(f -> level.hasSignal(getBlockPos().relative(f), f)) || level.hasNeighborSignal(getBlockPos().above()); | ||
} | ||
|
||
void breakBlock() { | ||
if (level == null || !redstoneMode.canBreak()) return; | ||
BlockPos pos = getTargetPos(); | ||
BlockState state = level.getBlockState(pos); | ||
if (state.getDestroySpeed(level, pos) < 0) return; // Unbreakable. | ||
Player fake = PlatformAccess.getAccess().mining().getQuarryFakePlayer(this, (ServerLevel) level, pos); | ||
fake.setItemInHand(InteractionHand.MAIN_HAND, getSilkPickaxe()); | ||
List<ItemStack> drops = Block.getDrops(state, (ServerLevel) level, pos, level.getBlockEntity(pos)); | ||
level.removeBlock(pos, false); | ||
/*drops.stream().map(s -> ItemHandlerHelper.insertItem(this.itemHandler, s, false)) // Return not-inserted items. | ||
.filter(Predicate.not(ItemStack::isEmpty)).forEach(s -> Block.popResource(level, getBlockPos(), s));*/ | ||
} | ||
|
||
/** | ||
* @return Whether the placement succeeded. | ||
*/ | ||
boolean placeBlock() { | ||
if (isEmpty() || !redstoneMode.canPlace()) return false; | ||
Direction facing = getMachineFacing(); | ||
BlockPos pos = getTargetPos(); | ||
Vec3 hitPos = DIRECTION_VEC3D_MAP.get(facing.getOpposite()).add(pos.getX(), pos.getY(), pos.getZ()); | ||
BlockHitResult rayTrace = new BlockHitResult(hitPos, facing.getOpposite(), pos, false); | ||
Player fake = PlatformAccess.getAccess().mining().getQuarryFakePlayer(this, (ServerLevel) level, pos); | ||
|
||
AtomicBoolean result = new AtomicBoolean(false); | ||
findEntry(container.getItems(), | ||
i -> tryPlaceItem(i, fake, rayTrace), | ||
lastPlacedIndex).ifPresent(i -> { | ||
if (!getItem(i).isEmpty()) { | ||
this.lastPlacedIndex = i; | ||
} else { | ||
this.lastPlacedIndex = findEntry(container.getItems(), s -> !s.isEmpty() && s.getItem() instanceof BlockItem, i).orElse(0); | ||
} | ||
setChanged(); | ||
syncToClient(); | ||
result.set(true); | ||
}); | ||
fake.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); | ||
return result.get(); | ||
} | ||
|
||
// -------------------- Utility -------------------- | ||
|
||
public static <T> OptionalInt findEntry(List<T> check, Predicate<T> filter, int startIndex) { | ||
int listSize = check.size(); | ||
if (startIndex >= listSize) | ||
return OptionalInt.empty(); | ||
return findEntryInternal(check, filter, startIndex, startIndex, listSize); | ||
} | ||
|
||
private static <T> OptionalInt findEntryInternal(List<T> check, Predicate<T> filter, int startIndex, int index, int listSize) { | ||
T value = check.get(index); | ||
if (filter.test(value)) | ||
return OptionalInt.of(index); | ||
if (index == startIndex - 1 || (startIndex == 0 && index == listSize - 1)) { | ||
// last search | ||
return OptionalInt.empty(); | ||
} else { | ||
int next = index + 1 == listSize ? 0 : index + 1; | ||
return findEntryInternal(check, filter, startIndex, next, listSize); | ||
} | ||
} | ||
|
||
static boolean tryPlaceItem(ItemStack stack, Player fake, BlockHitResult rayTrace) { | ||
if (stack.isEmpty()) return false; | ||
Item item = stack.getItem(); | ||
if (item instanceof BlockItem blockItem) { | ||
fake.setItemInHand(InteractionHand.MAIN_HAND, stack); | ||
BlockPlaceContext context = new BlockPlaceContext(new UseOnContext(fake, InteractionHand.MAIN_HAND, rayTrace)); | ||
return blockItem.place(context).consumesAction(); | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
public int getLastPlacedIndex() { | ||
return lastPlacedIndex; | ||
} | ||
|
||
protected ItemStack getSilkPickaxe() { | ||
assert level != null; | ||
ItemStack stack = new ItemStack(Items.DIAMOND_PICKAXE); | ||
stack.enchant(level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(Enchantments.SILK_TOUCH), 1); | ||
return stack; | ||
} | ||
|
||
// Container | ||
|
||
@Override | ||
public int getContainerSize() { | ||
return 9; | ||
} | ||
|
||
@Override | ||
public boolean isEmpty() { | ||
return container.isEmpty(); | ||
} | ||
|
||
@Override | ||
public ItemStack getItem(int slot) { | ||
return container.getItem(slot); | ||
} | ||
|
||
@Override | ||
public ItemStack removeItem(int slot, int amount) { | ||
return container.removeItem(slot, amount); | ||
} | ||
|
||
@Override | ||
public ItemStack removeItemNoUpdate(int slot) { | ||
return container.removeItemNoUpdate(slot); | ||
} | ||
|
||
@Override | ||
public void setItem(int slot, ItemStack stack) { | ||
container.setItem(slot, stack); | ||
} | ||
|
||
@Override | ||
public boolean stillValid(Player player) { | ||
return container.stillValid(player); | ||
} | ||
|
||
@Override | ||
public void clearContent() { | ||
container.clearContent(); | ||
} | ||
|
||
private static final class PlacerContainer extends SimpleContainer { | ||
private final QpEntity parent; | ||
|
||
public PlacerContainer(QpEntity parent, int size) { | ||
super(size); | ||
this.parent = parent; | ||
} | ||
|
||
@Override | ||
public void setChanged() { | ||
super.setChanged(); | ||
parent.setChanged(); | ||
} | ||
} | ||
|
||
public enum RedStoneMode { | ||
PULSE(true, true), | ||
PULSE_PLACE_ONLY(true, false), | ||
PULSE_BREAK_ONLY(false, true), | ||
; | ||
private final boolean placeEnabled; | ||
private final boolean breakEnabled; | ||
|
||
RedStoneMode(boolean placeEnabled, boolean breakEnabled) { | ||
this.placeEnabled = placeEnabled; | ||
this.breakEnabled = breakEnabled; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return name().replace('_', ' '); | ||
} | ||
|
||
public boolean canPlace() { | ||
return placeEnabled; | ||
} | ||
|
||
public boolean canBreak() { | ||
return breakEnabled; | ||
} | ||
|
||
public boolean shouldWork(BooleanSupplier powered) { | ||
return true; | ||
} | ||
|
||
public static RedStoneMode cycle(RedStoneMode now) { | ||
RedStoneMode[] modes = values(); | ||
for (int i = 0; i < modes.length; i++) { | ||
RedStoneMode mode = modes[i]; | ||
if (mode == now) { | ||
if (i + 1 == modes.length) | ||
return modes[0]; | ||
else | ||
return modes[i + 1]; | ||
} | ||
} | ||
return modes[0]; | ||
} | ||
} | ||
} |