WIP Overhaul
Block calculation only on client, then send to server to place. BuilderChain system to decouple buildmodes, buildmodifiers and randomizer bag.
This commit is contained in:
@@ -8,17 +8,10 @@ import net.minecraft.client.Minecraft;
|
|||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.client.player.LocalPlayer;
|
import net.minecraft.client.player.LocalPlayer;
|
||||||
import net.minecraft.client.renderer.ShaderInstance;
|
import net.minecraft.client.renderer.ShaderInstance;
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.sounds.SoundSource;
|
|
||||||
import net.minecraft.world.InteractionHand;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.BlockItem;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.level.ClipContext;
|
import net.minecraft.world.level.ClipContext;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.SoundType;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
@@ -36,7 +29,6 @@ import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
|||||||
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
||||||
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
|
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
||||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
|
||||||
import nl.requios.effortlessbuilding.gui.buildmode.PlayerSettingsGui;
|
import nl.requios.effortlessbuilding.gui.buildmode.PlayerSettingsGui;
|
||||||
import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu;
|
import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu;
|
||||||
import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui;
|
import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui;
|
||||||
@@ -92,7 +84,12 @@ public class ClientEvents {
|
|||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onClientTick(TickEvent.ClientTickEvent event) {
|
public static void onClientTick(TickEvent.ClientTickEvent event) {
|
||||||
|
if (!isGameActive()) return;
|
||||||
|
|
||||||
if (event.phase == TickEvent.Phase.START) {
|
if (event.phase == TickEvent.Phase.START) {
|
||||||
|
|
||||||
|
EffortlessBuildingClient.BUILDER_CHAIN.onTick();
|
||||||
|
|
||||||
onMouseInput();
|
onMouseInput();
|
||||||
|
|
||||||
//Update previousLookAt
|
//Update previousLookAt
|
||||||
@@ -140,41 +137,11 @@ public class ClientEvents {
|
|||||||
|
|
||||||
if (mc.options.keyUse.isDown()) {
|
if (mc.options.keyUse.isDown()) {
|
||||||
|
|
||||||
//KeyBinding.setKeyBindState(mc.gameSettings.keyBindUseItem.getKeyCode(), false);
|
|
||||||
|
|
||||||
if (placeCooldown <= 0) {
|
if (placeCooldown <= 0) {
|
||||||
placeCooldown = 4;
|
placeCooldown = 4;
|
||||||
|
|
||||||
ItemStack currentItemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
|
EffortlessBuildingClient.BUILDER_CHAIN.onRightClick();
|
||||||
if (currentItemStack.getItem() instanceof BlockItem ||
|
|
||||||
(CompatHelper.isItemBlockProxy(currentItemStack) && !player.isShiftKeyDown())) {
|
|
||||||
|
|
||||||
ItemStack itemStack = CompatHelper.getItemBlockFromStack(currentItemStack);
|
|
||||||
|
|
||||||
//find position in distance
|
|
||||||
HitResult lookingAt = getLookingAt(player);
|
|
||||||
if (lookingAt != null && lookingAt.getType() == HitResult.Type.BLOCK) {
|
|
||||||
BlockHitResult blockLookingAt = (BlockHitResult) lookingAt;
|
|
||||||
|
|
||||||
BuildModes.onBlockPlacedMessage(player, new BlockPlacedMessage(blockLookingAt, true));
|
|
||||||
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage(blockLookingAt, true));
|
|
||||||
|
|
||||||
//play sound if further than normal
|
|
||||||
if ((blockLookingAt.getLocation().subtract(player.getEyePosition(1f))).lengthSqr() > 25f &&
|
|
||||||
itemStack.getItem() instanceof BlockItem) {
|
|
||||||
|
|
||||||
BlockState state = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
|
|
||||||
BlockPos blockPos = blockLookingAt.getBlockPos();
|
|
||||||
SoundType soundType = state.getBlock().getSoundType(state, player.level, blockPos, player);
|
|
||||||
player.level.playSound(player, player.blockPosition(), soundType.getPlaceSound(), SoundSource.BLOCKS,
|
|
||||||
0.4f, soundType.getPitch());
|
|
||||||
player.swing(InteractionHand.MAIN_HAND);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
BuildModes.onBlockPlacedMessage(player, new BlockPlacedMessage());
|
|
||||||
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (buildMode == BuildModes.BuildModeEnum.SINGLE) {
|
} else if (buildMode == BuildModes.BuildModeEnum.SINGLE) {
|
||||||
placeCooldown--;
|
placeCooldown--;
|
||||||
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) placeCooldown = 0;
|
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) placeCooldown = 0;
|
||||||
@@ -189,34 +156,13 @@ public class ClientEvents {
|
|||||||
if (breakCooldown <= 0) {
|
if (breakCooldown <= 0) {
|
||||||
breakCooldown = 4;
|
breakCooldown = 4;
|
||||||
|
|
||||||
HitResult lookingAt = getLookingAt(player);
|
EffortlessBuildingClient.BUILDER_CHAIN.onLeftClick();
|
||||||
if (lookingAt != null && lookingAt.getType() == HitResult.Type.BLOCK) {
|
|
||||||
BlockHitResult blockLookingAt = (BlockHitResult) lookingAt;
|
|
||||||
|
|
||||||
BuildModes.onBlockBrokenMessage(player, new BlockBrokenMessage(blockLookingAt));
|
|
||||||
PacketHandler.INSTANCE.sendToServer(new BlockBrokenMessage(blockLookingAt));
|
|
||||||
|
|
||||||
//play sound if further than normal
|
|
||||||
if ((blockLookingAt.getLocation().subtract(player.getEyePosition(1f))).lengthSqr() > 25f) {
|
|
||||||
|
|
||||||
BlockPos blockPos = blockLookingAt.getBlockPos();
|
|
||||||
BlockState state = player.level.getBlockState(blockPos);
|
|
||||||
SoundType soundtype = state.getBlock().getSoundType(state, player.level, blockPos, player);
|
|
||||||
player.level.playSound(player, player.blockPosition(), soundtype.getBreakSound(), SoundSource.BLOCKS,
|
|
||||||
0.4f, soundtype.getPitch());
|
|
||||||
player.swing(InteractionHand.MAIN_HAND);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
BuildModes.onBlockBrokenMessage(player, new BlockBrokenMessage());
|
|
||||||
PacketHandler.INSTANCE.sendToServer(new BlockBrokenMessage());
|
|
||||||
}
|
|
||||||
} else if (buildMode == BuildModes.BuildModeEnum.SINGLE) {
|
} else if (buildMode == BuildModes.BuildModeEnum.SINGLE) {
|
||||||
breakCooldown--;
|
breakCooldown--;
|
||||||
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) breakCooldown = 0;
|
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) breakCooldown = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//EffortlessBuilding.packetHandler.sendToServer(new CancelModeMessage());
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
breakCooldown = 0;
|
breakCooldown = 0;
|
||||||
}
|
}
|
||||||
@@ -310,7 +256,7 @@ public class ClientEvents {
|
|||||||
public static void onGuiOpen(ScreenEvent event) {
|
public static void onGuiOpen(ScreenEvent event) {
|
||||||
Player player = Minecraft.getInstance().player;
|
Player player = Minecraft.getInstance().player;
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
BuildModes.initializeMode(player);
|
EffortlessBuildingClient.BUILDER_CHAIN.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +266,7 @@ public class ClientEvents {
|
|||||||
keyBindings[2].getKey().getValue());
|
keyBindings[2].getKey().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HitResult getLookingAt(Player player) {
|
public static BlockHitResult getLookingAt(Player player) {
|
||||||
Level world = player.level;
|
Level world = player.level;
|
||||||
|
|
||||||
//base distance off of player ability (config)
|
//base distance off of player ability (config)
|
||||||
@@ -329,9 +275,12 @@ public class ClientEvents {
|
|||||||
Vec3 look = player.getLookAngle();
|
Vec3 look = player.getLookAngle();
|
||||||
Vec3 start = new Vec3(player.getX(), player.getY() + player.getEyeHeight(), player.getZ());
|
Vec3 start = new Vec3(player.getX(), player.getY() + player.getEyeHeight(), player.getZ());
|
||||||
Vec3 end = new Vec3(player.getX() + look.x * raytraceRange, player.getY() + player.getEyeHeight() + look.y * raytraceRange, player.getZ() + look.z * raytraceRange);
|
Vec3 end = new Vec3(player.getX() + look.x * raytraceRange, player.getY() + player.getEyeHeight() + look.y * raytraceRange, player.getZ() + look.z * raytraceRange);
|
||||||
// return player.rayTrace(raytraceRange, 1f, RayTraceFluidMode.NEVER);
|
|
||||||
//TODO 1.14 check if correct
|
|
||||||
return world.clip(new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player));
|
return world.clip(new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isGameActive() {
|
||||||
|
return !(Minecraft.getInstance().level == null || Minecraft.getInstance().player == null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
|||||||
import net.minecraftforge.common.util.FakePlayer;
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent;
|
|
||||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||||
import net.minecraftforge.event.level.BlockEvent;
|
import net.minecraftforge.event.level.BlockEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
@@ -29,7 +28,6 @@ import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
|||||||
import nl.requios.effortlessbuilding.network.AddUndoMessage;
|
import nl.requios.effortlessbuilding.network.AddUndoMessage;
|
||||||
import nl.requios.effortlessbuilding.network.ClearUndoMessage;
|
import nl.requios.effortlessbuilding.network.ClearUndoMessage;
|
||||||
import nl.requios.effortlessbuilding.network.PacketHandler;
|
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||||
import nl.requios.effortlessbuilding.network.RequestLookAtMessage;
|
|
||||||
|
|
||||||
@EventBusSubscriber
|
@EventBusSubscriber
|
||||||
public class CommonEvents {
|
public class CommonEvents {
|
||||||
@@ -61,18 +59,17 @@ public class CommonEvents {
|
|||||||
EffortlessBuilding.DELAYED_BLOCK_PLACER.tick();
|
EffortlessBuilding.DELAYED_BLOCK_PLACER.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Cancel event if necessary. Nothing more, rest is handled on mouse right click
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) {
|
public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) {
|
||||||
if (event.getLevel().isClientSide()) return; //Never called clientside anyway, but just to be sure
|
if (event.getLevel().isClientSide()) return; //Never called clientside anyway, but just to be sure
|
||||||
|
|
||||||
if (!(event.getEntity() instanceof Player player)) return;
|
if (!(event.getEntity() instanceof Player player)) return;
|
||||||
|
|
||||||
if (event.getEntity() instanceof FakePlayer) return;
|
if (event.getEntity() instanceof FakePlayer) return;
|
||||||
|
|
||||||
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
|
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
|
||||||
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
|
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
|
||||||
|
|
||||||
if (buildMode != BuildModes.BuildModeEnum.DISABLED) {
|
if (buildMode != BuildModes.BuildModeEnum.DISABLED || modifierSettings.doQuickReplace()) {
|
||||||
|
|
||||||
//Only cancel if itemblock in hand
|
//Only cancel if itemblock in hand
|
||||||
//Fixed issue with e.g. Create Wrench shift-rightclick disassembling being cancelled.
|
//Fixed issue with e.g. Create Wrench shift-rightclick disassembling being cancelled.
|
||||||
@@ -80,19 +77,10 @@ public class CommonEvents {
|
|||||||
event.setCanceled(true);
|
event.setCanceled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (modifierSettings.doQuickReplace()) {
|
|
||||||
//Cancel event and send message if QuickReplace
|
|
||||||
if (isPlayerHoldingBlock(player)) {
|
|
||||||
event.setCanceled(true);
|
|
||||||
}
|
|
||||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new RequestLookAtMessage(true));
|
|
||||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
|
|
||||||
} else {
|
} else {
|
||||||
//NORMAL mode, let vanilla handle block placing
|
//NORMAL mode, let vanilla handle block placing
|
||||||
//But modifiers should still work
|
|
||||||
|
|
||||||
//Send message to client, which sends message back with raytrace info
|
//TODO move UndoRedo to serverside only
|
||||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new RequestLookAtMessage(false));
|
|
||||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
|
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,7 +88,6 @@ public class CommonEvents {
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onBlockBroken(BlockEvent.BreakEvent event) {
|
public static void onBlockBroken(BlockEvent.BreakEvent event) {
|
||||||
if (event.getLevel().isClientSide()) return;
|
if (event.getLevel().isClientSide()) return;
|
||||||
|
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
if (player instanceof FakePlayer) return;
|
if (player instanceof FakePlayer) return;
|
||||||
|
|
||||||
@@ -111,9 +98,6 @@ public class CommonEvents {
|
|||||||
event.setCanceled(true);
|
event.setCanceled(true);
|
||||||
} else {
|
} else {
|
||||||
//NORMAL mode, let vanilla handle block breaking
|
//NORMAL mode, let vanilla handle block breaking
|
||||||
//But modifiers and QuickReplace should still work
|
|
||||||
//Dont break the original block yourself, otherwise Tinkers Hammer and Veinminer won't work
|
|
||||||
BuildModes.onBlockBroken(player, event.getPos(), false);
|
|
||||||
|
|
||||||
//Add to undo stack in client
|
//Add to undo stack in client
|
||||||
if (player instanceof ServerPlayer && event.getState() != null && event.getPos() != null) {
|
if (player instanceof ServerPlayer && event.getState() != null && event.getPos() != null) {
|
||||||
|
|||||||
@@ -3,14 +3,18 @@ package nl.requios.effortlessbuilding;
|
|||||||
import net.minecraft.client.gui.screens.MenuScreens;
|
import net.minecraft.client.gui.screens.MenuScreens;
|
||||||
import net.minecraftforge.eventbus.api.IEventBus;
|
import net.minecraftforge.eventbus.api.IEventBus;
|
||||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
||||||
|
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
|
||||||
import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagScreen;
|
import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagScreen;
|
||||||
import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagScreen;
|
import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagScreen;
|
||||||
import nl.requios.effortlessbuilding.gui.RandomizerBagScreen;
|
import nl.requios.effortlessbuilding.gui.RandomizerBagScreen;
|
||||||
import nl.requios.effortlessbuilding.systems.BlockChain;
|
import nl.requios.effortlessbuilding.systems.BuilderChain;
|
||||||
|
|
||||||
public class EffortlessBuildingClient {
|
public class EffortlessBuildingClient {
|
||||||
|
|
||||||
public static final BlockChain BLOCK_CHAIN = new BlockChain();
|
public static final BuilderChain BUILDER_CHAIN = new BuilderChain();
|
||||||
|
public static final BuildModes BUILD_MODES = new BuildModes();
|
||||||
|
public static final BuildModifiers BUILD_MODIFIERS = new BuildModifiers();
|
||||||
|
|
||||||
public static void onConstructorClient(IEventBus modEventBus, IEventBus forgeEventBus) {
|
public static void onConstructorClient(IEventBus modEventBus, IEventBus forgeEventBus) {
|
||||||
modEventBus.addListener(EffortlessBuildingClient::clientSetup);
|
modEventBus.addListener(EffortlessBuildingClient::clientSetup);
|
||||||
|
|||||||
@@ -4,36 +4,32 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
|
|
||||||
import java.util.Dictionary;
|
import java.util.List;
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public abstract class BaseBuildMode implements IBuildMode {
|
public abstract class BaseBuildMode implements IBuildMode {
|
||||||
//In singleplayer client and server variables are shared
|
|
||||||
//Split everything that needs separate values and may not be called twice in one click
|
protected int clicks;
|
||||||
protected Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
|
|
||||||
protected Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
|
|
||||||
protected Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
|
|
||||||
protected Dictionary<UUID, Direction> sideHitTable = new Hashtable<>();
|
|
||||||
protected Dictionary<UUID, Vec3> hitVecTable = new Hashtable<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(Player player) {
|
public void initialize() {
|
||||||
rightClickClientTable.put(player.getUUID(), 0);
|
clicks = 0;
|
||||||
rightClickServerTable.put(player.getUUID(), 0);
|
|
||||||
firstPosTable.put(player.getUUID(), BlockPos.ZERO);
|
|
||||||
sideHitTable.put(player.getUUID(), Direction.UP);
|
|
||||||
hitVecTable.put(player.getUUID(), Vec3.ZERO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public boolean onClick(List<BlockEntry> blocks) {
|
||||||
|
clicks++;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override @Deprecated
|
||||||
public Direction getSideHit(Player player) {
|
public Direction getSideHit(Player player) {
|
||||||
return sideHitTable.get(player.getUUID());
|
return Direction.UP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override @Deprecated
|
||||||
public Vec3 getHitVec(Player player) {
|
public Vec3 getHitVec(Player player) {
|
||||||
return hitVecTable.get(player.getUUID());
|
return new Vec3(0.5, 0.5, 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,179 +2,39 @@ package nl.requios.effortlessbuilding.buildmode;
|
|||||||
|
|
||||||
import com.mojang.math.Vector4f;
|
import com.mojang.math.Vector4f;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.level.ClipContext;
|
import net.minecraft.world.level.ClipContext;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import nl.requios.effortlessbuilding.buildmode.buildmodes.*;
|
import nl.requios.effortlessbuilding.buildmode.buildmodes.*;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
|
||||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||||
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
|
||||||
import nl.requios.effortlessbuilding.network.BlockBrokenMessage;
|
|
||||||
import nl.requios.effortlessbuilding.network.BlockPlacedMessage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Dictionary;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static nl.requios.effortlessbuilding.buildmode.ModeOptions.OptionEnum;
|
import static nl.requios.effortlessbuilding.buildmode.ModeOptions.OptionEnum;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
public class BuildModes {
|
public class BuildModes {
|
||||||
|
|
||||||
//Static variables are shared between client and server in singleplayer
|
public void findCoordinates(List<BlockEntry> blocks, Player player, BuildModeEnum buildMode) {
|
||||||
//We need them separate
|
buildMode.instance.findCoordinates(blocks);
|
||||||
public static Dictionary<Player, Boolean> currentlyBreakingClient = new Hashtable<>();
|
|
||||||
public static Dictionary<Player, Boolean> currentlyBreakingServer = new Hashtable<>();
|
|
||||||
|
|
||||||
//Uses a network message to get the previous raytraceresult from the player
|
|
||||||
//The server could keep track of all raytraceresults but this might lag with many players
|
|
||||||
//Raytraceresult is needed for sideHit and hitVec
|
|
||||||
public static void onBlockPlacedMessage(Player player, BlockPlacedMessage message) {
|
|
||||||
|
|
||||||
//Check if not in the middle of breaking
|
|
||||||
Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
|
|
||||||
if (currentlyBreaking.get(player) != null && currentlyBreaking.get(player)) {
|
|
||||||
//Cancel breaking
|
|
||||||
initializeMode(player);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
|
|
||||||
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
|
|
||||||
BuildModeEnum buildMode = modeSettings.getBuildMode();
|
|
||||||
|
|
||||||
BlockPos startPos = null;
|
|
||||||
|
|
||||||
if (message.isBlockHit() && message.getBlockPos() != null) {
|
|
||||||
startPos = message.getBlockPos();
|
|
||||||
|
|
||||||
//Offset in direction of sidehit if not quickreplace and not replaceable
|
|
||||||
boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable();
|
|
||||||
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos);
|
|
||||||
if (!modifierSettings.doQuickReplace() && !replaceable && !becomesDoubleSlab) {
|
|
||||||
startPos = startPos.relative(message.getSideHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get under tall grass and other replaceable blocks
|
|
||||||
if (modifierSettings.doQuickReplace() && replaceable) {
|
|
||||||
startPos = startPos.below();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if player reach does not exceed startpos
|
|
||||||
int maxReach = ReachHelper.getMaxReach(player);
|
|
||||||
if (buildMode != BuildModeEnum.DISABLED && player.blockPosition().distSqr(startPos) > maxReach * maxReach) {
|
|
||||||
EffortlessBuilding.log(player, "Placement exceeds your reach.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Even when no starting block is found, call buildmode instance
|
|
||||||
//We might want to place things in the air
|
|
||||||
List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, message.getSideHit(), message.getHitVec(), modifierSettings.doQuickReplace());
|
|
||||||
|
|
||||||
if (coordinates.isEmpty()) {
|
|
||||||
currentlyBreaking.put(player, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Limit number of blocks you can place
|
//Limit number of blocks you can place
|
||||||
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
|
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
|
||||||
if (coordinates.size() > limit) {
|
while (blocks.size() > limit) {
|
||||||
coordinates = coordinates.subList(0, limit);
|
blocks.remove(blocks.size()-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Direction sideHit = buildMode.instance.getSideHit(player);
|
public BuildModeEnum getBuildMode(Player player) {
|
||||||
if (sideHit == null) sideHit = message.getSideHit();
|
return ModeSettingsManager.getModeSettings(player).getBuildMode();
|
||||||
|
|
||||||
Vec3 hitVec = buildMode.instance.getHitVec(player);
|
|
||||||
if (hitVec == null) hitVec = message.getHitVec();
|
|
||||||
|
|
||||||
BuildModifiers.onBlockPlaced(player, coordinates, sideHit, hitVec, message.getPlaceStartPos());
|
|
||||||
|
|
||||||
//Only works when finishing a buildmode is equal to placing some blocks
|
|
||||||
//No intermediate blocks allowed
|
|
||||||
currentlyBreaking.remove(player);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Use a network message to break blocks in the distance using clientside mouse input
|
public void onCancel(Player player) {
|
||||||
public static void onBlockBrokenMessage(Player player, BlockBrokenMessage message) {
|
getBuildMode(player).instance.initialize();
|
||||||
BlockPos startPos = message.isBlockHit() ? message.getBlockPos() : null;
|
|
||||||
onBlockBroken(player, startPos, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void onBlockBroken(Player player, BlockPos startPos, boolean breakStartPos) {
|
|
||||||
|
|
||||||
//Check if not in the middle of placing
|
|
||||||
Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
|
|
||||||
if (currentlyBreaking.get(player) != null && !currentlyBreaking.get(player)) {
|
|
||||||
//Cancel placing
|
|
||||||
initializeMode(player);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ReachHelper.canBreakFar(player)) return;
|
|
||||||
|
|
||||||
//If first click
|
|
||||||
if (currentlyBreaking.get(player) == null) {
|
|
||||||
//If startpos is null, dont do anything
|
|
||||||
if (startPos == null) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
|
|
||||||
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
|
|
||||||
|
|
||||||
//Get coordinates
|
|
||||||
BuildModeEnum buildMode = modeSettings.getBuildMode();
|
|
||||||
List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, Direction.UP, Vec3.ZERO, true);
|
|
||||||
|
|
||||||
if (coordinates.isEmpty()) {
|
|
||||||
currentlyBreaking.put(player, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Let buildmodifiers break blocks
|
|
||||||
BuildModifiers.onBlockBroken(player, coordinates, breakStartPos);
|
|
||||||
|
|
||||||
//Only works when finishing a buildmode is equal to breaking some blocks
|
|
||||||
//No intermediate blocks allowed
|
|
||||||
currentlyBreaking.remove(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<BlockPos> findCoordinates(Player player, BlockPos startPos, boolean skipRaytrace) {
|
|
||||||
List<BlockPos> coordinates = new ArrayList<>();
|
|
||||||
|
|
||||||
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
|
|
||||||
coordinates.addAll(modeSettings.getBuildMode().instance.findCoordinates(player, startPos, skipRaytrace));
|
|
||||||
|
|
||||||
return coordinates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void initializeMode(Player player) {
|
|
||||||
//Resetting mode, so not placing or breaking
|
|
||||||
Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
|
|
||||||
currentlyBreaking.remove(player);
|
|
||||||
|
|
||||||
ModeSettingsManager.getModeSettings(player).getBuildMode().instance.initialize(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isCurrentlyPlacing(Player player) {
|
|
||||||
Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
|
|
||||||
return currentlyBreaking.get(player) != null && !currentlyBreaking.get(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isCurrentlyBreaking(Player player) {
|
|
||||||
Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
|
|
||||||
return currentlyBreaking.get(player) != null && currentlyBreaking.get(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Either placing or breaking
|
|
||||||
public static boolean isActive(Player player) {
|
|
||||||
Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
|
|
||||||
return currentlyBreaking.get(player) != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Find coordinates on a line bound by a plane
|
//Find coordinates on a line bound by a plane
|
||||||
|
|||||||
@@ -4,22 +4,32 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface IBuildMode {
|
public interface IBuildMode {
|
||||||
|
|
||||||
//Fired when a player selects a buildmode and when it needs to initializeMode
|
//Fired when a player selects a buildmode and when it needs to initializeMode
|
||||||
void initialize(Player player);
|
void initialize();
|
||||||
|
|
||||||
//Fired when a block would be placed
|
//Fired when a block would be placed
|
||||||
//Return a list of coordinates where you want to place blocks
|
//Return a list of coordinates where you want to place blocks
|
||||||
|
@Deprecated
|
||||||
List<BlockPos> onRightClick(Player player, BlockPos blockPos, Direction sideHit, Vec3 hitVec, boolean skipRaytrace);
|
List<BlockPos> onRightClick(Player player, BlockPos blockPos, Direction sideHit, Vec3 hitVec, boolean skipRaytrace);
|
||||||
|
|
||||||
|
//Returns if we should place blocks now
|
||||||
|
boolean onClick(List<BlockEntry> blocks);
|
||||||
|
|
||||||
//Fired continuously for visualization purposes
|
//Fired continuously for visualization purposes
|
||||||
|
@Deprecated
|
||||||
List<BlockPos> findCoordinates(Player player, BlockPos blockPos, boolean skipRaytrace);
|
List<BlockPos> findCoordinates(Player player, BlockPos blockPos, boolean skipRaytrace);
|
||||||
|
|
||||||
|
void findCoordinates(List<BlockEntry> blocks);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
Direction getSideHit(Player player);
|
Direction getSideHit(Player player);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
Vec3 getHitVec(Player player);
|
Vec3 getHitVec(Player player);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import net.minecraftforge.common.util.LazyOptional;
|
|||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.network.PacketDistributor;
|
import net.minecraftforge.network.PacketDistributor;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
import nl.requios.effortlessbuilding.capability.ModeCapabilityManager;
|
import nl.requios.effortlessbuilding.capability.ModeCapabilityManager;
|
||||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||||
import nl.requios.effortlessbuilding.network.ModeSettingsMessage;
|
import nl.requios.effortlessbuilding.network.ModeSettingsMessage;
|
||||||
@@ -47,7 +48,9 @@ public class ModeSettingsManager {
|
|||||||
modeCapability.ifPresent((capability) -> {
|
modeCapability.ifPresent((capability) -> {
|
||||||
capability.setModeData(modeSettings);
|
capability.setModeData(modeSettings);
|
||||||
|
|
||||||
BuildModes.initializeMode(player);
|
if (player.level.isClientSide) {
|
||||||
|
EffortlessBuildingClient.BUILDER_CHAIN.cancel();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!modeCapability.isPresent()) {
|
if (!modeCapability.isPresent()) {
|
||||||
@@ -56,11 +59,7 @@ public class ModeSettingsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String sanitize(ModeSettings modeSettings, Player player) {
|
public static String sanitize(ModeSettings modeSettings, Player player) {
|
||||||
int maxReach = ReachHelper.getMaxReach(player);
|
|
||||||
String error = "";
|
String error = "";
|
||||||
|
|
||||||
//TODO sanitize
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,49 +12,6 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode {
|
|||||||
protected Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
|
protected Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
|
||||||
|
|
||||||
//Finds height after floor has been chosen in buildmodes with 3 clicks
|
//Finds height after floor has been chosen in buildmodes with 3 clicks
|
||||||
public static BlockPos findHeight(Player player, BlockPos secondPos, boolean skipRaytrace) {
|
|
||||||
Vec3 look = BuildModes.getPlayerLookVec(player);
|
|
||||||
Vec3 start = new Vec3(player.getX(), player.getY() + player.getEyeHeight(), player.getZ());
|
|
||||||
|
|
||||||
List<HeightCriteria> criteriaList = new ArrayList<>(3);
|
|
||||||
|
|
||||||
//X
|
|
||||||
Vec3 xBound = BuildModes.findXBound(secondPos.getX(), start, look);
|
|
||||||
criteriaList.add(new HeightCriteria(xBound, secondPos, start));
|
|
||||||
|
|
||||||
//Z
|
|
||||||
Vec3 zBound = BuildModes.findZBound(secondPos.getZ(), start, look);
|
|
||||||
criteriaList.add(new HeightCriteria(zBound, secondPos, start));
|
|
||||||
|
|
||||||
//Remove invalid criteria
|
|
||||||
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
|
|
||||||
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
|
|
||||||
|
|
||||||
//If none are valid, return empty list of blocks
|
|
||||||
if (criteriaList.isEmpty()) return null;
|
|
||||||
|
|
||||||
//If only 1 is valid, choose that one
|
|
||||||
HeightCriteria selected = criteriaList.get(0);
|
|
||||||
|
|
||||||
//If multiple are valid, choose based on criteria
|
|
||||||
if (criteriaList.size() > 1) {
|
|
||||||
//Select the one that is closest (from wall position to its line counterpart)
|
|
||||||
for (int i = 1; i < criteriaList.size(); i++) {
|
|
||||||
HeightCriteria criteria = criteriaList.get(i);
|
|
||||||
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
|
|
||||||
//Both very close to line, choose closest to player
|
|
||||||
if (criteria.distToPlayerSq < selected.distToPlayerSq)
|
|
||||||
selected = criteria;
|
|
||||||
} else {
|
|
||||||
//Pick closest to line
|
|
||||||
if (criteria.distToLineSq < selected.distToLineSq)
|
|
||||||
selected = criteria;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new BlockPos(selected.lineBound);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(Player player) {
|
public void initialize(Player player) {
|
||||||
super.initialize(player);
|
super.initialize(player);
|
||||||
@@ -172,6 +129,49 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BlockPos findHeight(Player player, BlockPos secondPos, boolean skipRaytrace) {
|
||||||
|
Vec3 look = BuildModes.getPlayerLookVec(player);
|
||||||
|
Vec3 start = new Vec3(player.getX(), player.getY() + player.getEyeHeight(), player.getZ());
|
||||||
|
|
||||||
|
List<HeightCriteria> criteriaList = new ArrayList<>(3);
|
||||||
|
|
||||||
|
//X
|
||||||
|
Vec3 xBound = BuildModes.findXBound(secondPos.getX(), start, look);
|
||||||
|
criteriaList.add(new HeightCriteria(xBound, secondPos, start));
|
||||||
|
|
||||||
|
//Z
|
||||||
|
Vec3 zBound = BuildModes.findZBound(secondPos.getZ(), start, look);
|
||||||
|
criteriaList.add(new HeightCriteria(zBound, secondPos, start));
|
||||||
|
|
||||||
|
//Remove invalid criteria
|
||||||
|
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
|
||||||
|
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
|
||||||
|
|
||||||
|
//If none are valid, return empty list of blocks
|
||||||
|
if (criteriaList.isEmpty()) return null;
|
||||||
|
|
||||||
|
//If only 1 is valid, choose that one
|
||||||
|
HeightCriteria selected = criteriaList.get(0);
|
||||||
|
|
||||||
|
//If multiple are valid, choose based on criteria
|
||||||
|
if (criteriaList.size() > 1) {
|
||||||
|
//Select the one that is closest (from wall position to its line counterpart)
|
||||||
|
for (int i = 1; i < criteriaList.size(); i++) {
|
||||||
|
HeightCriteria criteria = criteriaList.get(i);
|
||||||
|
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
|
||||||
|
//Both very close to line, choose closest to player
|
||||||
|
if (criteria.distToPlayerSq < selected.distToPlayerSq)
|
||||||
|
selected = criteria;
|
||||||
|
} else {
|
||||||
|
//Pick closest to line
|
||||||
|
if (criteria.distToLineSq < selected.distToLineSq)
|
||||||
|
selected = criteria;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new BlockPos(selected.lineBound);
|
||||||
|
}
|
||||||
|
|
||||||
//Finds the place of the second block pos
|
//Finds the place of the second block pos
|
||||||
protected abstract BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace);
|
protected abstract BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -13,34 +14,28 @@ import java.util.UUID;
|
|||||||
|
|
||||||
public abstract class TwoClicksBuildMode extends BaseBuildMode {
|
public abstract class TwoClicksBuildMode extends BaseBuildMode {
|
||||||
|
|
||||||
|
protected BlockEntry firstBlockEntry;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BlockPos> onRightClick(Player player, BlockPos blockPos, Direction sideHit, Vec3 hitVec, boolean skipRaytrace) {
|
public boolean onClick(List<BlockEntry> blocks) {
|
||||||
List<BlockPos> list = new ArrayList<>();
|
super.onClick(blocks);
|
||||||
|
|
||||||
Dictionary<UUID, Integer> rightClickTable = player.level.isClientSide ? rightClickClientTable : rightClickServerTable;
|
if (clicks == 1) {
|
||||||
int rightClickNr = rightClickTable.get(player.getUUID());
|
//First click, remember starting position
|
||||||
rightClickNr++;
|
|
||||||
rightClickTable.put(player.getUUID(), rightClickNr);
|
|
||||||
|
|
||||||
if (rightClickNr == 1) {
|
|
||||||
//If clicking in air, reset and try again
|
//If clicking in air, reset and try again
|
||||||
if (blockPos == null) {
|
if (blocks.size() == 0) {
|
||||||
rightClickTable.put(player.getUUID(), 0);
|
clicks = 0;
|
||||||
return list;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//First click, remember starting position
|
firstBlockEntry = blocks.get(0);
|
||||||
firstPosTable.put(player.getUUID(), blockPos);
|
|
||||||
sideHitTable.put(player.getUUID(), sideHit);
|
|
||||||
hitVecTable.put(player.getUUID(), hitVec);
|
|
||||||
//Keep list empty, dont place any blocks yet
|
|
||||||
} else {
|
} else {
|
||||||
//Second click, place blocks
|
//Second click, place blocks
|
||||||
list = findCoordinates(player, blockPos, skipRaytrace);
|
clicks = 0;
|
||||||
rightClickTable.put(player.getUUID(), 0);
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import net.minecraft.world.phys.Vec3;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
//Used only for Undo
|
||||||
public class BlockSet {
|
public class BlockSet {
|
||||||
private final List<BlockPos> coordinates;
|
private final List<BlockPos> coordinates;
|
||||||
private final List<BlockState> previousBlockStates;
|
private final List<BlockState> previousBlockStates;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package nl.requios.effortlessbuilding.buildmodifier;
|
package nl.requios.effortlessbuilding.buildmodifier;
|
||||||
|
|
||||||
|
import net.minecraft.client.player.LocalPlayer;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
@@ -18,6 +19,7 @@ import nl.requios.effortlessbuilding.CommonConfig;
|
|||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||||
import nl.requios.effortlessbuilding.systems.DelayedBlockPlacer;
|
import nl.requios.effortlessbuilding.systems.DelayedBlockPlacer;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
||||||
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
|
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
|
||||||
import nl.requios.effortlessbuilding.render.BlockPreviews;
|
import nl.requios.effortlessbuilding.render.BlockPreviews;
|
||||||
@@ -28,6 +30,10 @@ import java.util.List;
|
|||||||
|
|
||||||
public class BuildModifiers {
|
public class BuildModifiers {
|
||||||
|
|
||||||
|
public void findCoordinates(List<BlockEntry> blocks, LocalPlayer player, ModifierSettingsManager.ModifierSettings modifierSettings) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//Called from BuildModes
|
//Called from BuildModes
|
||||||
public static void onBlockPlaced(Player player, List<BlockPos> startCoordinates, Direction sideHit, Vec3 hitVec, boolean placeStartPos) {
|
public static void onBlockPlaced(Player player, List<BlockPos> startCoordinates, Direction sideHit, Vec3 hitVec, boolean placeStartPos) {
|
||||||
Level world = player.level;
|
Level world = player.level;
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ import net.minecraftforge.event.entity.player.PlayerEvent;
|
|||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
|
import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
|
||||||
|
|
||||||
@Mod.EventBusSubscriber
|
@Mod.EventBusSubscriber
|
||||||
public class ModeCapabilityManager {
|
public class ModeCapabilityManager {
|
||||||
@@ -83,7 +84,7 @@ public class ModeCapabilityManager {
|
|||||||
public Tag serializeNBT() {
|
public Tag serializeNBT() {
|
||||||
CompoundTag compound = new CompoundTag();
|
CompoundTag compound = new CompoundTag();
|
||||||
ModeSettings modeSettings = instance.getModeData();
|
ModeSettings modeSettings = instance.getModeData();
|
||||||
if (modeSettings == null) modeSettings = new ModeSettings();
|
if (modeSettings == null) modeSettings = new ModeSettingsManager.ModeSettings();
|
||||||
|
|
||||||
//compound.putInteger("buildMode", modeSettings.getBuildMode().ordinal());
|
//compound.putInteger("buildMode", modeSettings.getBuildMode().ordinal());
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
|
|||||||
import nl.requios.effortlessbuilding.network.ModeActionMessage;
|
import nl.requios.effortlessbuilding.network.ModeActionMessage;
|
||||||
import nl.requios.effortlessbuilding.network.ModeSettingsMessage;
|
import nl.requios.effortlessbuilding.network.ModeSettingsMessage;
|
||||||
import nl.requios.effortlessbuilding.network.PacketHandler;
|
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||||
import nl.requios.effortlessbuilding.proxy.ClientProxy;
|
|
||||||
import org.apache.commons.lang3.text.WordUtils;
|
import org.apache.commons.lang3.text.WordUtils;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
package nl.requios.effortlessbuilding.network;
|
|
||||||
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.HitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
import net.minecraftforge.fml.LogicalSide;
|
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
|
||||||
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Sends a message to the server indicating that a player wants to break a block
|
|
||||||
*/
|
|
||||||
public class BlockBrokenMessage {
|
|
||||||
|
|
||||||
private final boolean blockHit;
|
|
||||||
private final BlockPos blockPos;
|
|
||||||
private final Direction sideHit;
|
|
||||||
private final Vec3 hitVec;
|
|
||||||
|
|
||||||
public BlockBrokenMessage() {
|
|
||||||
this.blockHit = false;
|
|
||||||
this.blockPos = BlockPos.ZERO;
|
|
||||||
this.sideHit = Direction.UP;
|
|
||||||
this.hitVec = new Vec3(0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockBrokenMessage(BlockHitResult result) {
|
|
||||||
this.blockHit = result.getType() == HitResult.Type.BLOCK;
|
|
||||||
this.blockPos = result.getBlockPos();
|
|
||||||
this.sideHit = result.getDirection();
|
|
||||||
this.hitVec = result.getLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockBrokenMessage(boolean blockHit, BlockPos blockPos, Direction sideHit, Vec3 hitVec) {
|
|
||||||
this.blockHit = blockHit;
|
|
||||||
this.blockPos = blockPos;
|
|
||||||
this.sideHit = sideHit;
|
|
||||||
this.hitVec = hitVec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void encode(BlockBrokenMessage message, FriendlyByteBuf buf) {
|
|
||||||
buf.writeBoolean(message.blockHit);
|
|
||||||
buf.writeInt(message.blockPos.getX());
|
|
||||||
buf.writeInt(message.blockPos.getY());
|
|
||||||
buf.writeInt(message.blockPos.getZ());
|
|
||||||
buf.writeInt(message.sideHit.get3DDataValue());
|
|
||||||
buf.writeDouble(message.hitVec.x);
|
|
||||||
buf.writeDouble(message.hitVec.y);
|
|
||||||
buf.writeDouble(message.hitVec.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlockBrokenMessage decode(FriendlyByteBuf buf) {
|
|
||||||
boolean blockHit = buf.readBoolean();
|
|
||||||
BlockPos blockPos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
|
|
||||||
Direction sideHit = Direction.from3DDataValue(buf.readInt());
|
|
||||||
Vec3 hitVec = new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble());
|
|
||||||
return new BlockBrokenMessage(blockHit, blockPos, sideHit, hitVec);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBlockHit() {
|
|
||||||
return blockHit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockPos getBlockPos() {
|
|
||||||
return blockPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Direction getSideHit() {
|
|
||||||
return sideHit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 getHitVec() {
|
|
||||||
return hitVec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Handler {
|
|
||||||
public static void handle(BlockBrokenMessage message, Supplier<NetworkEvent.Context> ctx) {
|
|
||||||
ctx.get().enqueueWork(() -> {
|
|
||||||
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.SERVER) {
|
|
||||||
//Received serverside
|
|
||||||
BuildModes.onBlockBrokenMessage(ctx.get().getSender(), message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ctx.get().setPacketHandled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
package nl.requios.effortlessbuilding.network;
|
|
||||||
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.HitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import net.minecraftforge.fml.DistExecutor;
|
|
||||||
import net.minecraftforge.fml.LogicalSide;
|
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
|
||||||
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
|
||||||
import nl.requios.effortlessbuilding.render.BlockPreviews;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Sends a message to the server indicating that a player wants to place a block.
|
|
||||||
* Received clientside: server has placed blocks and its letting the client know.
|
|
||||||
*/
|
|
||||||
public class BlockPlacedMessage {
|
|
||||||
|
|
||||||
private final boolean blockHit;
|
|
||||||
private final BlockPos blockPos;
|
|
||||||
private final Direction sideHit;
|
|
||||||
private final Vec3 hitVec;
|
|
||||||
private final boolean placeStartPos; //prevent double placing in normal mode
|
|
||||||
|
|
||||||
public BlockPlacedMessage() {
|
|
||||||
this.blockHit = false;
|
|
||||||
this.blockPos = BlockPos.ZERO;
|
|
||||||
this.sideHit = Direction.UP;
|
|
||||||
this.hitVec = new Vec3(0, 0, 0);
|
|
||||||
this.placeStartPos = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockPlacedMessage(BlockHitResult result, boolean placeStartPos) {
|
|
||||||
this.blockHit = result.getType() == HitResult.Type.BLOCK;
|
|
||||||
this.blockPos = result.getBlockPos();
|
|
||||||
this.sideHit = result.getDirection();
|
|
||||||
this.hitVec = result.getLocation();
|
|
||||||
this.placeStartPos = placeStartPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockPlacedMessage(boolean blockHit, BlockPos blockPos, Direction sideHit, Vec3 hitVec, boolean placeStartPos) {
|
|
||||||
this.blockHit = blockHit;
|
|
||||||
this.blockPos = blockPos;
|
|
||||||
this.sideHit = sideHit;
|
|
||||||
this.hitVec = hitVec;
|
|
||||||
this.placeStartPos = placeStartPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void encode(BlockPlacedMessage message, FriendlyByteBuf buf) {
|
|
||||||
buf.writeBoolean(message.blockHit);
|
|
||||||
buf.writeInt(message.blockPos.getX());
|
|
||||||
buf.writeInt(message.blockPos.getY());
|
|
||||||
buf.writeInt(message.blockPos.getZ());
|
|
||||||
buf.writeInt(message.sideHit.get3DDataValue());
|
|
||||||
buf.writeDouble(message.hitVec.x);
|
|
||||||
buf.writeDouble(message.hitVec.y);
|
|
||||||
buf.writeDouble(message.hitVec.z);
|
|
||||||
buf.writeBoolean(message.placeStartPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlockPlacedMessage decode(FriendlyByteBuf buf) {
|
|
||||||
boolean blockHit = buf.readBoolean();
|
|
||||||
BlockPos blockPos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
|
|
||||||
Direction sideHit = Direction.from3DDataValue(buf.readInt());
|
|
||||||
Vec3 hitVec = new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble());
|
|
||||||
boolean placeStartPos = buf.readBoolean();
|
|
||||||
return new BlockPlacedMessage(blockHit, blockPos, sideHit, hitVec, placeStartPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBlockHit() {
|
|
||||||
return blockHit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockPos getBlockPos() {
|
|
||||||
return blockPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Direction getSideHit() {
|
|
||||||
return sideHit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 getHitVec() {
|
|
||||||
return hitVec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getPlaceStartPos() {
|
|
||||||
return placeStartPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Handler {
|
|
||||||
public static void handle(BlockPlacedMessage message, Supplier<NetworkEvent.Context> ctx) {
|
|
||||||
ctx.get().enqueueWork(() -> {
|
|
||||||
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) {
|
|
||||||
//Received clientside
|
|
||||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientHandler.handle(message, ctx));
|
|
||||||
} else {
|
|
||||||
//Received serverside
|
|
||||||
BuildModes.onBlockPlacedMessage(ctx.get().getSender(), message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ctx.get().setPacketHandled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static class ClientHandler {
|
|
||||||
public static void handle(BlockPlacedMessage message, Supplier<NetworkEvent.Context> ctx) {
|
|
||||||
//Nod RenderHandler to do the dissolve shader effect
|
|
||||||
BlockPreviews.onBlocksPlaced();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package nl.requios.effortlessbuilding.network;
|
|
||||||
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
|
||||||
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a message to the server indicating that a buildmode needs to be canceled for a player
|
|
||||||
*/
|
|
||||||
public class CancelModeMessage {
|
|
||||||
|
|
||||||
public static void encode(CancelModeMessage message, FriendlyByteBuf buf) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CancelModeMessage decode(FriendlyByteBuf buf) {
|
|
||||||
return new CancelModeMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Handler {
|
|
||||||
public static void handle(CancelModeMessage message, Supplier<NetworkEvent.Context> ctx) {
|
|
||||||
ctx.get().enqueueWork(() -> {
|
|
||||||
Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
|
|
||||||
|
|
||||||
BuildModes.initializeMode(player);
|
|
||||||
});
|
|
||||||
ctx.get().setPacketHandled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,10 +6,11 @@ import net.minecraftforge.network.NetworkEvent;
|
|||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
||||||
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
|
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
|
||||||
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shares mode settings (see ModeSettingsManager) between server and client
|
* Shares mode settings (see ModeSettingsManager) between server and client
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package nl.requios.effortlessbuilding.network;
|
||||||
|
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
|
import net.minecraftforge.fml.LogicalSide;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Sends a message to the client indicating that a block has been placed.
|
||||||
|
* Necessary because Forge's onBlockPlaced event is only called on the server.
|
||||||
|
*/
|
||||||
|
public class OnBlockPlacedMessage {
|
||||||
|
|
||||||
|
public OnBlockPlacedMessage() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void encode(OnBlockPlacedMessage message, FriendlyByteBuf buf) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OnBlockPlacedMessage decode(FriendlyByteBuf buf) {
|
||||||
|
return new OnBlockPlacedMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Handler {
|
||||||
|
public static void handle(OnBlockPlacedMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
|
ctx.get().enqueueWork(() -> {
|
||||||
|
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) {
|
||||||
|
//Received clientside
|
||||||
|
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientHandler.handle(message, ctx));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ctx.get().setPacketHandled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static class ClientHandler {
|
||||||
|
public static void handle(OnBlockPlacedMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
|
|
||||||
|
EffortlessBuildingClient.BUILDER_CHAIN.onRightClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,12 +20,10 @@ public class PacketHandler {
|
|||||||
INSTANCE.registerMessage(id++, ModifierSettingsMessage.class, ModifierSettingsMessage::encode, ModifierSettingsMessage::decode, ModifierSettingsMessage.Handler::handle);
|
INSTANCE.registerMessage(id++, ModifierSettingsMessage.class, ModifierSettingsMessage::encode, ModifierSettingsMessage::decode, ModifierSettingsMessage.Handler::handle);
|
||||||
INSTANCE.registerMessage(id++, ModeSettingsMessage.class, ModeSettingsMessage::encode, ModeSettingsMessage::decode, ModeSettingsMessage.Handler::handle);
|
INSTANCE.registerMessage(id++, ModeSettingsMessage.class, ModeSettingsMessage::encode, ModeSettingsMessage::decode, ModeSettingsMessage.Handler::handle);
|
||||||
INSTANCE.registerMessage(id++, ModeActionMessage.class, ModeActionMessage::encode, ModeActionMessage::decode, ModeActionMessage.Handler::handle);
|
INSTANCE.registerMessage(id++, ModeActionMessage.class, ModeActionMessage::encode, ModeActionMessage::decode, ModeActionMessage.Handler::handle);
|
||||||
INSTANCE.registerMessage(id++, BlockPlacedMessage.class, BlockPlacedMessage::encode, BlockPlacedMessage::decode, BlockPlacedMessage.Handler::handle);
|
INSTANCE.registerMessage(id++, OnBlockPlacedMessage.class, OnBlockPlacedMessage::encode, OnBlockPlacedMessage::decode, OnBlockPlacedMessage.Handler::handle);
|
||||||
INSTANCE.registerMessage(id++, BlockBrokenMessage.class, BlockBrokenMessage::encode, BlockBrokenMessage::decode, BlockBrokenMessage.Handler::handle);
|
|
||||||
INSTANCE.registerMessage(id++, CancelModeMessage.class, CancelModeMessage::encode, CancelModeMessage::decode, CancelModeMessage.Handler::handle);
|
|
||||||
INSTANCE.registerMessage(id++, RequestLookAtMessage.class, RequestLookAtMessage::encode, RequestLookAtMessage::decode, RequestLookAtMessage.Handler::handle);
|
|
||||||
INSTANCE.registerMessage(id++, AddUndoMessage.class, AddUndoMessage::encode, AddUndoMessage::decode, AddUndoMessage.Handler::handle);
|
INSTANCE.registerMessage(id++, AddUndoMessage.class, AddUndoMessage::encode, AddUndoMessage::decode, AddUndoMessage.Handler::handle);
|
||||||
INSTANCE.registerMessage(id++, ClearUndoMessage.class, ClearUndoMessage::encode, ClearUndoMessage::decode, ClearUndoMessage.Handler::handle);
|
INSTANCE.registerMessage(id++, ClearUndoMessage.class, ClearUndoMessage::encode, ClearUndoMessage::decode, ClearUndoMessage.Handler::handle);
|
||||||
|
INSTANCE.registerMessage(id++, ServerPlaceBlocksMessage.class, ServerPlaceBlocksMessage::encode, ServerPlaceBlocksMessage::decode, ServerPlaceBlocksMessage.Handler::handle);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
package nl.requios.effortlessbuilding.network;
|
|
||||||
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.HitResult;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import net.minecraftforge.fml.DistExecutor;
|
|
||||||
import net.minecraftforge.fml.LogicalSide;
|
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
|
||||||
import nl.requios.effortlessbuilding.ClientEvents;
|
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Sends a message to the client asking for its lookat (objectmouseover) data.
|
|
||||||
* This is then sent back with a BlockPlacedMessage.
|
|
||||||
*/
|
|
||||||
public class RequestLookAtMessage {
|
|
||||||
private final boolean placeStartPos;
|
|
||||||
|
|
||||||
public RequestLookAtMessage() {
|
|
||||||
placeStartPos = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RequestLookAtMessage(boolean placeStartPos) {
|
|
||||||
this.placeStartPos = placeStartPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void encode(RequestLookAtMessage message, FriendlyByteBuf buf) {
|
|
||||||
buf.writeBoolean(message.placeStartPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RequestLookAtMessage decode(FriendlyByteBuf buf) {
|
|
||||||
boolean placeStartPos = buf.readBoolean();
|
|
||||||
return new RequestLookAtMessage(placeStartPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getPlaceStartPos() {
|
|
||||||
return placeStartPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Handler {
|
|
||||||
public static void handle(RequestLookAtMessage message, Supplier<NetworkEvent.Context> ctx) {
|
|
||||||
ctx.get().enqueueWork(() -> {
|
|
||||||
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) {
|
|
||||||
//Received clientside
|
|
||||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientHandler.handle(message, ctx));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ctx.get().setPacketHandled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static class ClientHandler {
|
|
||||||
public static void handle(RequestLookAtMessage message, Supplier<NetworkEvent.Context> ctx) {
|
|
||||||
//Send back your info
|
|
||||||
Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
|
|
||||||
|
|
||||||
//Prevent double placing in normal mode with placeStartPos false
|
|
||||||
//Unless QuickReplace is on, then we do need to place start pos.
|
|
||||||
if (ClientEvents.previousLookAt.getType() == HitResult.Type.BLOCK) {
|
|
||||||
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage((BlockHitResult) ClientEvents.previousLookAt, message.getPlaceStartPos()));
|
|
||||||
} else {
|
|
||||||
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package nl.requios.effortlessbuilding.network;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.NbtUtils;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message to the server to place multiple blocks
|
||||||
|
*/
|
||||||
|
public class ServerPlaceBlocksMessage {
|
||||||
|
|
||||||
|
private List<BlockEntry> blocks;
|
||||||
|
|
||||||
|
public ServerPlaceBlocksMessage() {}
|
||||||
|
|
||||||
|
public ServerPlaceBlocksMessage(List<BlockEntry> blocks) {
|
||||||
|
this.blocks = blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void encode(ServerPlaceBlocksMessage message, FriendlyByteBuf buf) {
|
||||||
|
buf.writeCollection(message.blocks, BlockEntry::encode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerPlaceBlocksMessage decode(FriendlyByteBuf buf) {
|
||||||
|
ServerPlaceBlocksMessage message = new ServerPlaceBlocksMessage();
|
||||||
|
message.blocks = buf.readList(BlockEntry::decode);
|
||||||
|
return new ServerPlaceBlocksMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Handler {
|
||||||
|
public static void handle(ServerPlaceBlocksMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
|
ctx.get().enqueueWork(() -> {
|
||||||
|
Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
|
||||||
|
|
||||||
|
EffortlessBuilding.SERVER_BLOCK_PLACER.placeBlocks(player, message.blocks);
|
||||||
|
});
|
||||||
|
ctx.get().setPacketHandled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,8 +21,6 @@ import nl.requios.effortlessbuilding.CommonConfig;
|
|||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
import nl.requios.effortlessbuilding.buildmode.BuildModes;
|
||||||
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
|
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
|
||||||
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
|
|
||||||
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
|
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
|
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
|
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
|
||||||
@@ -38,6 +36,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public class BlockPreviews {
|
public class BlockPreviews {
|
||||||
private static final List<PlacedData> placedDataList = new ArrayList<>();
|
private static final List<PlacedData> placedDataList = new ArrayList<>();
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package nl.requios.effortlessbuilding.systems;
|
|
||||||
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
|
|
||||||
// Receives block placed events, then finds additional blocks we want to place through various systems,
|
|
||||||
// and then sends them to the server to be placed
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public class BlockChain {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
package nl.requios.effortlessbuilding.systems;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.BlockItem;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import nl.requios.effortlessbuilding.ClientEvents;
|
||||||
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
|
||||||
|
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
||||||
|
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||||
|
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||||
|
import nl.requios.effortlessbuilding.network.ServerPlaceBlocksMessage;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
// Receives block placed events, then finds additional blocks we want to place through various systems,
|
||||||
|
// and then sends them to the server to be placed
|
||||||
|
// Uses chain of responsibility pattern
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class BuilderChain {
|
||||||
|
|
||||||
|
private final List<BlockEntry> blocks = new ArrayList<>();
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
IDLE,
|
||||||
|
PLACING,
|
||||||
|
BREAKING
|
||||||
|
}
|
||||||
|
|
||||||
|
private State state = State.IDLE;
|
||||||
|
|
||||||
|
|
||||||
|
public void onRightClick() {
|
||||||
|
if (state == State.BREAKING) {
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == State.IDLE) {
|
||||||
|
state = State.PLACING;
|
||||||
|
}
|
||||||
|
|
||||||
|
var player = Minecraft.getInstance().player;
|
||||||
|
var buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
|
||||||
|
|
||||||
|
//Find out if we should place blocks now
|
||||||
|
if (buildMode.instance.onClick()) {
|
||||||
|
state = State.IDLE;
|
||||||
|
PacketHandler.INSTANCE.sendToServer(new ServerPlaceBlocksMessage(blocks));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onLeftClick() {
|
||||||
|
var player = Minecraft.getInstance().player;
|
||||||
|
|
||||||
|
if (state == State.PLACING) {
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReachHelper.canBreakFar(player)) return;
|
||||||
|
|
||||||
|
if (state == State.IDLE){
|
||||||
|
state = State.BREAKING;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
|
||||||
|
|
||||||
|
//Find out if we should break blocks now
|
||||||
|
if (buildMode.instance.onClick()) {
|
||||||
|
state = State.IDLE;
|
||||||
|
PacketHandler.INSTANCE.sendToServer(new ServerPlaceBlocksMessage(blocks));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onTick() {
|
||||||
|
blocks.clear();
|
||||||
|
|
||||||
|
var mc = Minecraft.getInstance();
|
||||||
|
var player = mc.player;
|
||||||
|
var level = mc.level;
|
||||||
|
|
||||||
|
//Check if we have a BlockItem in hand
|
||||||
|
var itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
|
||||||
|
boolean blockInHand = CompatHelper.isItemBlockProxy(itemStack);
|
||||||
|
|
||||||
|
// if (!blockInHand && state == State.PLACING) {
|
||||||
|
// state = State.IDLE;
|
||||||
|
// }
|
||||||
|
|
||||||
|
var modifierSettings = ModifierSettingsManager.getModifierSettings(player);
|
||||||
|
var buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
|
||||||
|
|
||||||
|
|
||||||
|
BlockHitResult lookingAt = ClientEvents.getLookingAt(player);
|
||||||
|
BlockEntry startEntry = findStartPosition(player, lookingAt, modifierSettings.doQuickReplace());
|
||||||
|
if (startEntry != null) {
|
||||||
|
blocks.add(startEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
EffortlessBuildingClient.BUILD_MODES.findCoordinates(blocks, player, buildMode);
|
||||||
|
EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player, modifierSettings);
|
||||||
|
|
||||||
|
if (state == State.PLACING) {
|
||||||
|
//TODO find block states
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel() {
|
||||||
|
var player = Minecraft.getInstance().player;
|
||||||
|
|
||||||
|
state = State.IDLE;
|
||||||
|
EffortlessBuildingClient.BUILD_MODES.onCancel(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockEntry findStartPosition(Player player, BlockHitResult lookingAt, boolean doingQuickReplace) {
|
||||||
|
if (lookingAt == null || lookingAt.getType() == HitResult.Type.MISS) return null;
|
||||||
|
|
||||||
|
var startPos = lookingAt.getBlockPos();
|
||||||
|
|
||||||
|
//Check if out of reach
|
||||||
|
int maxReach = ReachHelper.getMaxReach(player);
|
||||||
|
if (player.blockPosition().distSqr(startPos) > maxReach * maxReach) return null;
|
||||||
|
|
||||||
|
//Offset in direction of sidehit if not quickreplace and not replaceable
|
||||||
|
boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable();
|
||||||
|
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos);
|
||||||
|
if (!doingQuickReplace && !replaceable && !becomesDoubleSlab) {
|
||||||
|
startPos = startPos.relative(lookingAt.getDirection());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get under tall grass and other replaceable blocks
|
||||||
|
if (doingQuickReplace && replaceable) {
|
||||||
|
startPos = startPos.below();
|
||||||
|
}
|
||||||
|
|
||||||
|
var blockEntry = new BlockEntry(startPos);
|
||||||
|
|
||||||
|
//Place upside-down stairs if we aim high at block
|
||||||
|
var hitVec = lookingAt.getLocation();
|
||||||
|
//Format hitvec to 0.x
|
||||||
|
hitVec = new Vec3(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), Math.abs(hitVec.z - ((int) hitVec.z)));
|
||||||
|
if (hitVec.y > 0.5) {
|
||||||
|
blockEntry.mirrorY = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playPlacingSoundIfFurtherThanNormal(Player player, Vec3 location, BlockItem blockItem) {
|
||||||
|
|
||||||
|
if ((location.subtract(player.getEyePosition(1f))).lengthSqr() > 25f) {
|
||||||
|
BlockPos blockPos = new BlockPos(location);
|
||||||
|
BlockState state = blockItem.getBlock().defaultBlockState();
|
||||||
|
SoundType soundType = state.getBlock().getSoundType(state, player.level, blockPos, player);
|
||||||
|
player.level.playSound(player, player.blockPosition(), soundType.getPlaceSound(), SoundSource.BLOCKS,
|
||||||
|
0.4f, soundType.getPitch());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playBreakingSoundIfFurtherThanNormal(Player player, Vec3 location) {
|
||||||
|
|
||||||
|
if ((location.subtract(player.getEyePosition(1f))).lengthSqr() > 25f) {
|
||||||
|
BlockPos blockPos = new BlockPos(location);
|
||||||
|
BlockState state = player.level.getBlockState(blockPos);
|
||||||
|
SoundType soundtype = state.getBlock().getSoundType(state, player.level, blockPos, player);
|
||||||
|
player.level.playSound(player, player.blockPosition(), soundtype.getBreakSound(), SoundSource.BLOCKS,
|
||||||
|
0.4f, soundtype.getPitch());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swingHand(Player player, InteractionHand hand) {
|
||||||
|
player.swing(hand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,53 @@
|
|||||||
package nl.requios.effortlessbuilding.systems;
|
package nl.requios.effortlessbuilding.systems;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
// Receives block placement requests from the client and places them
|
// Receives block placement requests from the client and places them
|
||||||
public class ServerBlockPlacer {
|
public class ServerBlockPlacer {
|
||||||
|
|
||||||
|
public void placeBlocks(Player player, List<BlockEntry> blocks) {
|
||||||
|
for (BlockEntry block : blocks) {
|
||||||
|
placeBlock(player, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void placeBlock(Player player, BlockEntry block) {
|
||||||
|
Level world = player.level;
|
||||||
|
if (!world.isLoaded(block.blockPos)) return;
|
||||||
|
|
||||||
|
if (block.meansBreakBlock()) {
|
||||||
|
breakBlock(player, block.blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = world.setBlock(block.blockPos, block.blockState, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void breakBlock(Player player, BlockPos pos) {
|
||||||
|
ServerLevel world = (ServerLevel) player.level;
|
||||||
|
if (!world.isLoaded(pos) || world.isEmptyBlock(pos)) return;
|
||||||
|
|
||||||
|
//Held tool
|
||||||
|
|
||||||
|
if (!player.getAbilities().instabuild) {
|
||||||
|
|
||||||
|
//Drops
|
||||||
|
BlockState blockState = world.getBlockState(pos);
|
||||||
|
List<ItemStack> drops = Block.getDrops(blockState, world, pos, world.getBlockEntity(pos), player, player.getMainHandItem());
|
||||||
|
for (ItemStack drop : drops) {
|
||||||
|
player.addItem(drop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
world.removeBlock(pos, false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package nl.requios.effortlessbuilding.utilities;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.NbtUtils;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
|
public class BlockEntry {
|
||||||
|
public final BlockPos blockPos;
|
||||||
|
public boolean mirrorX;
|
||||||
|
public boolean mirrorY;
|
||||||
|
public boolean mirrorZ;
|
||||||
|
public BlockState blockState;
|
||||||
|
|
||||||
|
public BlockEntry(BlockPos blockPos) {
|
||||||
|
this.blockPos = blockPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BitSet getMirrorBitSet() {
|
||||||
|
BitSet bitSet = new BitSet(3);
|
||||||
|
bitSet.set(0, mirrorX);
|
||||||
|
bitSet.set(1, mirrorY);
|
||||||
|
bitSet.set(2, mirrorZ);
|
||||||
|
return bitSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMirrorBitSet(BitSet bitSet) {
|
||||||
|
mirrorX = bitSet.get(0);
|
||||||
|
mirrorY = bitSet.get(1);
|
||||||
|
mirrorZ = bitSet.get(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean meansBreakBlock() {
|
||||||
|
return blockState == null || blockState.isAir();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void encode(FriendlyByteBuf buf, BlockEntry block) {
|
||||||
|
buf.writeBlockPos(block.blockPos);
|
||||||
|
buf.writeBitSet(block.getMirrorBitSet());
|
||||||
|
buf.writeNbt(NbtUtils.writeBlockState(block.blockState));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockEntry decode(FriendlyByteBuf buf) {
|
||||||
|
BlockEntry block = new BlockEntry(buf.readBlockPos());
|
||||||
|
block.setMirrorBitSet(buf.readBitSet());
|
||||||
|
block.blockState = NbtUtils.readBlockState(buf.readNbt());
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user