Skip to content

Commit

Permalink
Move Lever to Hitbox System (closes #224)
Browse files Browse the repository at this point in the history
  • Loading branch information
hammy275 committed May 9, 2024
1 parent 8ce50f2 commit f475719
Show file tree
Hide file tree
Showing 10 changed files with 298 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ protected static void serverSetup() {
BeaconDataPacket::decode, BeaconDataPacket::handle);
Network.INSTANCE.register(DoubleControllerVibrate.class, DoubleControllerVibrate::encode,
DoubleControllerVibrate::decode, DoubleControllerVibrate::handle);
Network.INSTANCE.register(UsePacket.class, UsePacket::encode,
UsePacket::decode, UsePacket::handle);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class ClientConstants {
public static final int ticksToRenderHitboxesImmersive = Integer.MAX_VALUE;
public static final int ticksToRenderSmithingTable = ticksToRenderAnvil;
public static final int ticksToRenderChiseledBookshelf = Integer.MAX_VALUE;
public static final int ticksToRenderLever = Integer.MAX_VALUE;

// Size of items when rendered in front of something immersive
public static final float defaultItemScaleSize = 1f/3f;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package com.hammy275.immersivemc.client.immersive;

import com.hammy275.immersivemc.client.config.ClientConstants;
import com.hammy275.immersivemc.client.immersive.info.AbstractImmersiveInfo;
import com.hammy275.immersivemc.client.immersive.info.LeverInfo;
import com.hammy275.immersivemc.common.config.ActiveConfig;
import com.hammy275.immersivemc.common.immersive.ImmersiveCheckers;
import com.hammy275.immersivemc.common.immersive.handler.ImmersiveHandler;
import com.hammy275.immersivemc.common.immersive.storage.network.NetworkStorage;
import com.hammy275.immersivemc.common.network.Network;
import com.hammy275.immersivemc.common.network.packet.UsePacket;
import com.hammy275.immersivemc.common.util.Util;
import com.hammy275.immersivemc.common.vr.VRPlugin;
import com.mojang.blaze3d.vertex.PoseStack;
import net.blf02.vrapi.api.data.IVRData;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.AttachFace;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;

public class ImmersiveLever extends AbstractImmersive<LeverInfo> {
public ImmersiveLever() {
super(-1);
}

@Override
public boolean isVROnly() {
return true;
}

@Override
public boolean clientAuthoritative() {
return true;
}

@Override
public @Nullable ImmersiveHandler getHandler() {
return null;
}

@Override
public boolean shouldRender(LeverInfo info, boolean isInVR) {
return info.readyToRender();
}

@Override
protected void render(LeverInfo info, PoseStack stack, boolean isInVR) {
for (int i = 0; i <= 1; i++) {
renderHitbox(stack, info.getHitbox(i));
}
}

@Override
protected void doTick(LeverInfo info, boolean isInVR) {
super.doTick(info, isInVR);

BlockState lever = Minecraft.getInstance().level.getBlockState(info.getBlockPosition());
boolean powered = lever.getValue(BlockStateProperties.POWERED);
int startHitbox = powered ? 1 : 0;
int endHitbox = powered ? 0 : 1;

for (int c = 0; c <= 1; c++) {
IVRData hand = VRPlugin.API.getVRPlayer(Minecraft.getInstance().player).getController(c);
int lastGrabbed = info.grabbedBox[c];
int grabbed = Util.getFirstIntersect(hand.position(), info.getAllHitboxes()).orElse(-1);
info.grabbedBox[c] = grabbed;
if (grabbed == endHitbox && lastGrabbed == startHitbox) {
Util.useLever(Minecraft.getInstance().player, info.getBlockPosition());
Network.INSTANCE.sendToServer(new UsePacket(info.getBlockPosition()));
}
}

}

@Override
public boolean enabledInConfig() {
return ActiveConfig.active().useLever;
}

@Override
protected boolean inputSlotShouldRenderHelpHitbox(LeverInfo info, int slotNum) {
return false;
}

@Override
public boolean shouldTrack(BlockPos pos, Level level) {
return ImmersiveCheckers.isLever(pos, level);
}

@Override
public @Nullable LeverInfo refreshOrTrackObject(BlockPos pos, Level level) {
for (LeverInfo info : getTrackedObjects()) {
if (info.getBlockPosition().equals(pos)) {
info.setTicksLeft(ClientConstants.ticksToRenderLever);
return info;
}
}
LeverInfo info = new LeverInfo(pos);
infos.add(info);
return info;
}

@Override
public boolean shouldBlockClickIfEnabled(AbstractImmersiveInfo info) {
return true;
}

@Override
protected void initInfo(LeverInfo info) {
Level level = Minecraft.getInstance().level;
BlockState state = level.getBlockState(info.getBlockPosition());
Vec3 center = Vec3.atCenterOf(info.getBlockPosition());
AttachFace attachFace = state.getValue(BlockStateProperties.ATTACH_FACE);
Direction facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING);
Direction towardsBaseDir;
Direction towardsOnDir;
switch (attachFace) {
case WALL -> {
towardsBaseDir = facing.getOpposite();
towardsOnDir = Direction.DOWN;
}
case CEILING -> {
towardsBaseDir = Direction.UP;
towardsOnDir = facing;
}
case FLOOR -> {
towardsBaseDir = Direction.DOWN;
towardsOnDir = facing;
}
default -> throw new IllegalStateException("Lever is attached to unknown face " + attachFace.getSerializedName());
}
Vec3 towardsBase = Vec3.atLowerCornerOf(towardsBaseDir.getNormal());
Vec3 towardsOn = Vec3.atLowerCornerOf(towardsOnDir.getNormal());
center = center.add(towardsBase.scale(0.25));

Vec3 offPos = center.add(towardsOn.scale(-0.25));
Vec3 onPos = center.add(towardsOn.scale(0.25));

info.setPosition(0, offPos);
info.setPosition(1, onPos);

info.setHitbox(0, AABB.ofSize(offPos, 0.5, 0.5, 0.5));
info.setHitbox(1, AABB.ofSize(onPos, 0.5, 0.5, 0.5));
}

@Override
public void handleRightClick(AbstractImmersiveInfo info, Player player, int closest, InteractionHand hand) {
// NO-OP. Handled in doTick()
}

@Override
public void processStorageFromNetwork(AbstractImmersiveInfo info, NetworkStorage storage) {
// NO-OP. No storage.
}

@Override
public BlockPos getLightPos(LeverInfo info) {
return info.getBlockPosition();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ public class Immersives {
.setVROnly(true)
.build();

public static final ImmersiveLever immersiveLever = new ImmersiveLever();

public static final ImmersiveRepeater immersiveRepeater = new ImmersiveRepeater();
public static final BuiltImmersive immersiveShulker = ImmersiveBuilder.create(ImmersiveHandlers.shulkerBoxHandler)
.setConfigChecker(() -> ActiveConfig.active().useShulkerImmersion)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.hammy275.immersivemc.client.immersive.info;

import com.hammy275.immersivemc.client.config.ClientConstants;
import com.hammy275.immersivemc.common.obb.BoundingBox;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;

public class LeverInfo extends AbstractImmersiveInfo {

protected BoundingBox[] hitboxes = new BoundingBox[2];
protected Vec3[] positions = new Vec3[2];
protected final BlockPos pos;
public int[] grabbedBox = new int[]{-1, -1}; // Index is for controller num

public LeverInfo(BlockPos pos) {
super(ClientConstants.ticksToRenderLever);
this.pos = pos;
}

@Override
public void setInputSlots() {
this.inputHitboxes = hitboxes;
}

@Override
public BoundingBox getHitbox(int index) {
return hitboxes[index];
}

@Override
public BoundingBox[] getAllHitboxes() {
return hitboxes;
}

@Override
public void setHitbox(int slot, BoundingBox hitbox) {
hitboxes[slot] = hitbox;
}

@Override
public boolean hasHitboxes() {
return hitboxes[1] != null;
}

@Override
public Vec3 getPosition(int index) {
return positions[index];
}

@Override
public Vec3[] getAllPositions() {
return positions;
}

@Override
public void setPosition(int slot, Vec3 position) {
positions[slot] = position;
}

@Override
public boolean hasPositions() {
return positions[1] != null;
}

@Override
public boolean readyToRender() {
return hasHitboxes() && hasPositions();
}

@Override
public BlockPos getBlockPosition() {
return pos;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.hammy275.immersivemc.common.immersive.handler.ImmersiveHandlers;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.LeverBlock;
import net.minecraft.world.level.block.RepeaterBlock;

import java.util.LinkedList;
Expand All @@ -14,6 +15,7 @@ public class ImmersiveCheckers {
public static final List<CheckerFunction> CHECKERS = new LinkedList<>();

static {
CHECKERS.add(ImmersiveCheckers::isLever);
CHECKERS.add(ImmersiveCheckers::isRepeater);

for (ImmersiveHandler handler : ImmersiveHandlers.HANDLERS) {
Expand All @@ -23,6 +25,10 @@ public class ImmersiveCheckers {

// Vanilla

public static boolean isLever(BlockPos pos, Level level) {
return level.getBlockState(pos).getBlock() instanceof LeverBlock;
}

public static boolean isRepeater(BlockPos pos, Level level) {
return level.getBlockState(pos).getBlock() instanceof RepeaterBlock;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.hammy275.immersivemc.common.network.packet;

import com.hammy275.immersivemc.common.immersive.ImmersiveCheckers;
import com.hammy275.immersivemc.common.util.Util;
import dev.architectury.networking.NetworkManager;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;

import java.util.function.Supplier;

public class UsePacket {

public final BlockPos pos;

public UsePacket(BlockPos pos) {
this.pos = pos;
}

public static void encode(UsePacket message, FriendlyByteBuf buffer) {
buffer.writeBlockPos(message.pos);
}

public static UsePacket decode(FriendlyByteBuf buffer) {
return new UsePacket(buffer.readBlockPos());
}

public static void handle(final UsePacket packet, Supplier<NetworkManager.PacketContext> ctx) {
ctx.get().queue(() -> {
ServerPlayer player = ctx.get().getPlayer() instanceof ServerPlayer ? (ServerPlayer) ctx.get().getPlayer() : null;
if (player != null && ImmersiveCheckers.isLever(packet.pos, player.level())) {
Util.useLever(player, packet.pos);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.*;
Expand Down Expand Up @@ -197,6 +198,14 @@ public static void setRepeater(Level level, BlockPos pos, int newDelay) {
}
}

public static void useLever(Player player, BlockPos pos) {
if (ImmersiveCheckers.isLever(pos, player.level())) {
BlockState lever = player.level().getBlockState(pos);
lever.use(player.level(), player, InteractionHand.MAIN_HAND,
new BlockHitResult(Vec3.atCenterOf(pos), Direction.NORTH, pos, true));
}
}

public static Vec3 getPlayerVelocity(Vec3 lastTickPos, Vec3 currentTickPos) {
return new Vec3(currentTickPos.x - lastTickPos.x, currentTickPos.y - lastTickPos.y,
currentTickPos.z - lastTickPos.z);
Expand Down
Loading

0 comments on commit f475719

Please sign in to comment.