Added buttons in radial menu for replace modes. Implemented/fixed replace modes.
Made ModeOptions clientside and UndoRedo serverside. New config option: only show previews when building, default true. Overhauled drawOutlinesIfNoBlockInHand, now drawOutlineAtBreakPosition. Fixed not being able to break blocks.
This commit is contained in:
@@ -10,7 +10,7 @@ public class ClientConfig {
|
||||
|
||||
public static class Visuals {
|
||||
public final ForgeConfigSpec.ConfigValue<Boolean> showBlockPreviews;
|
||||
public final ForgeConfigSpec.ConfigValue<Boolean> alwaysShowBlockPreview;
|
||||
public final ForgeConfigSpec.ConfigValue<Boolean> onlyShowBlockPreviewsWhenBuilding;
|
||||
public final ForgeConfigSpec.ConfigValue<Integer> maxBlockPreviews;
|
||||
|
||||
public Visuals(ForgeConfigSpec.Builder builder) {
|
||||
@@ -18,16 +18,16 @@ public class ClientConfig {
|
||||
|
||||
showBlockPreviews = builder
|
||||
.comment("Show previews of the blocks while placing them")
|
||||
.define("useShaders", true);
|
||||
.define("showBlockPreviews", true);
|
||||
|
||||
alwaysShowBlockPreview = builder
|
||||
.comment("Show a block preview if you have a block in hand even in the 'Disabled' build mode")
|
||||
.define("alwaysShowBlockPreview", false);
|
||||
onlyShowBlockPreviewsWhenBuilding = builder
|
||||
.comment("Show block previews only when actively using a build mode")
|
||||
.define("onlyShowBlockPreviewsWhenBuilding", true);
|
||||
|
||||
maxBlockPreviews = builder
|
||||
.comment("Don't show block previews when placing more than this many blocks. " +
|
||||
"The outline will always be rendered.")
|
||||
.define("shaderTreshold", 500);
|
||||
.define("maxBlockPreviews", 500);
|
||||
|
||||
|
||||
builder.pop();
|
||||
|
||||
@@ -52,15 +52,14 @@ public class ClientEvents {
|
||||
EffortlessBuilding.log("Registering KeyMappings!");
|
||||
|
||||
// register key bindings
|
||||
keyBindings = new KeyMapping[6];
|
||||
keyBindings = new KeyMapping[5];
|
||||
|
||||
// instantiate the key bindings
|
||||
keyBindings[0] = new KeyMapping("key.effortlessbuilding.hud.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_KP_ADD, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[1] = new KeyMapping("key.effortlessbuilding.replace.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_KP_SUBTRACT, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[2] = new KeyMapping("key.effortlessbuilding.mode.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_ALT, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[3] = new KeyMapping("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Z, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[4] = new KeyMapping("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Y, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[5] = new KeyMapping("key.effortlessbuilding.altplacement.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_CONTROL, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[0] = new KeyMapping("key.effortlessbuilding.mode.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_ALT, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[1] = new KeyMapping("key.effortlessbuilding.hud.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_KP_ADD, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[2] = new KeyMapping("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Z, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[3] = new KeyMapping("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Y, 0), "key.effortlessbuilding.category");
|
||||
keyBindings[4] = new KeyMapping("key.effortlessbuilding.altplacement.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_CONTROL, 0), "key.effortlessbuilding.category");
|
||||
|
||||
for (KeyMapping keyBinding : keyBindings) {
|
||||
event.register(keyBinding);
|
||||
@@ -148,19 +147,8 @@ public class ClientEvents {
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
//Remember to send packet to server if necessary
|
||||
//Show Modifier Settings GUI
|
||||
if (keyBindings[0].consumeClick()) {
|
||||
openModifierSettings();
|
||||
}
|
||||
|
||||
//QuickReplace toggle
|
||||
if (keyBindings[1].consumeClick()) {
|
||||
EffortlessBuildingClient.BUILD_SETTINGS.toggleQuickReplace();
|
||||
}
|
||||
|
||||
//Radial menu
|
||||
if (keyBindings[2].isDown()) {
|
||||
if (keyBindings[0].isDown()) {
|
||||
if (ReachHelper.getMaxReach(player) > 0) {
|
||||
if (!RadialMenu.instance.isVisible()) {
|
||||
Minecraft.getInstance().setScreen(RadialMenu.instance);
|
||||
@@ -170,22 +158,23 @@ public class ClientEvents {
|
||||
}
|
||||
}
|
||||
|
||||
//Show Modifier Settings GUI
|
||||
if (keyBindings[1].consumeClick()) {
|
||||
openModifierSettings();
|
||||
}
|
||||
|
||||
//Undo (Ctrl+Z)
|
||||
if (keyBindings[3].consumeClick()) {
|
||||
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.UNDO;
|
||||
ModeOptions.performAction(player, action);
|
||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
|
||||
if (keyBindings[2].consumeClick()) {
|
||||
ModeOptions.performAction(player, ModeOptions.ActionEnum.UNDO);
|
||||
}
|
||||
|
||||
//Redo (Ctrl+Y)
|
||||
if (keyBindings[4].consumeClick()) {
|
||||
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.REDO;
|
||||
ModeOptions.performAction(player, action);
|
||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
|
||||
if (keyBindings[3].consumeClick()) {
|
||||
ModeOptions.performAction(player, ModeOptions.ActionEnum.REDO);
|
||||
}
|
||||
|
||||
//Change placement mode
|
||||
if (keyBindings[5].consumeClick()) {
|
||||
if (keyBindings[4].isDown()) {
|
||||
//Toggle between first two actions of the first option of the current build mode
|
||||
BuildModeEnum currentBuildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
||||
if (currentBuildMode.options.length > 0) {
|
||||
@@ -193,10 +182,8 @@ public class ClientEvents {
|
||||
if (option.actions.length >= 2) {
|
||||
if (ModeOptions.getOptionSetting(option) == option.actions[0]) {
|
||||
ModeOptions.performAction(player, option.actions[1]);
|
||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(option.actions[1]));
|
||||
} else {
|
||||
ModeOptions.performAction(player, option.actions[0]);
|
||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(option.actions[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class CommonConfig {
|
||||
undoStackSize = builder
|
||||
.comment("How many placements are remembered for the undo functionality.")
|
||||
.worldRestart()
|
||||
.define("undoStackSize", 10);
|
||||
.define("undoStackSize", 50);
|
||||
|
||||
builder.pop();
|
||||
}
|
||||
|
||||
@@ -18,13 +18,11 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
|
||||
import nl.requios.effortlessbuilding.systems.UndoRedo;
|
||||
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
|
||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||
import nl.requios.effortlessbuilding.systems.ServerBuildState;
|
||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||
import nl.requios.effortlessbuilding.network.AddUndoMessage;
|
||||
import nl.requios.effortlessbuilding.network.ClearUndoMessage;
|
||||
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||
|
||||
@EventBusSubscriber
|
||||
@@ -72,12 +70,6 @@ public class CommonEvents {
|
||||
if (isPlayerHoldingBlock(player)) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
|
||||
} else {
|
||||
//NORMAL mode, let vanilla handle block placing
|
||||
|
||||
//TODO move UndoRedo to serverside only
|
||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,16 +85,6 @@ public class CommonEvents {
|
||||
|
||||
if (!ServerBuildState.isLikeVanilla(player) && ReachHelper.canBreakFar(player)) {
|
||||
event.setCanceled(true);
|
||||
} else {
|
||||
//NORMAL mode, let vanilla handle block breaking
|
||||
|
||||
//Add to undo stack in client
|
||||
//TODO move UndoRedo to serverside only
|
||||
if (player instanceof ServerPlayer && event.getState() != null && event.getPos() != null) {
|
||||
PacketDistributor.PacketTarget packetTarget = PacketDistributor.PLAYER.with(() -> (ServerPlayer) player);
|
||||
if (packetTarget != null)
|
||||
PacketHandler.INSTANCE.send(packetTarget, new AddUndoMessage(event.getPos(), event.getState(), Blocks.AIR.defaultBlockState()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +98,7 @@ public class CommonEvents {
|
||||
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
|
||||
if (event.getEntity() instanceof FakePlayer) return;
|
||||
Player player = event.getEntity();
|
||||
ServerBuildState.handleNewPlayer(player);
|
||||
ModifierSettingsManager.handleNewPlayer(player);
|
||||
}
|
||||
|
||||
@@ -126,13 +109,13 @@ public class CommonEvents {
|
||||
if (player.getCommandSenderWorld().isClientSide) return;
|
||||
|
||||
UndoRedo.clear(player);
|
||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new ClearUndoMessage());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) {
|
||||
if (event.getEntity() instanceof FakePlayer) return;
|
||||
Player player = event.getEntity();
|
||||
ServerBuildState.handleNewPlayer(player);
|
||||
ModifierSettingsManager.handleNewPlayer(player);
|
||||
}
|
||||
|
||||
@@ -149,10 +132,10 @@ public class CommonEvents {
|
||||
modifierSettings.getArraySettings().enabled = false;
|
||||
ModifierSettingsManager.setModifierSettings(player, modifierSettings);
|
||||
|
||||
ServerBuildState.handleNewPlayer(player);
|
||||
ModifierSettingsManager.handleNewPlayer(player);
|
||||
|
||||
UndoRedo.clear(player);
|
||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new ClearUndoMessage());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -165,6 +148,4 @@ public class CommonEvents {
|
||||
Player newPlayer = event.getEntity();
|
||||
ModifierSettingsManager.setModifierSettings(newPlayer, ModifierSettingsManager.getModifierSettings(oldPlayer));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
package nl.requios.effortlessbuilding.buildmode;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import nl.requios.effortlessbuilding.ClientEvents;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
|
||||
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||
import nl.requios.effortlessbuilding.network.PerformRedoPacket;
|
||||
import nl.requios.effortlessbuilding.network.PerformUndoPacket;
|
||||
import nl.requios.effortlessbuilding.systems.BuildSettings;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class ModeOptions {
|
||||
|
||||
private static ActionEnum buildSpeed = ActionEnum.NORMAL_SPEED;
|
||||
@@ -58,76 +64,43 @@ public class ModeOptions {
|
||||
return circleStart;
|
||||
}
|
||||
|
||||
//Called on both client and server
|
||||
public static void performAction(Player player, ActionEnum action) {
|
||||
if (action == null) return;
|
||||
|
||||
switch (action) {
|
||||
case UNDO:
|
||||
UndoRedo.undo(player);
|
||||
break;
|
||||
case REDO:
|
||||
UndoRedo.redo(player);
|
||||
break;
|
||||
case REPLACE:
|
||||
if (player.level.isClientSide)
|
||||
EffortlessBuildingClient.BUILD_SETTINGS.toggleQuickReplace();
|
||||
break;
|
||||
case OPEN_MODIFIER_SETTINGS:
|
||||
if (player.level.isClientSide)
|
||||
ClientEvents.openModifierSettings();
|
||||
break;
|
||||
case OPEN_PLAYER_SETTINGS:
|
||||
if (player.level.isClientSide)
|
||||
ClientEvents.openPlayerSettings();
|
||||
break;
|
||||
case UNDO -> PacketHandler.INSTANCE.sendToServer(new PerformUndoPacket());
|
||||
case REDO -> PacketHandler.INSTANCE.sendToServer(new PerformRedoPacket());
|
||||
case OPEN_MODIFIER_SETTINGS -> ClientEvents.openModifierSettings();
|
||||
case OPEN_PLAYER_SETTINGS -> ClientEvents.openPlayerSettings();
|
||||
|
||||
case NORMAL_SPEED:
|
||||
buildSpeed = ActionEnum.NORMAL_SPEED;
|
||||
break;
|
||||
case FAST_SPEED:
|
||||
buildSpeed = ActionEnum.FAST_SPEED;
|
||||
break;
|
||||
case FULL:
|
||||
fill = ActionEnum.FULL;
|
||||
break;
|
||||
case HOLLOW:
|
||||
fill = ActionEnum.HOLLOW;
|
||||
break;
|
||||
case CUBE_FULL:
|
||||
cubeFill = ActionEnum.CUBE_FULL;
|
||||
break;
|
||||
case CUBE_HOLLOW:
|
||||
cubeFill = ActionEnum.CUBE_HOLLOW;
|
||||
break;
|
||||
case CUBE_SKELETON:
|
||||
cubeFill = ActionEnum.CUBE_SKELETON;
|
||||
break;
|
||||
case SHORT_EDGE:
|
||||
raisedEdge = ActionEnum.SHORT_EDGE;
|
||||
break;
|
||||
case LONG_EDGE:
|
||||
raisedEdge = ActionEnum.LONG_EDGE;
|
||||
break;
|
||||
case THICKNESS_1:
|
||||
lineThickness = ActionEnum.THICKNESS_1;
|
||||
break;
|
||||
case THICKNESS_3:
|
||||
lineThickness = ActionEnum.THICKNESS_3;
|
||||
break;
|
||||
case THICKNESS_5:
|
||||
lineThickness = ActionEnum.THICKNESS_5;
|
||||
break;
|
||||
case CIRCLE_START_CENTER:
|
||||
circleStart = ActionEnum.CIRCLE_START_CENTER;
|
||||
break;
|
||||
case CIRCLE_START_CORNER:
|
||||
circleStart = ActionEnum.CIRCLE_START_CORNER;
|
||||
break;
|
||||
case REPLACE_ONLY_AIR -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.ONLY_AIR);
|
||||
case REPLACE_BLOCKS_AND_AIR -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.BLOCKS_AND_AIR);
|
||||
case REPLACE_ONLY_BLOCKS -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.ONLY_BLOCKS);
|
||||
case REPLACE_FILTERED_BY_OFFHAND -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.FILTERED_BY_OFFHAND);
|
||||
case TOGGLE_PROTECT_TILE_ENTITIES -> EffortlessBuildingClient.BUILD_SETTINGS.toggleProtectTileEntities();
|
||||
|
||||
case NORMAL_SPEED -> buildSpeed = ActionEnum.NORMAL_SPEED;
|
||||
case FAST_SPEED -> buildSpeed = ActionEnum.FAST_SPEED;
|
||||
|
||||
case FULL -> fill = ActionEnum.FULL;
|
||||
case HOLLOW -> fill = ActionEnum.HOLLOW;
|
||||
|
||||
case CUBE_FULL -> cubeFill = ActionEnum.CUBE_FULL;
|
||||
case CUBE_HOLLOW -> cubeFill = ActionEnum.CUBE_HOLLOW;
|
||||
case CUBE_SKELETON -> cubeFill = ActionEnum.CUBE_SKELETON;
|
||||
|
||||
case SHORT_EDGE -> raisedEdge = ActionEnum.SHORT_EDGE;
|
||||
case LONG_EDGE -> raisedEdge = ActionEnum.LONG_EDGE;
|
||||
|
||||
case THICKNESS_1 -> lineThickness = ActionEnum.THICKNESS_1;
|
||||
case THICKNESS_3 -> lineThickness = ActionEnum.THICKNESS_3;
|
||||
case THICKNESS_5 -> lineThickness = ActionEnum.THICKNESS_5;
|
||||
|
||||
case CIRCLE_START_CENTER -> circleStart = ActionEnum.CIRCLE_START_CENTER;
|
||||
case CIRCLE_START_CORNER -> circleStart = ActionEnum.CIRCLE_START_CORNER;
|
||||
}
|
||||
|
||||
if (player.level.isClientSide &&
|
||||
action != ActionEnum.REPLACE &&
|
||||
action != ActionEnum.OPEN_MODIFIER_SETTINGS &&
|
||||
action != ActionEnum.OPEN_PLAYER_SETTINGS) {
|
||||
|
||||
@@ -138,10 +111,15 @@ public class ModeOptions {
|
||||
public enum ActionEnum {
|
||||
UNDO("effortlessbuilding.action.undo"),
|
||||
REDO("effortlessbuilding.action.redo"),
|
||||
REPLACE("effortlessbuilding.action.replace"),
|
||||
OPEN_MODIFIER_SETTINGS("effortlessbuilding.action.open_modifier_settings"),
|
||||
OPEN_PLAYER_SETTINGS("effortlessbuilding.action.open_player_settings"),
|
||||
|
||||
REPLACE_ONLY_AIR("effortlessbuilding.action.replace_only_air"),
|
||||
REPLACE_BLOCKS_AND_AIR("effortlessbuilding.action.replace_blocks_and_air"),
|
||||
REPLACE_ONLY_BLOCKS("effortlessbuilding.action.replace_only_blocks"),
|
||||
REPLACE_FILTERED_BY_OFFHAND("effortlessbuilding.action.replace_filtered_by_offhand"),
|
||||
TOGGLE_PROTECT_TILE_ENTITIES("effortlessbuilding.action.toggle_protect_tile_entities"),
|
||||
|
||||
NORMAL_SPEED("effortlessbuilding.action.normal_speed"),
|
||||
FAST_SPEED("effortlessbuilding.action.fast_speed"),
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||
@@ -29,18 +30,14 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode {
|
||||
|
||||
if (clicks == 1) {
|
||||
//First click, remember starting position
|
||||
firstBlockEntry = EffortlessBuildingClient.BUILDER_CHAIN.getStartPos();
|
||||
|
||||
//If clicking in air, reset and try again
|
||||
if (blocks.size() == 0) {
|
||||
clicks = 0;
|
||||
return false;
|
||||
}
|
||||
if (firstBlockEntry == null) clicks = 0;
|
||||
|
||||
firstBlockEntry = blocks.getFirstBlockEntry();
|
||||
} else if (clicks == 2) {
|
||||
//Second click, find second position
|
||||
|
||||
//If clicking in air, reset and try again
|
||||
if (blocks.size() == 0) {
|
||||
clicks = 0;
|
||||
return false;
|
||||
|
||||
@@ -3,6 +3,7 @@ package nl.requios.effortlessbuilding.buildmode;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||
@@ -25,14 +26,11 @@ public abstract class TwoClicksBuildMode extends BaseBuildMode {
|
||||
|
||||
if (clicks == 1) {
|
||||
//First click, remember starting position
|
||||
firstBlockEntry = EffortlessBuildingClient.BUILDER_CHAIN.getStartPos();
|
||||
|
||||
//If clicking in air, reset and try again
|
||||
if (blocks.size() == 0) {
|
||||
clicks = 0;
|
||||
return false;
|
||||
}
|
||||
if (firstBlockEntry == null) clicks = 0;
|
||||
|
||||
firstBlockEntry = blocks.getFirstBlockEntry();
|
||||
} else {
|
||||
//Second click, place blocks
|
||||
clicks = 0;
|
||||
|
||||
@@ -19,10 +19,11 @@ import nl.requios.effortlessbuilding.CommonConfig;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||
import nl.requios.effortlessbuilding.systems.DelayedBlockPlacer;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||
import nl.requios.effortlessbuilding.systems.UndoRedo;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
||||
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
|
||||
import nl.requios.effortlessbuilding.utilities.UndoRedoBlockSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -14,6 +14,7 @@ import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.FormattedText;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
@@ -22,8 +23,6 @@ import nl.requios.effortlessbuilding.ClientEvents;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
||||
import nl.requios.effortlessbuilding.network.ModeActionMessage;
|
||||
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
@@ -64,7 +63,8 @@ public class RadialMenu extends Screen {
|
||||
private final double textDistance = 75;
|
||||
private final double buttonDistance = 105;
|
||||
private final float fadeSpeed = 0.3f;
|
||||
private final int descriptionHeight = 100;
|
||||
private final int buildModeDescriptionHeight = 100;
|
||||
private final int actionDescriptionWidth = 200;
|
||||
|
||||
public BuildModeEnum switchTo = null;
|
||||
public ActionEnum doAction = null;
|
||||
@@ -91,7 +91,7 @@ public class RadialMenu extends Screen {
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (!ClientEvents.isKeybindDown(2)) {
|
||||
if (!ClientEvents.isKeybindDown(0)) {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
@@ -146,18 +146,23 @@ public class RadialMenu extends Screen {
|
||||
}
|
||||
|
||||
//Add actions
|
||||
buttons.add(new MenuButton(ActionEnum.UNDO.name, ActionEnum.UNDO, -buttonDistance - 26, -13, Direction.UP));
|
||||
buttons.add(new MenuButton(ActionEnum.REDO.name, ActionEnum.REDO, -buttonDistance, -13, Direction.UP));
|
||||
// buttons.add(new MenuButton(ActionEnum.OPEN_PLAYER_SETTINGS.name, ActionEnum.OPEN_PLAYER_SETTINGS, -buttonDistance - 26 - 13, 13, Direction.DOWN));
|
||||
buttons.add(new MenuButton(ActionEnum.OPEN_MODIFIER_SETTINGS.name, ActionEnum.OPEN_MODIFIER_SETTINGS, -buttonDistance - 26, 13, Direction.DOWN));
|
||||
buttons.add(new MenuButton(ActionEnum.REPLACE.name, ActionEnum.REPLACE, -buttonDistance, 13, Direction.DOWN));
|
||||
// buttons.add(new MenuButton(ActionEnum.OPEN_PLAYER_SETTINGS, -buttonDistance - 65, -13, Direction.UP));
|
||||
buttons.add(new MenuButton(ActionEnum.TOGGLE_PROTECT_TILE_ENTITIES, -buttonDistance - 78, -13, Direction.UP));
|
||||
buttons.add(new MenuButton(ActionEnum.OPEN_MODIFIER_SETTINGS, -buttonDistance - 52, -13, Direction.UP));
|
||||
buttons.add(new MenuButton(ActionEnum.UNDO, -buttonDistance - 26, -13, Direction.UP));
|
||||
buttons.add(new MenuButton(ActionEnum.REDO, -buttonDistance, -13, Direction.UP));
|
||||
|
||||
buttons.add(new MenuButton(ActionEnum.REPLACE_ONLY_AIR, -buttonDistance - 78, 13, Direction.DOWN));
|
||||
buttons.add(new MenuButton(ActionEnum.REPLACE_BLOCKS_AND_AIR, -buttonDistance - 52, 13, Direction.DOWN));
|
||||
buttons.add(new MenuButton(ActionEnum.REPLACE_ONLY_BLOCKS, -buttonDistance - 26, 13, Direction.DOWN));
|
||||
buttons.add(new MenuButton(ActionEnum.REPLACE_FILTERED_BY_OFFHAND, -buttonDistance, 13, Direction.DOWN));
|
||||
|
||||
//Add buildmode dependent options
|
||||
OptionEnum[] options = currentBuildMode.options;
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
for (int j = 0; j < options[i].actions.length; j++) {
|
||||
ActionEnum action = options[i].actions[j];
|
||||
buttons.add(new MenuButton(action.name, action, buttonDistance + j * 26, -13 + i * 39, Direction.DOWN));
|
||||
buttons.add(new MenuButton(action, buttonDistance + j * 26, -13 + i * 39, Direction.DOWN));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,15 +255,17 @@ public class RadialMenu extends Screen {
|
||||
private void drawSideButtonBackgrounds(BufferBuilder buffer, double middleX, double middleY, double mouseXCenter, double mouseYCenter, ArrayList<MenuButton> buttons) {
|
||||
for (final MenuButton btn : buttons) {
|
||||
|
||||
final boolean isSelected =
|
||||
final boolean isHighlighted = btn.x1 <= mouseXCenter && btn.x2 >= mouseXCenter && btn.y1 <= mouseYCenter && btn.y2 >= mouseYCenter;
|
||||
|
||||
boolean isSelected =
|
||||
btn.action == getBuildSpeed() ||
|
||||
btn.action == getFill() ||
|
||||
btn.action == getCubeFill() ||
|
||||
btn.action == getRaisedEdge() ||
|
||||
btn.action == getLineThickness() ||
|
||||
btn.action == getCircleStart();
|
||||
|
||||
final boolean isHighlighted = btn.x1 <= mouseXCenter && btn.x2 >= mouseXCenter && btn.y1 <= mouseYCenter && btn.y2 >= mouseYCenter;
|
||||
btn.action == getCircleStart() ||
|
||||
btn.action == EffortlessBuildingClient.BUILD_SETTINGS.getReplaceModeActionEnum() ||
|
||||
btn.action == ActionEnum.TOGGLE_PROTECT_TILE_ENTITIES && EffortlessBuildingClient.BUILD_SETTINGS.shouldProtectTileEntities();
|
||||
|
||||
Vector4f color = sideButtonColor;
|
||||
if (isSelected) color = selectedColor;
|
||||
@@ -340,20 +347,21 @@ public class RadialMenu extends Screen {
|
||||
|
||||
//Draw description
|
||||
text = I18n.get(menuRegion.mode.getDescriptionKey());
|
||||
font.drawShadow(ms, text, (int) middleX - font.width(text) / 2f, (int) middleY + descriptionHeight, descriptionTextColor);
|
||||
font.drawShadow(ms, text, (int) middleX - font.width(text) / 2f, (int) middleY + buildModeDescriptionHeight, descriptionTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
//Draw action text
|
||||
for (final MenuButton button : buttons) {
|
||||
if (button.highlighted) {
|
||||
|
||||
String text = ChatFormatting.AQUA + button.name;
|
||||
String description = ChatFormatting.WHITE + button.description;
|
||||
|
||||
//Add keybind in brackets
|
||||
String keybind = findKeybind(button, currentBuildMode);
|
||||
String keybindFormatted = "";
|
||||
if (!keybind.isEmpty())
|
||||
keybindFormatted = ChatFormatting.GRAY + "(" + WordUtils.capitalizeFully(keybind) + ")";
|
||||
boolean hasKeybind = !keybind.isEmpty();
|
||||
keybind = ChatFormatting.GRAY + "(" + WordUtils.capitalizeFully(keybind) + ")";
|
||||
|
||||
if (button.textSide == Direction.WEST) {
|
||||
|
||||
@@ -367,19 +375,31 @@ public class RadialMenu extends Screen {
|
||||
|
||||
} else if (button.textSide == Direction.UP || button.textSide == Direction.NORTH) {
|
||||
|
||||
font.draw(ms, keybindFormatted, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(keybindFormatted) * 0.5),
|
||||
(int) (middleY + button.y1 - 26), whiteTextColor);
|
||||
int y = (int) (middleY + button.y1 - 14);
|
||||
font.draw(ms, text, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(text) * 0.5), y, whiteTextColor);
|
||||
|
||||
font.draw(ms, text, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(text) * 0.5),
|
||||
(int) (middleY + button.y1 - 14), whiteTextColor);
|
||||
y -= 12;
|
||||
if (hasKeybind) {
|
||||
font.draw(ms, keybind, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(keybind) * 0.5), y, whiteTextColor);
|
||||
y -= 12;
|
||||
}
|
||||
|
||||
if (!description.isEmpty())
|
||||
font.drawWordWrap(FormattedText.of(description), (int) (middleX + (button.x1 + button.x2) * 0.5 - actionDescriptionWidth * 0.5), y, actionDescriptionWidth, whiteTextColor);
|
||||
|
||||
} else if (button.textSide == Direction.DOWN || button.textSide == Direction.SOUTH) {
|
||||
|
||||
font.draw(ms, text, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(text) * 0.5),
|
||||
(int) (middleY + button.y1 + 26), whiteTextColor);
|
||||
int y = (int) (middleY + button.y1 + 26);
|
||||
font.draw(ms, text, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(text) * 0.5), y, whiteTextColor);
|
||||
|
||||
font.draw(ms, keybindFormatted, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(keybindFormatted) * 0.5),
|
||||
(int) (middleY + button.y1 + 38), whiteTextColor);
|
||||
y += 12;
|
||||
if (hasKeybind) {
|
||||
font.draw(ms, keybind, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(keybind) * 0.5), y, whiteTextColor);
|
||||
y += 12;
|
||||
}
|
||||
|
||||
if (!description.isEmpty())
|
||||
font.drawWordWrap(FormattedText.of(description), (int) (middleX + (button.x1 + button.x2) * 0.5 - actionDescriptionWidth * 0.5), y, actionDescriptionWidth, whiteTextColor);
|
||||
|
||||
}
|
||||
|
||||
@@ -390,15 +410,14 @@ public class RadialMenu extends Screen {
|
||||
private String findKeybind(MenuButton button, BuildModeEnum currentBuildMode){
|
||||
String result = "";
|
||||
int keybindingIndex = -1;
|
||||
if (button.action == ActionEnum.UNDO) keybindingIndex = 3;
|
||||
if (button.action == ActionEnum.REDO) keybindingIndex = 4;
|
||||
if (button.action == ActionEnum.REPLACE) keybindingIndex = 1;
|
||||
if (button.action == ActionEnum.OPEN_MODIFIER_SETTINGS) keybindingIndex = 0;
|
||||
if (button.action == ActionEnum.OPEN_MODIFIER_SETTINGS) keybindingIndex = 1;
|
||||
if (button.action == ActionEnum.UNDO) keybindingIndex = 2;
|
||||
if (button.action == ActionEnum.REDO) keybindingIndex = 3;
|
||||
|
||||
if (keybindingIndex != -1) {
|
||||
KeyMapping keyMap = ClientEvents.keyBindings[keybindingIndex];
|
||||
|
||||
if (!keyMap.getKeyModifier().name().equals("none")) {
|
||||
if (!keyMap.getKeyModifier().name().equals("None")) {
|
||||
result = keyMap.getKeyModifier().name() + " ";
|
||||
}
|
||||
result += I18n.get(keyMap.getKey().getName());
|
||||
@@ -408,10 +427,12 @@ public class RadialMenu extends Screen {
|
||||
//Add (ctrl) to first two actions of first option
|
||||
if (button.action == currentBuildMode.options[0].actions[0]
|
||||
|| button.action == currentBuildMode.options[0].actions[1]) {
|
||||
result = I18n.get(ClientEvents.keyBindings[5].getKey().getName());
|
||||
result = I18n.get(ClientEvents.keyBindings[4].getKey().getDisplayName().getString());
|
||||
if (result.equals("Left Control")) result = "Ctrl";
|
||||
}
|
||||
}
|
||||
|
||||
result = result.replace("Key.keyboard.", "");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -465,7 +486,6 @@ public class RadialMenu extends Screen {
|
||||
playRadialMenuSound();
|
||||
|
||||
ModeOptions.performAction(player, action);
|
||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
|
||||
|
||||
if (fromMouseClick) performedActionUsingMouse = true;
|
||||
}
|
||||
@@ -487,11 +507,17 @@ public class RadialMenu extends Screen {
|
||||
public double y1, y2;
|
||||
public boolean highlighted;
|
||||
public String name;
|
||||
public String description = "";
|
||||
public Direction textSide;
|
||||
|
||||
public MenuButton(final String name, final ActionEnum action, final double x, final double y,
|
||||
public MenuButton(final ActionEnum action, final double x, final double y,
|
||||
final Direction textSide) {
|
||||
this.name = I18n.get(name);
|
||||
this.name = I18n.get(action.name);
|
||||
|
||||
if (I18n.exists(action.name + ".description")) {
|
||||
this.description = I18n.get(action.name + ".description");
|
||||
}
|
||||
|
||||
this.action = action;
|
||||
x1 = x - 10;
|
||||
x2 = x + 10;
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ModifierSettingsGui extends Screen {
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int p_96553_, int p_96554_) {
|
||||
if (keyCode == ClientEvents.keyBindings[0].getKey().getValue()) {
|
||||
if (keyCode == ClientEvents.keyBindings[1].getKey().getValue()) {
|
||||
minecraft.player.closeContainer();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
package nl.requios.effortlessbuilding.network;
|
||||
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.core.BlockPos;
|
||||
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.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.UndoRedoBlockSet;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/***
|
||||
* Sends a message to the client asking to add a block to the undo stack.
|
||||
*/
|
||||
@Deprecated
|
||||
public class AddUndoMessage {
|
||||
private final BlockPos coordinate;
|
||||
private final BlockState previousBlockState;
|
||||
private final BlockState newBlockState;
|
||||
|
||||
public AddUndoMessage() {
|
||||
coordinate = BlockPos.ZERO;
|
||||
previousBlockState = null;
|
||||
newBlockState = null;
|
||||
}
|
||||
|
||||
public AddUndoMessage(BlockPos coordinate, BlockState previousBlockState, BlockState newBlockState) {
|
||||
this.coordinate = coordinate;
|
||||
this.previousBlockState = previousBlockState;
|
||||
this.newBlockState = newBlockState;
|
||||
}
|
||||
|
||||
public static void encode(AddUndoMessage message, FriendlyByteBuf buf) {
|
||||
buf.writeInt(message.coordinate.getX());
|
||||
buf.writeInt(message.coordinate.getY());
|
||||
buf.writeInt(message.coordinate.getZ());
|
||||
buf.writeInt(Block.getId(message.previousBlockState));
|
||||
buf.writeInt(Block.getId(message.newBlockState));
|
||||
}
|
||||
|
||||
public static AddUndoMessage decode(FriendlyByteBuf buf) {
|
||||
BlockPos coordinate = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
|
||||
BlockState previousBlockState = Block.stateById(buf.readInt());
|
||||
BlockState newBlockState = Block.stateById(buf.readInt());
|
||||
return new AddUndoMessage(coordinate, previousBlockState, newBlockState);
|
||||
}
|
||||
|
||||
public BlockPos getCoordinate() {
|
||||
return coordinate;
|
||||
}
|
||||
|
||||
public BlockState getPreviousBlockState() {
|
||||
return previousBlockState;
|
||||
}
|
||||
|
||||
public BlockState getNewBlockState() {
|
||||
return newBlockState;
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(AddUndoMessage 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(AddUndoMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||
Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
|
||||
//Add to undo stack clientside
|
||||
//Only the appropriate player that needs to add this to the undo stack gets this message
|
||||
UndoRedo.addUndo(player, new UndoRedoBlockSet(
|
||||
new ArrayList<BlockPos>() {{
|
||||
add(message.getCoordinate());
|
||||
}},
|
||||
new ArrayList<BlockState>() {{
|
||||
add(message.getPreviousBlockState());
|
||||
}},
|
||||
new ArrayList<BlockState>() {{
|
||||
add(message.getNewBlockState());
|
||||
}},
|
||||
message.getCoordinate(), message.getCoordinate()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package nl.requios.effortlessbuilding.network;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
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.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/***
|
||||
* Sends a message to the client asking to clear the undo and redo stacks.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ClearUndoMessage {
|
||||
|
||||
public ClearUndoMessage() {
|
||||
}
|
||||
|
||||
public static void encode(ClearUndoMessage message, FriendlyByteBuf buf) {
|
||||
|
||||
}
|
||||
|
||||
public static ClearUndoMessage decode(FriendlyByteBuf buf) {
|
||||
return new ClearUndoMessage();
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(ClearUndoMessage 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(ClearUndoMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||
Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
|
||||
|
||||
//Add to undo stack clientside
|
||||
UndoRedo.clear(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +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.ModeOptions;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Shares mode settings (see ModeSettingsManager) between server and client
|
||||
*/
|
||||
@Deprecated
|
||||
public class ModeActionMessage {
|
||||
|
||||
private ModeOptions.ActionEnum action;
|
||||
|
||||
public ModeActionMessage() {
|
||||
}
|
||||
|
||||
public ModeActionMessage(ModeOptions.ActionEnum action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public static void encode(ModeActionMessage message, FriendlyByteBuf buf) {
|
||||
buf.writeInt(message.action.ordinal());
|
||||
}
|
||||
|
||||
public static ModeActionMessage decode(FriendlyByteBuf buf) {
|
||||
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.values()[buf.readInt()];
|
||||
return new ModeActionMessage(action);
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(ModeActionMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
|
||||
|
||||
ModeOptions.performAction(player, message.action);
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,16 +26,14 @@ public class PacketHandler {
|
||||
IsQuickReplacingPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
||||
INSTANCE.registerMessage(id++, ModifierSettingsMessage.class, ModifierSettingsMessage::encode, ModifierSettingsMessage::decode,
|
||||
ModifierSettingsMessage.Handler::handle);
|
||||
INSTANCE.registerMessage(id++, ModeActionMessage.class, ModeActionMessage::encode, ModeActionMessage::decode,
|
||||
ModeActionMessage.Handler::handle);
|
||||
INSTANCE.registerMessage(id++, ServerPlaceBlocksPacket.class, ServerPlaceBlocksPacket::encode, ServerPlaceBlocksPacket::decode,
|
||||
ServerPlaceBlocksPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
||||
INSTANCE.registerMessage(id++, ServerBreakBlocksPacket.class, ServerBreakBlocksPacket::encode, ServerBreakBlocksPacket::decode,
|
||||
ServerBreakBlocksPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
||||
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++, PerformUndoPacket.class, PerformUndoPacket::encode, PerformUndoPacket::decode,
|
||||
PerformUndoPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
||||
INSTANCE.registerMessage(id++, PerformRedoPacket.class, PerformRedoPacket::encode, PerformRedoPacket::decode,
|
||||
PerformRedoPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package nl.requios.effortlessbuilding.network;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import nl.requios.effortlessbuilding.systems.UndoRedo;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class PerformRedoPacket {
|
||||
|
||||
public PerformRedoPacket() {}
|
||||
|
||||
public static void encode(PerformRedoPacket message, FriendlyByteBuf buf) {}
|
||||
|
||||
public static PerformRedoPacket decode(FriendlyByteBuf buf) {
|
||||
return new PerformRedoPacket();
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(PerformRedoPacket message, Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
UndoRedo.redo(ctx.get().getSender());
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package nl.requios.effortlessbuilding.network;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import nl.requios.effortlessbuilding.systems.UndoRedo;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class PerformUndoPacket {
|
||||
|
||||
public PerformUndoPacket() {}
|
||||
|
||||
public static void encode(PerformUndoPacket message, FriendlyByteBuf buf) {}
|
||||
|
||||
public static PerformUndoPacket decode(FriendlyByteBuf buf) {
|
||||
return new PerformUndoPacket();
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(PerformUndoPacket message, Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
UndoRedo.undo(ctx.get().getSender());
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
@@ -29,12 +30,12 @@ public class BlockPreviews {
|
||||
public void onTick() {
|
||||
var player = Minecraft.getInstance().player;
|
||||
|
||||
drawPlacedBlocks(player);
|
||||
drawPlacedBlocks();
|
||||
drawLookAtPreview(player);
|
||||
drawOutlinesIfNoBlockInHand(player);
|
||||
drawOutlineAtBreakPosition(player);
|
||||
}
|
||||
|
||||
public void drawPlacedBlocks(Player player) {
|
||||
public void drawPlacedBlocks() {
|
||||
//Render placed blocks with appear animation
|
||||
if (ClientConfig.visuals.showBlockPreviews.get()) {
|
||||
for (PlacedBlocksEntry placed : placedBlocksList) {
|
||||
@@ -55,21 +56,22 @@ public class BlockPreviews {
|
||||
}
|
||||
|
||||
public void drawLookAtPreview(Player player) {
|
||||
if (EffortlessBuildingClient.BUILD_MODES.getBuildMode() == BuildModeEnum.DISABLED &&
|
||||
!ClientConfig.visuals.alwaysShowBlockPreview.get()) return;
|
||||
if (EffortlessBuildingClient.BUILD_MODES.getBuildMode() == BuildModeEnum.DISABLED) return;
|
||||
if (EffortlessBuildingClient.BUILDER_CHAIN.getBuildingState() == BuilderChain.BuildingState.IDLE &&
|
||||
ClientConfig.visuals.onlyShowBlockPreviewsWhenBuilding.get()) return;
|
||||
|
||||
var blocks = EffortlessBuildingClient.BUILDER_CHAIN.getBlocks();
|
||||
if (blocks.size() == 0) return;
|
||||
|
||||
var coordinates = blocks.getCoordinates();
|
||||
var state = EffortlessBuildingClient.BUILDER_CHAIN.getState();
|
||||
var state = EffortlessBuildingClient.BUILDER_CHAIN.getPretendBuildingState();
|
||||
|
||||
//Dont fade out the outline if we are still determining where to place
|
||||
//Every outline with same ID will not fade out (because it gets replaced)
|
||||
Object outlineID = "single";
|
||||
if (blocks.size() > 1) outlineID = blocks.firstPos;
|
||||
|
||||
if (state != BuilderChain.State.BREAKING) {
|
||||
if (state != BuilderChain.BuildingState.BREAKING) {
|
||||
//Use fancy shader if config allows, otherwise outlines
|
||||
if (ClientConfig.visuals.showBlockPreviews.get() && blocks.size() < ClientConfig.visuals.maxBlockPreviews.get()) {
|
||||
renderBlockPreviews(blocks, false, 0f);
|
||||
@@ -98,7 +100,7 @@ public class BlockPreviews {
|
||||
}
|
||||
|
||||
//Display block count and dimensions in actionbar
|
||||
if (state != BuilderChain.State.IDLE) {
|
||||
if (state != BuilderChain.BuildingState.IDLE) {
|
||||
|
||||
//Find min and max values (not simply firstPos and secondPos because that doesn't work with circles)
|
||||
int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
|
||||
@@ -126,31 +128,35 @@ public class BlockPreviews {
|
||||
}
|
||||
}
|
||||
|
||||
public void drawOutlinesIfNoBlockInHand(Player player) {
|
||||
var builderChain = EffortlessBuildingClient.BUILDER_CHAIN;
|
||||
if (builderChain.isBlockInHand()) return;
|
||||
if (builderChain.getState() != BuilderChain.State.IDLE) return;
|
||||
public void drawOutlineAtBreakPosition(Player player) {
|
||||
if (EffortlessBuildingClient.BUILD_MODES.getBuildMode() == BuildModeEnum.DISABLED) return;
|
||||
|
||||
var blocks = new ArrayList<>(builderChain.getBlocks().values());
|
||||
if (blocks.size() == 0) return;
|
||||
BuilderChain builderChain = EffortlessBuildingClient.BUILDER_CHAIN;
|
||||
BlockPos pos = builderChain.getStartPosForBreaking();
|
||||
if (pos == null) return;
|
||||
|
||||
//Only render first outline if further than normal reach
|
||||
var lookingAtNear = Minecraft.getInstance().hitResult;
|
||||
if (lookingAtNear != null && lookingAtNear.getType() == HitResult.Type.BLOCK)
|
||||
blocks.remove(0);
|
||||
|
||||
//Only render outlines if there is a block, like vanilla
|
||||
blocks.removeIf(blockEntry -> blockEntry.existingBlockState == null ||
|
||||
blockEntry.existingBlockState.isAir() ||
|
||||
blockEntry.existingBlockState.getMaterial().isLiquid());
|
||||
|
||||
if (!blocks.isEmpty()) {
|
||||
var coordinates = blocks.stream().map(blockEntry -> blockEntry.blockPos).collect(Collectors.toList());
|
||||
CreateClient.OUTLINER.showCluster("break", coordinates)
|
||||
.disableNormals()
|
||||
.lineWidth(1 / 64f)
|
||||
.colored(0x222222);
|
||||
var abilitiesState = builderChain.getAbilitiesState();
|
||||
if (ClientConfig.visuals.onlyShowBlockPreviewsWhenBuilding.get()) {
|
||||
if (abilitiesState == BuilderChain.AbilitiesState.NONE) return;
|
||||
} else {
|
||||
if (abilitiesState != BuilderChain.AbilitiesState.CAN_BREAK) return;
|
||||
}
|
||||
|
||||
//Only render if further than normal reach
|
||||
if (EffortlessBuildingClient.BUILDER_CHAIN.getLookingAtNear() != null) return;
|
||||
|
||||
AABB aabb = new AABB(pos);
|
||||
if (player.level.isLoaded(pos)) {
|
||||
var blockState = player.level.getBlockState(pos);
|
||||
if (!blockState.isAir()) {
|
||||
aabb = blockState.getShape(player.level, pos).bounds().move(pos);
|
||||
}
|
||||
}
|
||||
|
||||
CreateClient.OUTLINER.showAABB("break", aabb)
|
||||
.disableNormals()
|
||||
.lineWidth(1 / 64f)
|
||||
.colored(0x222222);
|
||||
}
|
||||
|
||||
protected void renderBlockPreviews(BlockSet blocks, boolean breaking, float dissolve) {
|
||||
@@ -186,8 +192,8 @@ public class BlockPreviews {
|
||||
t = Mth.clamp(t, 0, 1);
|
||||
//Now we got a usable t value for this block
|
||||
|
||||
t = (float) Mth.smoothstep(t);
|
||||
// t = (float) bezier(t, .58,-0.08,.23,1.33);
|
||||
// t = (float) Mth.smoothstep(t);
|
||||
t = gain(t, 0.5f);
|
||||
|
||||
if (!breaking) {
|
||||
scale = 0.5f + (t * 0.3f);
|
||||
@@ -206,21 +212,12 @@ public class BlockPreviews {
|
||||
.scale(scale);
|
||||
}
|
||||
|
||||
//A bezier easing function where implicit first and last control points are (0,0) and (1,1).
|
||||
public double bezier(double t, double x1, double y1, double x2, double y2) {
|
||||
double t2 = t * t;
|
||||
double t3 = t2 * t;
|
||||
|
||||
double cx = 3.0 * x1;
|
||||
double bx = 3.0 * (x2 - x1) - cx;
|
||||
double ax = 1.0 - cx -bx;
|
||||
|
||||
double cy = 3.0 * y1;
|
||||
double by = 3.0 * (y2 - y1) - cy;
|
||||
double ay = 1.0 - cy - by;
|
||||
|
||||
// Calculate the curve point at parameter value t
|
||||
return (ay * t3) + (by * t2) + (cy * t) + 0;
|
||||
//k=1 is the identity curve, k<1 produces the classic gain() shape, and k>1 produces "s" shaped curves. The curves are symmetric (and inverse) for k=a and k=1/a.
|
||||
//https://iquilezles.org/articles/functions/
|
||||
private float gain(float x, float k)
|
||||
{
|
||||
float a = (float) (0.5 * Math.pow(2.0 * ((x < 0.5) ? x : 1.0 - x), k));
|
||||
return (x < 0.5) ? a : (1.0f - a);
|
||||
}
|
||||
|
||||
public void onBlocksPlaced(BlockSet blocks) {
|
||||
|
||||
@@ -55,7 +55,7 @@ public class RenderHandler {
|
||||
renderSubText(event.getPoseStack());
|
||||
}
|
||||
|
||||
private static final ChatFormatting highlightColor = ChatFormatting.BLUE;
|
||||
private static final ChatFormatting highlightColor = ChatFormatting.DARK_AQUA;
|
||||
private static final ChatFormatting normalColor = ChatFormatting.WHITE;
|
||||
private static final Component placingText = Component.literal(
|
||||
normalColor + "Left-click to " + highlightColor + "cancel, " +
|
||||
@@ -66,10 +66,10 @@ public class RenderHandler {
|
||||
normalColor + "Right-click to " + highlightColor + "cancel");
|
||||
|
||||
private static void renderSubText(PoseStack ms) {
|
||||
var state = EffortlessBuildingClient.BUILDER_CHAIN.getState();
|
||||
if (state == BuilderChain.State.IDLE) return;
|
||||
var state = EffortlessBuildingClient.BUILDER_CHAIN.getBuildingState();
|
||||
if (state == BuilderChain.BuildingState.IDLE) return;
|
||||
|
||||
var text = state == BuilderChain.State.PLACING ? placingText : breakingText;
|
||||
var text = state == BuilderChain.BuildingState.PLACING ? placingText : breakingText;
|
||||
|
||||
int screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth();
|
||||
int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight();
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package nl.requios.effortlessbuilding.systems;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
||||
import nl.requios.effortlessbuilding.network.IsQuickReplacingPacket;
|
||||
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||
|
||||
@@ -12,56 +10,57 @@ import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||
public class BuildSettings {
|
||||
public enum ReplaceMode {
|
||||
ONLY_AIR,
|
||||
SOLID_AND_AIR,
|
||||
SOLID_ONLY,
|
||||
BLOCKS_AND_AIR,
|
||||
ONLY_BLOCKS,
|
||||
FILTERED_BY_OFFHAND
|
||||
}
|
||||
|
||||
private boolean quickReplace = false;
|
||||
public ReplaceMode replaceMode = ReplaceMode.ONLY_AIR;
|
||||
private boolean replaceTileEntities;
|
||||
private ReplaceMode replaceMode = ReplaceMode.ONLY_AIR;
|
||||
private boolean protectTileEntities = true;
|
||||
|
||||
public boolean isQuickReplacing() {
|
||||
return quickReplace;
|
||||
}
|
||||
|
||||
public void toggleQuickReplace() {
|
||||
setQuickReplace(!quickReplace);
|
||||
}
|
||||
|
||||
public void setQuickReplace(boolean quickReplace) {
|
||||
this.quickReplace = quickReplace;
|
||||
|
||||
EffortlessBuilding.log(Minecraft.getInstance().player, "Set " + ChatFormatting.GOLD + "Quick Replace " +
|
||||
ChatFormatting.RESET + (this.quickReplace ? "on" : "off"));
|
||||
PacketHandler.INSTANCE.sendToServer(new IsQuickReplacingPacket(this.quickReplace));
|
||||
return replaceMode != ReplaceMode.ONLY_AIR;
|
||||
}
|
||||
|
||||
public void setReplaceMode(ReplaceMode replaceMode) {
|
||||
this.replaceMode = replaceMode;
|
||||
PacketHandler.INSTANCE.sendToServer(new IsQuickReplacingPacket(isQuickReplacing()));
|
||||
}
|
||||
|
||||
public void setReplaceTileEntities(boolean replaceTileEntities) {
|
||||
this.replaceTileEntities = replaceTileEntities;
|
||||
public ReplaceMode getReplaceMode() {
|
||||
return replaceMode;
|
||||
}
|
||||
|
||||
public ModeOptions.ActionEnum getReplaceModeActionEnum() {
|
||||
return switch (replaceMode) {
|
||||
case ONLY_AIR -> ModeOptions.ActionEnum.REPLACE_ONLY_AIR;
|
||||
case BLOCKS_AND_AIR -> ModeOptions.ActionEnum.REPLACE_BLOCKS_AND_AIR;
|
||||
case ONLY_BLOCKS -> ModeOptions.ActionEnum.REPLACE_ONLY_BLOCKS;
|
||||
case FILTERED_BY_OFFHAND -> ModeOptions.ActionEnum.REPLACE_FILTERED_BY_OFFHAND;
|
||||
};
|
||||
}
|
||||
|
||||
public void toggleProtectTileEntities() {
|
||||
protectTileEntities = !protectTileEntities;
|
||||
}
|
||||
|
||||
public boolean shouldReplaceAir() {
|
||||
return replaceMode == ReplaceMode.ONLY_AIR || replaceMode == ReplaceMode.SOLID_AND_AIR;
|
||||
return replaceMode == ReplaceMode.ONLY_AIR || replaceMode == ReplaceMode.BLOCKS_AND_AIR;
|
||||
}
|
||||
|
||||
public boolean shouldReplaceSolid() {
|
||||
return replaceMode == ReplaceMode.SOLID_ONLY || replaceMode == ReplaceMode.SOLID_AND_AIR;
|
||||
public boolean shouldReplaceBlocks() {
|
||||
return replaceMode == ReplaceMode.ONLY_BLOCKS || replaceMode == ReplaceMode.BLOCKS_AND_AIR;
|
||||
}
|
||||
|
||||
public boolean shouldReplaceFiltered() {
|
||||
return replaceMode == ReplaceMode.FILTERED_BY_OFFHAND;
|
||||
}
|
||||
|
||||
public boolean shouldReplaceTileEntities() {
|
||||
return replaceTileEntities;
|
||||
public boolean shouldProtectTileEntities() {
|
||||
return protectTileEntities;
|
||||
}
|
||||
|
||||
public boolean shouldOffsetStartPosition() {
|
||||
return shouldReplaceSolid() || shouldReplaceFiltered();
|
||||
return replaceMode != ReplaceMode.ONLY_AIR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ 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.BuildModeEnum;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
|
||||
@@ -27,9 +28,7 @@ import nl.requios.effortlessbuilding.network.ServerBreakBlocksPacket;
|
||||
import nl.requios.effortlessbuilding.network.ServerPlaceBlocksPacket;
|
||||
import nl.requios.effortlessbuilding.utilities.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
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
|
||||
@@ -38,42 +37,46 @@ import java.util.List;
|
||||
public class BuilderChain {
|
||||
|
||||
private final BlockSet blocks = new BlockSet();
|
||||
private boolean blockInHand;
|
||||
private boolean lookingAtInteractiveObject;
|
||||
private Item previousHeldItem;
|
||||
private int soundTime = 0;
|
||||
private BlockEntry startPosForPlacing;
|
||||
private BlockPos startPosForBreaking;
|
||||
private BlockHitResult lookingAtNear;
|
||||
|
||||
public enum State {
|
||||
public enum BuildingState {
|
||||
IDLE,
|
||||
PLACING,
|
||||
BREAKING
|
||||
}
|
||||
|
||||
private State state = State.IDLE;
|
||||
//What we are currently doing
|
||||
private BuildingState buildingState = BuildingState.IDLE;
|
||||
|
||||
public enum AbilitiesState {
|
||||
CAN_PLACE_AND_BREAK,
|
||||
CAN_BREAK,
|
||||
NONE
|
||||
}
|
||||
|
||||
//Whether we can place or break blocks, determined by what we are looking at and what we are holding
|
||||
private AbilitiesState abilitiesState = AbilitiesState.CAN_PLACE_AND_BREAK;
|
||||
|
||||
public void onRightClick() {
|
||||
if (lookingAtInteractiveObject) return;
|
||||
var player = Minecraft.getInstance().player;
|
||||
|
||||
if (state == State.BREAKING) {
|
||||
if (abilitiesState != AbilitiesState.CAN_PLACE_AND_BREAK || buildingState == BuildingState.BREAKING) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blockInHand) {
|
||||
if (state == State.PLACING) cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == State.IDLE) {
|
||||
state = State.PLACING;
|
||||
if (buildingState == BuildingState.IDLE) {
|
||||
buildingState = BuildingState.PLACING;
|
||||
}
|
||||
|
||||
var player = Minecraft.getInstance().player;
|
||||
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
||||
|
||||
//Find out if we should place blocks now
|
||||
if (buildMode.instance.onClick(blocks)) {
|
||||
state = State.IDLE;
|
||||
buildingState = BuildingState.IDLE;
|
||||
|
||||
if (!blocks.isEmpty()) {
|
||||
EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksPlaced(blocks);
|
||||
@@ -85,28 +88,29 @@ public class BuilderChain {
|
||||
}
|
||||
|
||||
public void onLeftClick() {
|
||||
if (lookingAtInteractiveObject) return;
|
||||
var player = Minecraft.getInstance().player;
|
||||
|
||||
if (state == State.PLACING) {
|
||||
if (abilitiesState == AbilitiesState.NONE || buildingState == BuildingState.PLACING) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
var player = Minecraft.getInstance().player;
|
||||
if (!ReachHelper.canBreakFar(player)) return;
|
||||
|
||||
if (state == State.IDLE){
|
||||
state = State.BREAKING;
|
||||
if (buildingState == BuildingState.IDLE){
|
||||
buildingState = BuildingState.BREAKING;
|
||||
|
||||
//Recalculate block positions, because start position has changed
|
||||
onTick();
|
||||
//Use new start position for breaking, because we assumed the player was gonna place
|
||||
blocks.setStartPos(new BlockEntry(startPosForBreaking));
|
||||
BuilderFilter.filterOnCoordinates(blocks, player);
|
||||
findExistingBlockStates(player.level);
|
||||
BuilderFilter.filterOnExistingBlockStates(blocks, player);
|
||||
}
|
||||
|
||||
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
||||
|
||||
//Find out if we should break blocks now
|
||||
if (buildMode.instance.onClick(blocks)) {
|
||||
state = State.IDLE;
|
||||
buildingState = BuildingState.IDLE;
|
||||
|
||||
if (!blocks.isEmpty()) {
|
||||
EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksBroken(blocks);
|
||||
@@ -120,40 +124,45 @@ public class BuilderChain {
|
||||
public void onTick() {
|
||||
var previousCoordinates = new HashSet<>(blocks.getCoordinates());
|
||||
blocks.clear();
|
||||
startPosForPlacing = null;
|
||||
startPosForBreaking = null;
|
||||
lookingAtNear = null;
|
||||
|
||||
var mc = Minecraft.getInstance();
|
||||
var player = mc.player;
|
||||
var world = mc.level;
|
||||
|
||||
//Check if we have a BlockItem in hand
|
||||
var itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
|
||||
blockInHand = CompatHelper.isItemBlockProxy(itemStack);
|
||||
|
||||
lookingAtInteractiveObject = BlockUtilities.determineIfLookingAtInteractiveObject(mc, world);
|
||||
if (lookingAtInteractiveObject) return;
|
||||
abilitiesState = determineAbilities(mc, player, world);
|
||||
if (abilitiesState == AbilitiesState.NONE) return;
|
||||
|
||||
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
||||
var modifierSettings = ModifierSettingsManager.getModifierSettings(player);
|
||||
|
||||
if (state == State.IDLE) {
|
||||
if (buildingState == BuildingState.IDLE) {
|
||||
//Find start position
|
||||
BlockHitResult lookingAt = ClientEvents.getLookingAtFar(player);
|
||||
BlockEntry startEntry = findStartPosition(player, lookingAt);
|
||||
BlockEntry startEntry = findStartPosition(player, buildMode);
|
||||
if (startEntry != null) {
|
||||
blocks.add(startEntry);
|
||||
blocks.firstPos = startEntry.blockPos;
|
||||
blocks.lastPos = startEntry.blockPos;
|
||||
blocks.setStartPos(startEntry);
|
||||
} else {
|
||||
//We aren't placing or breaking blocks, and we have no start position
|
||||
abilitiesState = AbilitiesState.NONE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EffortlessBuildingClient.BUILD_MODES.findCoordinates(blocks, player, buildMode);
|
||||
EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player, modifierSettings);
|
||||
|
||||
BuilderFilter.filterOnCoordinates(blocks, player);
|
||||
|
||||
if (buildMode == BuildModeEnum.DISABLED && blocks.size() <= 1) {
|
||||
abilitiesState = AbilitiesState.NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
findExistingBlockStates(world);
|
||||
BuilderFilter.filterOnExistingBlockStates(blocks, player);
|
||||
|
||||
var itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
|
||||
findNewBlockStates(player, itemStack);
|
||||
BuilderFilter.filterOnNewBlockStates(blocks, player);
|
||||
|
||||
@@ -165,6 +174,28 @@ public class BuilderChain {
|
||||
previousHeldItem = itemStack.getItem();
|
||||
}
|
||||
|
||||
//Whether we can place or break blocks, determined by what we are looking at and what we are holding
|
||||
private AbilitiesState determineAbilities(Minecraft mc, Player player, Level world) {
|
||||
|
||||
var hitResult = Minecraft.getInstance().hitResult;
|
||||
if (hitResult != null && hitResult.getType() == HitResult.Type.BLOCK) {
|
||||
lookingAtNear = (BlockHitResult) hitResult;
|
||||
}
|
||||
|
||||
var itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
|
||||
boolean blockInHand = CompatHelper.isItemBlockProxy(itemStack);
|
||||
boolean lookingAtInteractiveObject = BlockUtilities.determineIfLookingAtInteractiveObject(mc, world);
|
||||
boolean isShiftKeyDown = player.isShiftKeyDown();
|
||||
|
||||
if (lookingAtInteractiveObject && !isShiftKeyDown)
|
||||
return AbilitiesState.NONE;
|
||||
|
||||
if (!blockInHand)
|
||||
return AbilitiesState.CAN_BREAK;
|
||||
|
||||
return AbilitiesState.CAN_PLACE_AND_BREAK;
|
||||
}
|
||||
|
||||
private void onBlocksChanged(Player player) {
|
||||
|
||||
//Renew randomness of randomizer bag
|
||||
@@ -177,64 +208,77 @@ public class BuilderChain {
|
||||
if (blocks.getLastBlockEntry() != null && blocks.getLastBlockEntry().newBlockState != null) {
|
||||
var lastBlockState = blocks.getLastBlockEntry().newBlockState;
|
||||
SoundType soundType = lastBlockState.getBlock().getSoundType(lastBlockState, player.level, blocks.lastPos, player);
|
||||
SoundEvent soundEvent = state == BuilderChain.State.BREAKING ? soundType.getBreakSound() : soundType.getPlaceSound();
|
||||
SoundEvent soundEvent = buildingState == BuildingState.BREAKING ? soundType.getBreakSound() : soundType.getPlaceSound();
|
||||
player.level.playSound(player, player.blockPosition(), soundEvent, SoundSource.BLOCKS, 0.3f, 0.8f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (state == State.IDLE) return;
|
||||
state = State.IDLE;
|
||||
if (buildingState == BuildingState.IDLE) return;
|
||||
buildingState = BuildingState.IDLE;
|
||||
EffortlessBuildingClient.BUILD_MODES.onCancel();
|
||||
Minecraft.getInstance().player.playSound(SoundEvents.UI_TOAST_OUT, 4, 1);
|
||||
}
|
||||
|
||||
private BlockEntry findStartPosition(Player player, BlockHitResult lookingAtFar) {
|
||||
if (lookingAtFar == null || lookingAtFar.getType() == HitResult.Type.MISS) return null;
|
||||
private BlockEntry findStartPosition(Player player, BuildModeEnum buildMode) {
|
||||
|
||||
var startPos = lookingAtFar.getBlockPos();
|
||||
//Determine if we should look far or nearby
|
||||
boolean shouldLookAtNear = buildMode == BuildModeEnum.DISABLED;
|
||||
BlockHitResult lookingAt;
|
||||
if (shouldLookAtNear) {
|
||||
lookingAt = lookingAtNear;
|
||||
} else {
|
||||
lookingAt = ClientEvents.getLookingAtFar(player);
|
||||
}
|
||||
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;
|
||||
|
||||
//TODO we are always at IDLE state here, find another way to check if we are breaking
|
||||
if (state != State.BREAKING) {
|
||||
startPosForBreaking = startPos;
|
||||
if (!shouldLookAtNear && !ReachHelper.canBreakFar(player)) {
|
||||
startPosForBreaking = null;
|
||||
}
|
||||
|
||||
if (abilitiesState == AbilitiesState.CAN_PLACE_AND_BREAK) {
|
||||
//Calculate start position for placing
|
||||
|
||||
//Offset in direction of sidehit if not quickreplace and not replaceable
|
||||
boolean shouldOffsetStartPosition = EffortlessBuildingClient.BUILD_SETTINGS.shouldOffsetStartPosition();
|
||||
boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable();
|
||||
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos);
|
||||
if (!shouldOffsetStartPosition && !replaceable && !becomesDoubleSlab) {
|
||||
startPos = startPos.relative(lookingAtFar.getDirection());
|
||||
startPos = startPos.relative(lookingAt.getDirection());
|
||||
}
|
||||
|
||||
//Get under tall grass and other replaceable blocks
|
||||
if (shouldOffsetStartPosition && replaceable) {
|
||||
startPos = startPos.below();
|
||||
}
|
||||
|
||||
} else {
|
||||
//We can only break
|
||||
|
||||
//Do not break far if we are not allowed to
|
||||
if (!ReachHelper.canBreakFar(player)) {
|
||||
boolean startPosIsNear = false;
|
||||
var lookingAtNear = Minecraft.getInstance().hitResult;
|
||||
if (lookingAtNear != null && lookingAtNear.getType() == HitResult.Type.BLOCK) {
|
||||
startPosIsNear = ((BlockHitResult) lookingAtNear).getBlockPos().equals(startPos);
|
||||
}
|
||||
if (!startPosIsNear) return null;
|
||||
}
|
||||
if (startPosForBreaking == null) return null;
|
||||
}
|
||||
|
||||
var blockEntry = new BlockEntry(startPos);
|
||||
|
||||
//Place upside-down stairs if we aim high at block
|
||||
var hitVec = lookingAtFar.getLocation();
|
||||
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;
|
||||
}
|
||||
|
||||
startPosForPlacing = blockEntry;
|
||||
|
||||
return blockEntry;
|
||||
}
|
||||
|
||||
@@ -245,7 +289,7 @@ public class BuilderChain {
|
||||
}
|
||||
|
||||
private void findNewBlockStates(Player player, ItemStack itemStack) {
|
||||
if (state == State.BREAKING) return;
|
||||
if (buildingState == BuildingState.BREAKING) return;
|
||||
|
||||
if (itemStack.getItem() instanceof BlockItem) {
|
||||
|
||||
@@ -264,20 +308,39 @@ public class BuilderChain {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public BlockSet getBlocks() {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public boolean isBlockInHand() {
|
||||
return blockInHand;
|
||||
public BuildingState getBuildingState() {
|
||||
return buildingState;
|
||||
}
|
||||
|
||||
public boolean isLookingAtInteractiveObject() {
|
||||
return lookingAtInteractiveObject;
|
||||
public AbilitiesState getAbilitiesState() {
|
||||
return abilitiesState;
|
||||
}
|
||||
|
||||
public BuildingState getPretendBuildingState() {
|
||||
if (buildingState != BuildingState.IDLE) return buildingState;
|
||||
if (abilitiesState == AbilitiesState.CAN_PLACE_AND_BREAK) return BuildingState.PLACING;
|
||||
if (abilitiesState == AbilitiesState.CAN_BREAK) return BuildingState.BREAKING;
|
||||
return BuildingState.IDLE;
|
||||
}
|
||||
|
||||
public BlockEntry getStartPosForPlacing() {
|
||||
return startPosForPlacing;
|
||||
}
|
||||
|
||||
public BlockPos getStartPosForBreaking() {
|
||||
return startPosForBreaking;
|
||||
}
|
||||
|
||||
public BlockEntry getStartPos() {
|
||||
if (getPretendBuildingState() == BuildingState.BREAKING) return new BlockEntry(getStartPosForBreaking());
|
||||
return getStartPosForPlacing();
|
||||
}
|
||||
|
||||
public BlockHitResult getLookingAtNear() {
|
||||
return lookingAtNear;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||
import nl.requios.effortlessbuilding.utilities.PlaceChecker;
|
||||
|
||||
@@ -17,7 +16,8 @@ public class BuilderFilter {
|
||||
|
||||
public static void filterOnExistingBlockStates(BlockSet blocks, Player player) {
|
||||
var buildSettings = EffortlessBuildingClient.BUILD_SETTINGS;
|
||||
boolean placing = EffortlessBuildingClient.BUILDER_CHAIN.getState() == BuilderChain.State.PLACING;
|
||||
var buildingState = EffortlessBuildingClient.BUILDER_CHAIN.getPretendBuildingState();
|
||||
boolean placing = buildingState == BuilderChain.BuildingState.PLACING;
|
||||
|
||||
var iter = blocks.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
@@ -25,12 +25,13 @@ public class BuilderFilter {
|
||||
var blockState = blockEntry.existingBlockState;
|
||||
boolean remove = false;
|
||||
|
||||
if (!buildSettings.shouldReplaceTileEntities() && blockState.hasBlockEntity()) remove = true;
|
||||
if (buildSettings.shouldProtectTileEntities() && blockState.hasBlockEntity()) remove = true;
|
||||
|
||||
if (placing) {
|
||||
if (placing && !buildSettings.shouldReplaceFiltered()) {
|
||||
if (!buildSettings.shouldReplaceAir() && blockState.isAir()) remove = true;
|
||||
boolean isSolid = blockState.isRedstoneConductor(player.level, blockEntry.blockPos);
|
||||
if (!buildSettings.shouldReplaceSolid() && isSolid) remove = true;
|
||||
boolean isReplaceable = blockState.getMaterial().isReplaceable();
|
||||
// boolean isSolid = blockState.isRedstoneConductor(player.level, blockEntry.blockPos);
|
||||
if (!buildSettings.shouldReplaceBlocks() && !isReplaceable) remove = true;
|
||||
}
|
||||
|
||||
if (buildSettings.shouldReplaceFiltered()) {
|
||||
@@ -43,13 +44,16 @@ public class BuilderFilter {
|
||||
}
|
||||
|
||||
public static void filterOnNewBlockStates(BlockSet blocks, Player player) {
|
||||
var buildSettings = EffortlessBuildingClient.BUILD_SETTINGS;
|
||||
var buildingState = EffortlessBuildingClient.BUILDER_CHAIN.getPretendBuildingState();
|
||||
boolean placing = buildingState == BuilderChain.BuildingState.PLACING;
|
||||
|
||||
var iter = blocks.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
var blockEntry = iter.next().getValue();
|
||||
boolean remove = false;
|
||||
|
||||
if (!PlaceChecker.shouldPlaceBlock(player.level, blockEntry)) remove = true;
|
||||
if (placing && !PlaceChecker.shouldPlaceBlock(player.level, blockEntry)) remove = true;
|
||||
|
||||
if (remove) iter.remove();
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.UndoRedoBlockSet;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
|
||||
import nl.requios.effortlessbuilding.utilities.UndoRedoBlockSet;
|
||||
import nl.requios.effortlessbuilding.utilities.InventoryHelper;
|
||||
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public class ServerBlockPlacer {
|
||||
private boolean isPlacingOrBreakingBlocks = false;
|
||||
|
||||
public void placeBlocks(Player player, BlockSet blocks) {
|
||||
EffortlessBuilding.log(player, "Placing " + blocks.size() + " blocks");
|
||||
// EffortlessBuilding.log(player, "Placing " + blocks.size() + " blocks");
|
||||
|
||||
for (BlockEntry block : blocks) {
|
||||
placeBlock(player, block);
|
||||
@@ -47,7 +47,7 @@ public class ServerBlockPlacer {
|
||||
}
|
||||
|
||||
public void breakBlocks(Player player, BlockSet blocks) {
|
||||
EffortlessBuilding.log(player, "Breaking " + blocks.size() + " blocks");
|
||||
// EffortlessBuilding.log(player, "Breaking " + blocks.size() + " blocks");
|
||||
|
||||
for (BlockEntry block : blocks) {
|
||||
breakBlock(player, block);
|
||||
|
||||
@@ -7,6 +7,11 @@ public class ServerBuildState {
|
||||
private static final String IS_USING_BUILD_MODE_KEY = EffortlessBuilding.MODID + ":isUsingBuildMode";
|
||||
private static final String IS_QUICK_REPLACING_KEY = EffortlessBuilding.MODID + ":isQuickReplacing";
|
||||
|
||||
public static void handleNewPlayer(Player player) {
|
||||
setIsUsingBuildMode(player, false);
|
||||
setIsQuickReplacing(player, false);
|
||||
}
|
||||
|
||||
public static boolean isUsingBuildMode(Player player) {
|
||||
return player.getPersistentData().contains(IS_USING_BUILD_MODE_KEY);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package nl.requios.effortlessbuilding.buildmodifier;
|
||||
package nl.requios.effortlessbuilding.systems;
|
||||
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@@ -10,12 +10,14 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import nl.requios.effortlessbuilding.CommonConfig;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.utilities.UndoRedoBlockSet;
|
||||
import nl.requios.effortlessbuilding.utilities.FixedStack;
|
||||
import nl.requios.effortlessbuilding.utilities.InventoryHelper;
|
||||
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
//Server only
|
||||
public class UndoRedo {
|
||||
|
||||
//Undo and redo stacks per player
|
||||
@@ -1,9 +1,10 @@
|
||||
package nl.requios.effortlessbuilding.utilities;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -12,6 +13,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
//Common
|
||||
public class BlockSet extends HashMap<BlockPos, BlockEntry> implements Iterable<BlockEntry> {
|
||||
public static boolean logging = true;
|
||||
|
||||
@@ -35,20 +37,19 @@ public class BlockSet extends HashMap<BlockPos, BlockEntry> implements Iterable<
|
||||
}
|
||||
}
|
||||
|
||||
public void setStartPos(BlockEntry startPos) {
|
||||
clear();
|
||||
add(startPos);
|
||||
firstPos = startPos.blockPos;
|
||||
lastPos = startPos.blockPos;
|
||||
}
|
||||
|
||||
public void add(BlockEntry blockEntry) {
|
||||
if (!containsKey(blockEntry.blockPos)) {
|
||||
|
||||
//Limit number of blocks you can place
|
||||
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(Minecraft.getInstance().player);
|
||||
if (size() >= limit) {
|
||||
if (logging) EffortlessBuilding.log("BlockSet limit reached, not adding block at " + blockEntry.blockPos);
|
||||
return;
|
||||
if (!DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> ClientSide.isFull(this))) {
|
||||
put(blockEntry.blockPos, blockEntry);
|
||||
}
|
||||
|
||||
put(blockEntry.blockPos, blockEntry);
|
||||
|
||||
} else {
|
||||
|
||||
if (logging) EffortlessBuilding.log("BlockSet already contains block at " + blockEntry.blockPos);
|
||||
}
|
||||
}
|
||||
@@ -78,4 +79,17 @@ public class BlockSet extends HashMap<BlockPos, BlockEntry> implements Iterable<
|
||||
public static BlockSet decode(FriendlyByteBuf buf) {
|
||||
return new BlockSet(buf.readList(BlockEntry::decode));
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class ClientSide {
|
||||
public static boolean isFull(BlockSet blockSet) {
|
||||
//Limit number of blocks you can place
|
||||
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(net.minecraft.client.Minecraft.getInstance().player);
|
||||
if (blockSet.size() >= limit) {
|
||||
if (logging) EffortlessBuilding.log("BlockSet limit reached, not adding block.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package nl.requios.effortlessbuilding.utilities;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
@@ -9,6 +8,7 @@ import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@@ -16,6 +16,7 @@ import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
//Common
|
||||
public class BlockUtilities {
|
||||
|
||||
public static BlockState getBlockState(Player player, InteractionHand hand, ItemStack blockItemStack, BlockEntry blockEntry) {
|
||||
@@ -25,7 +26,7 @@ public class BlockUtilities {
|
||||
return block.getStateForPlacement(new BlockPlaceContext(player, hand, blockItemStack, blockHitResult));
|
||||
}
|
||||
|
||||
public static boolean determineIfLookingAtInteractiveObject(Minecraft mc, ClientLevel level) {
|
||||
public static boolean determineIfLookingAtInteractiveObject(Minecraft mc, Level level) {
|
||||
//Check if we are looking at an interactive object
|
||||
var result = false;
|
||||
if (mc.hitResult != null) {
|
||||
|
||||
@@ -17,13 +17,16 @@ public class PlaceChecker {
|
||||
|
||||
//SchematicPrinter::shouldPlaceBlock
|
||||
public static boolean shouldPlaceBlock(Level world, BlockEntry blockEntry) {
|
||||
if (world == null)
|
||||
if (world == null || blockEntry == null)
|
||||
return false;
|
||||
|
||||
var pos = blockEntry.blockPos;
|
||||
var state = blockEntry.newBlockState;
|
||||
BlockEntity tileEntity = null;
|
||||
|
||||
if (state == null)
|
||||
return false;
|
||||
|
||||
BlockState toReplace = world.getBlockState(pos);
|
||||
BlockEntity toReplaceTE = world.getBlockEntity(pos);
|
||||
BlockState toReplaceOther = null;
|
||||
|
||||
@@ -6,6 +6,7 @@ import nl.requios.effortlessbuilding.CommonConfig;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
||||
|
||||
//Common
|
||||
public class ReachHelper {
|
||||
private static final String REACH_UPGRADE_KEY = EffortlessBuilding.MODID + ":reachUpgrade";
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package nl.requios.effortlessbuilding.buildmodifier;
|
||||
package nl.requios.effortlessbuilding.utilities;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
//Used only for Undo
|
||||
//Server only
|
||||
@Deprecated
|
||||
public class UndoRedoBlockSet {
|
||||
private final List<BlockPos> coordinates;
|
||||
private final List<BlockState> previousBlockStates;
|
||||
Reference in New Issue
Block a user