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 static class Visuals {
|
||||||
public final ForgeConfigSpec.ConfigValue<Boolean> showBlockPreviews;
|
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 final ForgeConfigSpec.ConfigValue<Integer> maxBlockPreviews;
|
||||||
|
|
||||||
public Visuals(ForgeConfigSpec.Builder builder) {
|
public Visuals(ForgeConfigSpec.Builder builder) {
|
||||||
@@ -18,16 +18,16 @@ public class ClientConfig {
|
|||||||
|
|
||||||
showBlockPreviews = builder
|
showBlockPreviews = builder
|
||||||
.comment("Show previews of the blocks while placing them")
|
.comment("Show previews of the blocks while placing them")
|
||||||
.define("useShaders", true);
|
.define("showBlockPreviews", true);
|
||||||
|
|
||||||
alwaysShowBlockPreview = builder
|
onlyShowBlockPreviewsWhenBuilding = builder
|
||||||
.comment("Show a block preview if you have a block in hand even in the 'Disabled' build mode")
|
.comment("Show block previews only when actively using a build mode")
|
||||||
.define("alwaysShowBlockPreview", false);
|
.define("onlyShowBlockPreviewsWhenBuilding", true);
|
||||||
|
|
||||||
maxBlockPreviews = builder
|
maxBlockPreviews = builder
|
||||||
.comment("Don't show block previews when placing more than this many blocks. " +
|
.comment("Don't show block previews when placing more than this many blocks. " +
|
||||||
"The outline will always be rendered.")
|
"The outline will always be rendered.")
|
||||||
.define("shaderTreshold", 500);
|
.define("maxBlockPreviews", 500);
|
||||||
|
|
||||||
|
|
||||||
builder.pop();
|
builder.pop();
|
||||||
|
|||||||
@@ -52,15 +52,14 @@ public class ClientEvents {
|
|||||||
EffortlessBuilding.log("Registering KeyMappings!");
|
EffortlessBuilding.log("Registering KeyMappings!");
|
||||||
|
|
||||||
// register key bindings
|
// register key bindings
|
||||||
keyBindings = new KeyMapping[6];
|
keyBindings = new KeyMapping[5];
|
||||||
|
|
||||||
// instantiate the key bindings
|
// 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[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.replace.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_KP_SUBTRACT, 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.mode.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_ALT, 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.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.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");
|
||||||
keyBindings[5] = new KeyMapping("key.effortlessbuilding.altplacement.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_CONTROL, 0), "key.effortlessbuilding.category");
|
|
||||||
|
|
||||||
for (KeyMapping keyBinding : keyBindings) {
|
for (KeyMapping keyBinding : keyBindings) {
|
||||||
event.register(keyBinding);
|
event.register(keyBinding);
|
||||||
@@ -148,19 +147,8 @@ public class ClientEvents {
|
|||||||
if (player == null)
|
if (player == null)
|
||||||
return;
|
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
|
//Radial menu
|
||||||
if (keyBindings[2].isDown()) {
|
if (keyBindings[0].isDown()) {
|
||||||
if (ReachHelper.getMaxReach(player) > 0) {
|
if (ReachHelper.getMaxReach(player) > 0) {
|
||||||
if (!RadialMenu.instance.isVisible()) {
|
if (!RadialMenu.instance.isVisible()) {
|
||||||
Minecraft.getInstance().setScreen(RadialMenu.instance);
|
Minecraft.getInstance().setScreen(RadialMenu.instance);
|
||||||
@@ -170,22 +158,23 @@ public class ClientEvents {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Show Modifier Settings GUI
|
||||||
|
if (keyBindings[1].consumeClick()) {
|
||||||
|
openModifierSettings();
|
||||||
|
}
|
||||||
|
|
||||||
//Undo (Ctrl+Z)
|
//Undo (Ctrl+Z)
|
||||||
if (keyBindings[3].consumeClick()) {
|
if (keyBindings[2].consumeClick()) {
|
||||||
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.UNDO;
|
ModeOptions.performAction(player, ModeOptions.ActionEnum.UNDO);
|
||||||
ModeOptions.performAction(player, action);
|
|
||||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Redo (Ctrl+Y)
|
//Redo (Ctrl+Y)
|
||||||
if (keyBindings[4].consumeClick()) {
|
if (keyBindings[3].consumeClick()) {
|
||||||
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.REDO;
|
ModeOptions.performAction(player, ModeOptions.ActionEnum.REDO);
|
||||||
ModeOptions.performAction(player, action);
|
|
||||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Change placement mode
|
//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
|
//Toggle between first two actions of the first option of the current build mode
|
||||||
BuildModeEnum currentBuildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
BuildModeEnum currentBuildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
||||||
if (currentBuildMode.options.length > 0) {
|
if (currentBuildMode.options.length > 0) {
|
||||||
@@ -193,10 +182,8 @@ public class ClientEvents {
|
|||||||
if (option.actions.length >= 2) {
|
if (option.actions.length >= 2) {
|
||||||
if (ModeOptions.getOptionSetting(option) == option.actions[0]) {
|
if (ModeOptions.getOptionSetting(option) == option.actions[0]) {
|
||||||
ModeOptions.performAction(player, option.actions[1]);
|
ModeOptions.performAction(player, option.actions[1]);
|
||||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(option.actions[1]));
|
|
||||||
} else {
|
} else {
|
||||||
ModeOptions.performAction(player, option.actions[0]);
|
ModeOptions.performAction(player, option.actions[0]);
|
||||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(option.actions[0]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class CommonConfig {
|
|||||||
undoStackSize = builder
|
undoStackSize = builder
|
||||||
.comment("How many placements are remembered for the undo functionality.")
|
.comment("How many placements are remembered for the undo functionality.")
|
||||||
.worldRestart()
|
.worldRestart()
|
||||||
.define("undoStackSize", 10);
|
.define("undoStackSize", 50);
|
||||||
|
|
||||||
builder.pop();
|
builder.pop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,11 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|||||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||||
import net.minecraftforge.network.PacketDistributor;
|
import net.minecraftforge.network.PacketDistributor;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
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.capability.ModifierCapabilityManager;
|
||||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||||
import nl.requios.effortlessbuilding.systems.ServerBuildState;
|
import nl.requios.effortlessbuilding.systems.ServerBuildState;
|
||||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||||
import nl.requios.effortlessbuilding.network.AddUndoMessage;
|
|
||||||
import nl.requios.effortlessbuilding.network.ClearUndoMessage;
|
|
||||||
import nl.requios.effortlessbuilding.network.PacketHandler;
|
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||||
|
|
||||||
@EventBusSubscriber
|
@EventBusSubscriber
|
||||||
@@ -72,12 +70,6 @@ public class CommonEvents {
|
|||||||
if (isPlayerHoldingBlock(player)) {
|
if (isPlayerHoldingBlock(player)) {
|
||||||
event.setCanceled(true);
|
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)) {
|
if (!ServerBuildState.isLikeVanilla(player) && ReachHelper.canBreakFar(player)) {
|
||||||
event.setCanceled(true);
|
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) {
|
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
|
||||||
if (event.getEntity() instanceof FakePlayer) return;
|
if (event.getEntity() instanceof FakePlayer) return;
|
||||||
Player player = event.getEntity();
|
Player player = event.getEntity();
|
||||||
|
ServerBuildState.handleNewPlayer(player);
|
||||||
ModifierSettingsManager.handleNewPlayer(player);
|
ModifierSettingsManager.handleNewPlayer(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,13 +109,13 @@ public class CommonEvents {
|
|||||||
if (player.getCommandSenderWorld().isClientSide) return;
|
if (player.getCommandSenderWorld().isClientSide) return;
|
||||||
|
|
||||||
UndoRedo.clear(player);
|
UndoRedo.clear(player);
|
||||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new ClearUndoMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) {
|
public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) {
|
||||||
if (event.getEntity() instanceof FakePlayer) return;
|
if (event.getEntity() instanceof FakePlayer) return;
|
||||||
Player player = event.getEntity();
|
Player player = event.getEntity();
|
||||||
|
ServerBuildState.handleNewPlayer(player);
|
||||||
ModifierSettingsManager.handleNewPlayer(player);
|
ModifierSettingsManager.handleNewPlayer(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,10 +132,10 @@ public class CommonEvents {
|
|||||||
modifierSettings.getArraySettings().enabled = false;
|
modifierSettings.getArraySettings().enabled = false;
|
||||||
ModifierSettingsManager.setModifierSettings(player, modifierSettings);
|
ModifierSettingsManager.setModifierSettings(player, modifierSettings);
|
||||||
|
|
||||||
|
ServerBuildState.handleNewPlayer(player);
|
||||||
ModifierSettingsManager.handleNewPlayer(player);
|
ModifierSettingsManager.handleNewPlayer(player);
|
||||||
|
|
||||||
UndoRedo.clear(player);
|
UndoRedo.clear(player);
|
||||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new ClearUndoMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
@@ -165,6 +148,4 @@ public class CommonEvents {
|
|||||||
Player newPlayer = event.getEntity();
|
Player newPlayer = event.getEntity();
|
||||||
ModifierSettingsManager.setModifierSettings(newPlayer, ModifierSettingsManager.getModifierSettings(oldPlayer));
|
ModifierSettingsManager.setModifierSettings(newPlayer, ModifierSettingsManager.getModifierSettings(oldPlayer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
package nl.requios.effortlessbuilding.buildmode;
|
package nl.requios.effortlessbuilding.buildmode;
|
||||||
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
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.ClientEvents;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
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 {
|
public class ModeOptions {
|
||||||
|
|
||||||
private static ActionEnum buildSpeed = ActionEnum.NORMAL_SPEED;
|
private static ActionEnum buildSpeed = ActionEnum.NORMAL_SPEED;
|
||||||
@@ -58,76 +64,43 @@ public class ModeOptions {
|
|||||||
return circleStart;
|
return circleStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Called on both client and server
|
|
||||||
public static void performAction(Player player, ActionEnum action) {
|
public static void performAction(Player player, ActionEnum action) {
|
||||||
if (action == null) return;
|
if (action == null) return;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case UNDO:
|
case UNDO -> PacketHandler.INSTANCE.sendToServer(new PerformUndoPacket());
|
||||||
UndoRedo.undo(player);
|
case REDO -> PacketHandler.INSTANCE.sendToServer(new PerformRedoPacket());
|
||||||
break;
|
case OPEN_MODIFIER_SETTINGS -> ClientEvents.openModifierSettings();
|
||||||
case REDO:
|
case OPEN_PLAYER_SETTINGS -> ClientEvents.openPlayerSettings();
|
||||||
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 NORMAL_SPEED:
|
case REPLACE_ONLY_AIR -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.ONLY_AIR);
|
||||||
buildSpeed = ActionEnum.NORMAL_SPEED;
|
case REPLACE_BLOCKS_AND_AIR -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.BLOCKS_AND_AIR);
|
||||||
break;
|
case REPLACE_ONLY_BLOCKS -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.ONLY_BLOCKS);
|
||||||
case FAST_SPEED:
|
case REPLACE_FILTERED_BY_OFFHAND -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.FILTERED_BY_OFFHAND);
|
||||||
buildSpeed = ActionEnum.FAST_SPEED;
|
case TOGGLE_PROTECT_TILE_ENTITIES -> EffortlessBuildingClient.BUILD_SETTINGS.toggleProtectTileEntities();
|
||||||
break;
|
|
||||||
case FULL:
|
case NORMAL_SPEED -> buildSpeed = ActionEnum.NORMAL_SPEED;
|
||||||
fill = ActionEnum.FULL;
|
case FAST_SPEED -> buildSpeed = ActionEnum.FAST_SPEED;
|
||||||
break;
|
|
||||||
case HOLLOW:
|
case FULL -> fill = ActionEnum.FULL;
|
||||||
fill = ActionEnum.HOLLOW;
|
case HOLLOW -> fill = ActionEnum.HOLLOW;
|
||||||
break;
|
|
||||||
case CUBE_FULL:
|
case CUBE_FULL -> cubeFill = ActionEnum.CUBE_FULL;
|
||||||
cubeFill = ActionEnum.CUBE_FULL;
|
case CUBE_HOLLOW -> cubeFill = ActionEnum.CUBE_HOLLOW;
|
||||||
break;
|
case CUBE_SKELETON -> cubeFill = ActionEnum.CUBE_SKELETON;
|
||||||
case CUBE_HOLLOW:
|
|
||||||
cubeFill = ActionEnum.CUBE_HOLLOW;
|
case SHORT_EDGE -> raisedEdge = ActionEnum.SHORT_EDGE;
|
||||||
break;
|
case LONG_EDGE -> raisedEdge = ActionEnum.LONG_EDGE;
|
||||||
case CUBE_SKELETON:
|
|
||||||
cubeFill = ActionEnum.CUBE_SKELETON;
|
case THICKNESS_1 -> lineThickness = ActionEnum.THICKNESS_1;
|
||||||
break;
|
case THICKNESS_3 -> lineThickness = ActionEnum.THICKNESS_3;
|
||||||
case SHORT_EDGE:
|
case THICKNESS_5 -> lineThickness = ActionEnum.THICKNESS_5;
|
||||||
raisedEdge = ActionEnum.SHORT_EDGE;
|
|
||||||
break;
|
case CIRCLE_START_CENTER -> circleStart = ActionEnum.CIRCLE_START_CENTER;
|
||||||
case LONG_EDGE:
|
case CIRCLE_START_CORNER -> circleStart = ActionEnum.CIRCLE_START_CORNER;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.level.isClientSide &&
|
if (player.level.isClientSide &&
|
||||||
action != ActionEnum.REPLACE &&
|
|
||||||
action != ActionEnum.OPEN_MODIFIER_SETTINGS &&
|
action != ActionEnum.OPEN_MODIFIER_SETTINGS &&
|
||||||
action != ActionEnum.OPEN_PLAYER_SETTINGS) {
|
action != ActionEnum.OPEN_PLAYER_SETTINGS) {
|
||||||
|
|
||||||
@@ -138,10 +111,15 @@ public class ModeOptions {
|
|||||||
public enum ActionEnum {
|
public enum ActionEnum {
|
||||||
UNDO("effortlessbuilding.action.undo"),
|
UNDO("effortlessbuilding.action.undo"),
|
||||||
REDO("effortlessbuilding.action.redo"),
|
REDO("effortlessbuilding.action.redo"),
|
||||||
REPLACE("effortlessbuilding.action.replace"),
|
|
||||||
OPEN_MODIFIER_SETTINGS("effortlessbuilding.action.open_modifier_settings"),
|
OPEN_MODIFIER_SETTINGS("effortlessbuilding.action.open_modifier_settings"),
|
||||||
OPEN_PLAYER_SETTINGS("effortlessbuilding.action.open_player_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"),
|
NORMAL_SPEED("effortlessbuilding.action.normal_speed"),
|
||||||
FAST_SPEED("effortlessbuilding.action.fast_speed"),
|
FAST_SPEED("effortlessbuilding.action.fast_speed"),
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft;
|
|||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||||
@@ -29,18 +30,14 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode {
|
|||||||
|
|
||||||
if (clicks == 1) {
|
if (clicks == 1) {
|
||||||
//First click, remember starting position
|
//First click, remember starting position
|
||||||
|
firstBlockEntry = EffortlessBuildingClient.BUILDER_CHAIN.getStartPos();
|
||||||
|
|
||||||
//If clicking in air, reset and try again
|
//If clicking in air, reset and try again
|
||||||
if (blocks.size() == 0) {
|
if (firstBlockEntry == null) clicks = 0;
|
||||||
clicks = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstBlockEntry = blocks.getFirstBlockEntry();
|
|
||||||
} else if (clicks == 2) {
|
} else if (clicks == 2) {
|
||||||
//Second click, find second position
|
//Second click, find second position
|
||||||
|
|
||||||
//If clicking in air, reset and try again
|
|
||||||
if (blocks.size() == 0) {
|
if (blocks.size() == 0) {
|
||||||
clicks = 0;
|
clicks = 0;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package nl.requios.effortlessbuilding.buildmode;
|
|||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||||
@@ -25,14 +26,11 @@ public abstract class TwoClicksBuildMode extends BaseBuildMode {
|
|||||||
|
|
||||||
if (clicks == 1) {
|
if (clicks == 1) {
|
||||||
//First click, remember starting position
|
//First click, remember starting position
|
||||||
|
firstBlockEntry = EffortlessBuildingClient.BUILDER_CHAIN.getStartPos();
|
||||||
|
|
||||||
//If clicking in air, reset and try again
|
//If clicking in air, reset and try again
|
||||||
if (blocks.size() == 0) {
|
if (firstBlockEntry == null) clicks = 0;
|
||||||
clicks = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstBlockEntry = blocks.getFirstBlockEntry();
|
|
||||||
} else {
|
} else {
|
||||||
//Second click, place blocks
|
//Second click, place blocks
|
||||||
clicks = 0;
|
clicks = 0;
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ 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.systems.UndoRedo;
|
||||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||||
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.utilities.UndoRedoBlockSet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
|||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.FormattedText;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
import net.minecraft.sounds.SoundSource;
|
import net.minecraft.sounds.SoundSource;
|
||||||
@@ -22,8 +23,6 @@ import nl.requios.effortlessbuilding.ClientEvents;
|
|||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
|
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.apache.commons.lang3.text.WordUtils;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
@@ -64,7 +63,8 @@ public class RadialMenu extends Screen {
|
|||||||
private final double textDistance = 75;
|
private final double textDistance = 75;
|
||||||
private final double buttonDistance = 105;
|
private final double buttonDistance = 105;
|
||||||
private final float fadeSpeed = 0.3f;
|
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 BuildModeEnum switchTo = null;
|
||||||
public ActionEnum doAction = null;
|
public ActionEnum doAction = null;
|
||||||
@@ -91,7 +91,7 @@ public class RadialMenu extends Screen {
|
|||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
|
||||||
if (!ClientEvents.isKeybindDown(2)) {
|
if (!ClientEvents.isKeybindDown(0)) {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,18 +146,23 @@ public class RadialMenu extends Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Add actions
|
//Add actions
|
||||||
buttons.add(new MenuButton(ActionEnum.UNDO.name, ActionEnum.UNDO, -buttonDistance - 26, -13, Direction.UP));
|
// buttons.add(new MenuButton(ActionEnum.OPEN_PLAYER_SETTINGS, -buttonDistance - 65, -13, Direction.UP));
|
||||||
buttons.add(new MenuButton(ActionEnum.REDO.name, ActionEnum.REDO, -buttonDistance, -13, Direction.UP));
|
buttons.add(new MenuButton(ActionEnum.TOGGLE_PROTECT_TILE_ENTITIES, -buttonDistance - 78, -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, -buttonDistance - 52, -13, Direction.UP));
|
||||||
buttons.add(new MenuButton(ActionEnum.OPEN_MODIFIER_SETTINGS.name, ActionEnum.OPEN_MODIFIER_SETTINGS, -buttonDistance - 26, 13, Direction.DOWN));
|
buttons.add(new MenuButton(ActionEnum.UNDO, -buttonDistance - 26, -13, Direction.UP));
|
||||||
buttons.add(new MenuButton(ActionEnum.REPLACE.name, ActionEnum.REPLACE, -buttonDistance, 13, Direction.DOWN));
|
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
|
//Add buildmode dependent options
|
||||||
OptionEnum[] options = currentBuildMode.options;
|
OptionEnum[] options = currentBuildMode.options;
|
||||||
for (int i = 0; i < options.length; i++) {
|
for (int i = 0; i < options.length; i++) {
|
||||||
for (int j = 0; j < options[i].actions.length; j++) {
|
for (int j = 0; j < options[i].actions.length; j++) {
|
||||||
ActionEnum action = options[i].actions[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) {
|
private void drawSideButtonBackgrounds(BufferBuilder buffer, double middleX, double middleY, double mouseXCenter, double mouseYCenter, ArrayList<MenuButton> buttons) {
|
||||||
for (final MenuButton btn : 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 == getBuildSpeed() ||
|
||||||
btn.action == getFill() ||
|
btn.action == getFill() ||
|
||||||
btn.action == getCubeFill() ||
|
btn.action == getCubeFill() ||
|
||||||
btn.action == getRaisedEdge() ||
|
btn.action == getRaisedEdge() ||
|
||||||
btn.action == getLineThickness() ||
|
btn.action == getLineThickness() ||
|
||||||
btn.action == getCircleStart();
|
btn.action == getCircleStart() ||
|
||||||
|
btn.action == EffortlessBuildingClient.BUILD_SETTINGS.getReplaceModeActionEnum() ||
|
||||||
final boolean isHighlighted = btn.x1 <= mouseXCenter && btn.x2 >= mouseXCenter && btn.y1 <= mouseYCenter && btn.y2 >= mouseYCenter;
|
btn.action == ActionEnum.TOGGLE_PROTECT_TILE_ENTITIES && EffortlessBuildingClient.BUILD_SETTINGS.shouldProtectTileEntities();
|
||||||
|
|
||||||
Vector4f color = sideButtonColor;
|
Vector4f color = sideButtonColor;
|
||||||
if (isSelected) color = selectedColor;
|
if (isSelected) color = selectedColor;
|
||||||
@@ -340,20 +347,21 @@ public class RadialMenu extends Screen {
|
|||||||
|
|
||||||
//Draw description
|
//Draw description
|
||||||
text = I18n.get(menuRegion.mode.getDescriptionKey());
|
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
|
//Draw action text
|
||||||
for (final MenuButton button : buttons) {
|
for (final MenuButton button : buttons) {
|
||||||
if (button.highlighted) {
|
if (button.highlighted) {
|
||||||
|
|
||||||
String text = ChatFormatting.AQUA + button.name;
|
String text = ChatFormatting.AQUA + button.name;
|
||||||
|
String description = ChatFormatting.WHITE + button.description;
|
||||||
|
|
||||||
//Add keybind in brackets
|
//Add keybind in brackets
|
||||||
String keybind = findKeybind(button, currentBuildMode);
|
String keybind = findKeybind(button, currentBuildMode);
|
||||||
String keybindFormatted = "";
|
boolean hasKeybind = !keybind.isEmpty();
|
||||||
if (!keybind.isEmpty())
|
keybind = ChatFormatting.GRAY + "(" + WordUtils.capitalizeFully(keybind) + ")";
|
||||||
keybindFormatted = ChatFormatting.GRAY + "(" + WordUtils.capitalizeFully(keybind) + ")";
|
|
||||||
|
|
||||||
if (button.textSide == Direction.WEST) {
|
if (button.textSide == Direction.WEST) {
|
||||||
|
|
||||||
@@ -367,19 +375,31 @@ public class RadialMenu extends Screen {
|
|||||||
|
|
||||||
} else if (button.textSide == Direction.UP || button.textSide == Direction.NORTH) {
|
} 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 y = (int) (middleY + button.y1 - 14);
|
||||||
(int) (middleY + button.y1 - 26), whiteTextColor);
|
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),
|
y -= 12;
|
||||||
(int) (middleY + button.y1 - 14), whiteTextColor);
|
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) {
|
} 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 y = (int) (middleY + button.y1 + 26);
|
||||||
(int) (middleY + button.y1 + 26), whiteTextColor);
|
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),
|
y += 12;
|
||||||
(int) (middleY + button.y1 + 38), whiteTextColor);
|
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){
|
private String findKeybind(MenuButton button, BuildModeEnum currentBuildMode){
|
||||||
String result = "";
|
String result = "";
|
||||||
int keybindingIndex = -1;
|
int keybindingIndex = -1;
|
||||||
if (button.action == ActionEnum.UNDO) keybindingIndex = 3;
|
if (button.action == ActionEnum.OPEN_MODIFIER_SETTINGS) keybindingIndex = 1;
|
||||||
if (button.action == ActionEnum.REDO) keybindingIndex = 4;
|
if (button.action == ActionEnum.UNDO) keybindingIndex = 2;
|
||||||
if (button.action == ActionEnum.REPLACE) keybindingIndex = 1;
|
if (button.action == ActionEnum.REDO) keybindingIndex = 3;
|
||||||
if (button.action == ActionEnum.OPEN_MODIFIER_SETTINGS) keybindingIndex = 0;
|
|
||||||
|
|
||||||
if (keybindingIndex != -1) {
|
if (keybindingIndex != -1) {
|
||||||
KeyMapping keyMap = ClientEvents.keyBindings[keybindingIndex];
|
KeyMapping keyMap = ClientEvents.keyBindings[keybindingIndex];
|
||||||
|
|
||||||
if (!keyMap.getKeyModifier().name().equals("none")) {
|
if (!keyMap.getKeyModifier().name().equals("None")) {
|
||||||
result = keyMap.getKeyModifier().name() + " ";
|
result = keyMap.getKeyModifier().name() + " ";
|
||||||
}
|
}
|
||||||
result += I18n.get(keyMap.getKey().getName());
|
result += I18n.get(keyMap.getKey().getName());
|
||||||
@@ -408,10 +427,12 @@ public class RadialMenu extends Screen {
|
|||||||
//Add (ctrl) to first two actions of first option
|
//Add (ctrl) to first two actions of first option
|
||||||
if (button.action == currentBuildMode.options[0].actions[0]
|
if (button.action == currentBuildMode.options[0].actions[0]
|
||||||
|| button.action == currentBuildMode.options[0].actions[1]) {
|
|| 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";
|
if (result.equals("Left Control")) result = "Ctrl";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = result.replace("Key.keyboard.", "");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +486,6 @@ public class RadialMenu extends Screen {
|
|||||||
playRadialMenuSound();
|
playRadialMenuSound();
|
||||||
|
|
||||||
ModeOptions.performAction(player, action);
|
ModeOptions.performAction(player, action);
|
||||||
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
|
|
||||||
|
|
||||||
if (fromMouseClick) performedActionUsingMouse = true;
|
if (fromMouseClick) performedActionUsingMouse = true;
|
||||||
}
|
}
|
||||||
@@ -487,11 +507,17 @@ public class RadialMenu extends Screen {
|
|||||||
public double y1, y2;
|
public double y1, y2;
|
||||||
public boolean highlighted;
|
public boolean highlighted;
|
||||||
public String name;
|
public String name;
|
||||||
|
public String description = "";
|
||||||
public Direction textSide;
|
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) {
|
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;
|
this.action = action;
|
||||||
x1 = x - 10;
|
x1 = x - 10;
|
||||||
x2 = x + 10;
|
x2 = x + 10;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class ModifierSettingsGui extends Screen {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keyPressed(int keyCode, int p_96553_, int p_96554_) {
|
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();
|
minecraft.player.closeContainer();
|
||||||
return true;
|
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));
|
IsQuickReplacingPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
||||||
INSTANCE.registerMessage(id++, ModifierSettingsMessage.class, ModifierSettingsMessage::encode, ModifierSettingsMessage::decode,
|
INSTANCE.registerMessage(id++, ModifierSettingsMessage.class, ModifierSettingsMessage::encode, ModifierSettingsMessage::decode,
|
||||||
ModifierSettingsMessage.Handler::handle);
|
ModifierSettingsMessage.Handler::handle);
|
||||||
INSTANCE.registerMessage(id++, ModeActionMessage.class, ModeActionMessage::encode, ModeActionMessage::decode,
|
|
||||||
ModeActionMessage.Handler::handle);
|
|
||||||
INSTANCE.registerMessage(id++, ServerPlaceBlocksPacket.class, ServerPlaceBlocksPacket::encode, ServerPlaceBlocksPacket::decode,
|
INSTANCE.registerMessage(id++, ServerPlaceBlocksPacket.class, ServerPlaceBlocksPacket::encode, ServerPlaceBlocksPacket::decode,
|
||||||
ServerPlaceBlocksPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
ServerPlaceBlocksPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
||||||
INSTANCE.registerMessage(id++, ServerBreakBlocksPacket.class, ServerBreakBlocksPacket::encode, ServerBreakBlocksPacket::decode,
|
INSTANCE.registerMessage(id++, ServerBreakBlocksPacket.class, ServerBreakBlocksPacket::encode, ServerBreakBlocksPacket::decode,
|
||||||
ServerBreakBlocksPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
ServerBreakBlocksPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
||||||
INSTANCE.registerMessage(id++, AddUndoMessage.class, AddUndoMessage::encode, AddUndoMessage::decode,
|
INSTANCE.registerMessage(id++, PerformUndoPacket.class, PerformUndoPacket::encode, PerformUndoPacket::decode,
|
||||||
AddUndoMessage.Handler::handle);
|
PerformUndoPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER));
|
||||||
INSTANCE.registerMessage(id++, ClearUndoMessage.class, ClearUndoMessage::encode, ClearUndoMessage::decode,
|
INSTANCE.registerMessage(id++, PerformRedoPacket.class, PerformRedoPacket::encode, PerformRedoPacket::decode,
|
||||||
ClearUndoMessage.Handler::handle);
|
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.world.entity.player.Player;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
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 net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
@@ -29,12 +30,12 @@ public class BlockPreviews {
|
|||||||
public void onTick() {
|
public void onTick() {
|
||||||
var player = Minecraft.getInstance().player;
|
var player = Minecraft.getInstance().player;
|
||||||
|
|
||||||
drawPlacedBlocks(player);
|
drawPlacedBlocks();
|
||||||
drawLookAtPreview(player);
|
drawLookAtPreview(player);
|
||||||
drawOutlinesIfNoBlockInHand(player);
|
drawOutlineAtBreakPosition(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawPlacedBlocks(Player player) {
|
public void drawPlacedBlocks() {
|
||||||
//Render placed blocks with appear animation
|
//Render placed blocks with appear animation
|
||||||
if (ClientConfig.visuals.showBlockPreviews.get()) {
|
if (ClientConfig.visuals.showBlockPreviews.get()) {
|
||||||
for (PlacedBlocksEntry placed : placedBlocksList) {
|
for (PlacedBlocksEntry placed : placedBlocksList) {
|
||||||
@@ -55,21 +56,22 @@ public class BlockPreviews {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void drawLookAtPreview(Player player) {
|
public void drawLookAtPreview(Player player) {
|
||||||
if (EffortlessBuildingClient.BUILD_MODES.getBuildMode() == BuildModeEnum.DISABLED &&
|
if (EffortlessBuildingClient.BUILD_MODES.getBuildMode() == BuildModeEnum.DISABLED) return;
|
||||||
!ClientConfig.visuals.alwaysShowBlockPreview.get()) return;
|
if (EffortlessBuildingClient.BUILDER_CHAIN.getBuildingState() == BuilderChain.BuildingState.IDLE &&
|
||||||
|
ClientConfig.visuals.onlyShowBlockPreviewsWhenBuilding.get()) return;
|
||||||
|
|
||||||
var blocks = EffortlessBuildingClient.BUILDER_CHAIN.getBlocks();
|
var blocks = EffortlessBuildingClient.BUILDER_CHAIN.getBlocks();
|
||||||
if (blocks.size() == 0) return;
|
if (blocks.size() == 0) return;
|
||||||
|
|
||||||
var coordinates = blocks.getCoordinates();
|
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
|
//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)
|
//Every outline with same ID will not fade out (because it gets replaced)
|
||||||
Object outlineID = "single";
|
Object outlineID = "single";
|
||||||
if (blocks.size() > 1) outlineID = blocks.firstPos;
|
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
|
//Use fancy shader if config allows, otherwise outlines
|
||||||
if (ClientConfig.visuals.showBlockPreviews.get() && blocks.size() < ClientConfig.visuals.maxBlockPreviews.get()) {
|
if (ClientConfig.visuals.showBlockPreviews.get() && blocks.size() < ClientConfig.visuals.maxBlockPreviews.get()) {
|
||||||
renderBlockPreviews(blocks, false, 0f);
|
renderBlockPreviews(blocks, false, 0f);
|
||||||
@@ -98,7 +100,7 @@ public class BlockPreviews {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Display block count and dimensions in actionbar
|
//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)
|
//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;
|
int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
|
||||||
@@ -126,31 +128,35 @@ public class BlockPreviews {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawOutlinesIfNoBlockInHand(Player player) {
|
public void drawOutlineAtBreakPosition(Player player) {
|
||||||
var builderChain = EffortlessBuildingClient.BUILDER_CHAIN;
|
if (EffortlessBuildingClient.BUILD_MODES.getBuildMode() == BuildModeEnum.DISABLED) return;
|
||||||
if (builderChain.isBlockInHand()) return;
|
|
||||||
if (builderChain.getState() != BuilderChain.State.IDLE) return;
|
|
||||||
|
|
||||||
var blocks = new ArrayList<>(builderChain.getBlocks().values());
|
BuilderChain builderChain = EffortlessBuildingClient.BUILDER_CHAIN;
|
||||||
if (blocks.size() == 0) return;
|
BlockPos pos = builderChain.getStartPosForBreaking();
|
||||||
|
if (pos == null) return;
|
||||||
|
|
||||||
//Only render first outline if further than normal reach
|
var abilitiesState = builderChain.getAbilitiesState();
|
||||||
var lookingAtNear = Minecraft.getInstance().hitResult;
|
if (ClientConfig.visuals.onlyShowBlockPreviewsWhenBuilding.get()) {
|
||||||
if (lookingAtNear != null && lookingAtNear.getType() == HitResult.Type.BLOCK)
|
if (abilitiesState == BuilderChain.AbilitiesState.NONE) return;
|
||||||
blocks.remove(0);
|
} else {
|
||||||
|
if (abilitiesState != BuilderChain.AbilitiesState.CAN_BREAK) return;
|
||||||
//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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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) {
|
protected void renderBlockPreviews(BlockSet blocks, boolean breaking, float dissolve) {
|
||||||
@@ -186,8 +192,8 @@ public class BlockPreviews {
|
|||||||
t = Mth.clamp(t, 0, 1);
|
t = Mth.clamp(t, 0, 1);
|
||||||
//Now we got a usable t value for this block
|
//Now we got a usable t value for this block
|
||||||
|
|
||||||
t = (float) Mth.smoothstep(t);
|
// t = (float) Mth.smoothstep(t);
|
||||||
// t = (float) bezier(t, .58,-0.08,.23,1.33);
|
t = gain(t, 0.5f);
|
||||||
|
|
||||||
if (!breaking) {
|
if (!breaking) {
|
||||||
scale = 0.5f + (t * 0.3f);
|
scale = 0.5f + (t * 0.3f);
|
||||||
@@ -206,21 +212,12 @@ public class BlockPreviews {
|
|||||||
.scale(scale);
|
.scale(scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
//A bezier easing function where implicit first and last control points are (0,0) and (1,1).
|
//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.
|
||||||
public double bezier(double t, double x1, double y1, double x2, double y2) {
|
//https://iquilezles.org/articles/functions/
|
||||||
double t2 = t * t;
|
private float gain(float x, float k)
|
||||||
double t3 = t2 * t;
|
{
|
||||||
|
float a = (float) (0.5 * Math.pow(2.0 * ((x < 0.5) ? x : 1.0 - x), k));
|
||||||
double cx = 3.0 * x1;
|
return (x < 0.5) ? a : (1.0f - a);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBlocksPlaced(BlockSet blocks) {
|
public void onBlocksPlaced(BlockSet blocks) {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class RenderHandler {
|
|||||||
renderSubText(event.getPoseStack());
|
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 ChatFormatting normalColor = ChatFormatting.WHITE;
|
||||||
private static final Component placingText = Component.literal(
|
private static final Component placingText = Component.literal(
|
||||||
normalColor + "Left-click to " + highlightColor + "cancel, " +
|
normalColor + "Left-click to " + highlightColor + "cancel, " +
|
||||||
@@ -66,10 +66,10 @@ public class RenderHandler {
|
|||||||
normalColor + "Right-click to " + highlightColor + "cancel");
|
normalColor + "Right-click to " + highlightColor + "cancel");
|
||||||
|
|
||||||
private static void renderSubText(PoseStack ms) {
|
private static void renderSubText(PoseStack ms) {
|
||||||
var state = EffortlessBuildingClient.BUILDER_CHAIN.getState();
|
var state = EffortlessBuildingClient.BUILDER_CHAIN.getBuildingState();
|
||||||
if (state == BuilderChain.State.IDLE) return;
|
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 screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth();
|
||||||
int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight();
|
int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight();
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package nl.requios.effortlessbuilding.systems;
|
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.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
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.IsQuickReplacingPacket;
|
||||||
import nl.requios.effortlessbuilding.network.PacketHandler;
|
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||||
|
|
||||||
@@ -12,56 +10,57 @@ import nl.requios.effortlessbuilding.network.PacketHandler;
|
|||||||
public class BuildSettings {
|
public class BuildSettings {
|
||||||
public enum ReplaceMode {
|
public enum ReplaceMode {
|
||||||
ONLY_AIR,
|
ONLY_AIR,
|
||||||
SOLID_AND_AIR,
|
BLOCKS_AND_AIR,
|
||||||
SOLID_ONLY,
|
ONLY_BLOCKS,
|
||||||
FILTERED_BY_OFFHAND
|
FILTERED_BY_OFFHAND
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean quickReplace = false;
|
private ReplaceMode replaceMode = ReplaceMode.ONLY_AIR;
|
||||||
public ReplaceMode replaceMode = ReplaceMode.ONLY_AIR;
|
private boolean protectTileEntities = true;
|
||||||
private boolean replaceTileEntities;
|
|
||||||
|
|
||||||
public boolean isQuickReplacing() {
|
public boolean isQuickReplacing() {
|
||||||
return quickReplace;
|
return replaceMode != ReplaceMode.ONLY_AIR;
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReplaceMode(ReplaceMode replaceMode) {
|
public void setReplaceMode(ReplaceMode replaceMode) {
|
||||||
this.replaceMode = replaceMode;
|
this.replaceMode = replaceMode;
|
||||||
|
PacketHandler.INSTANCE.sendToServer(new IsQuickReplacingPacket(isQuickReplacing()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReplaceTileEntities(boolean replaceTileEntities) {
|
public ReplaceMode getReplaceMode() {
|
||||||
this.replaceTileEntities = replaceTileEntities;
|
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() {
|
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() {
|
public boolean shouldReplaceBlocks() {
|
||||||
return replaceMode == ReplaceMode.SOLID_ONLY || replaceMode == ReplaceMode.SOLID_AND_AIR;
|
return replaceMode == ReplaceMode.ONLY_BLOCKS || replaceMode == ReplaceMode.BLOCKS_AND_AIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldReplaceFiltered() {
|
public boolean shouldReplaceFiltered() {
|
||||||
return replaceMode == ReplaceMode.FILTERED_BY_OFFHAND;
|
return replaceMode == ReplaceMode.FILTERED_BY_OFFHAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldReplaceTileEntities() {
|
public boolean shouldProtectTileEntities() {
|
||||||
return replaceTileEntities;
|
return protectTileEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldOffsetStartPosition() {
|
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 net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import nl.requios.effortlessbuilding.ClientEvents;
|
import nl.requios.effortlessbuilding.ClientEvents;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
|
import nl.requios.effortlessbuilding.buildmode.BuildModeEnum;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
||||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||||
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
|
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.network.ServerPlaceBlocksPacket;
|
||||||
import nl.requios.effortlessbuilding.utilities.*;
|
import nl.requios.effortlessbuilding.utilities.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
// Receives block placed events, then finds additional blocks we want to place through various systems,
|
// 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
|
// and then sends them to the server to be placed
|
||||||
@@ -38,42 +37,46 @@ import java.util.List;
|
|||||||
public class BuilderChain {
|
public class BuilderChain {
|
||||||
|
|
||||||
private final BlockSet blocks = new BlockSet();
|
private final BlockSet blocks = new BlockSet();
|
||||||
private boolean blockInHand;
|
|
||||||
private boolean lookingAtInteractiveObject;
|
|
||||||
private Item previousHeldItem;
|
private Item previousHeldItem;
|
||||||
private int soundTime = 0;
|
private int soundTime = 0;
|
||||||
|
private BlockEntry startPosForPlacing;
|
||||||
|
private BlockPos startPosForBreaking;
|
||||||
|
private BlockHitResult lookingAtNear;
|
||||||
|
|
||||||
public enum State {
|
public enum BuildingState {
|
||||||
IDLE,
|
IDLE,
|
||||||
PLACING,
|
PLACING,
|
||||||
BREAKING
|
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() {
|
public void onRightClick() {
|
||||||
if (lookingAtInteractiveObject) return;
|
if (abilitiesState != AbilitiesState.CAN_PLACE_AND_BREAK || buildingState == BuildingState.BREAKING) {
|
||||||
var player = Minecraft.getInstance().player;
|
|
||||||
|
|
||||||
if (state == State.BREAKING) {
|
|
||||||
cancel();
|
cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blockInHand) {
|
if (buildingState == BuildingState.IDLE) {
|
||||||
if (state == State.PLACING) cancel();
|
buildingState = BuildingState.PLACING;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == State.IDLE) {
|
|
||||||
state = State.PLACING;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var player = Minecraft.getInstance().player;
|
||||||
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
||||||
|
|
||||||
//Find out if we should place blocks now
|
//Find out if we should place blocks now
|
||||||
if (buildMode.instance.onClick(blocks)) {
|
if (buildMode.instance.onClick(blocks)) {
|
||||||
state = State.IDLE;
|
buildingState = BuildingState.IDLE;
|
||||||
|
|
||||||
if (!blocks.isEmpty()) {
|
if (!blocks.isEmpty()) {
|
||||||
EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksPlaced(blocks);
|
EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksPlaced(blocks);
|
||||||
@@ -85,28 +88,29 @@ public class BuilderChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onLeftClick() {
|
public void onLeftClick() {
|
||||||
if (lookingAtInteractiveObject) return;
|
if (abilitiesState == AbilitiesState.NONE || buildingState == BuildingState.PLACING) {
|
||||||
var player = Minecraft.getInstance().player;
|
|
||||||
|
|
||||||
if (state == State.PLACING) {
|
|
||||||
cancel();
|
cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var player = Minecraft.getInstance().player;
|
||||||
if (!ReachHelper.canBreakFar(player)) return;
|
if (!ReachHelper.canBreakFar(player)) return;
|
||||||
|
|
||||||
if (state == State.IDLE){
|
if (buildingState == BuildingState.IDLE){
|
||||||
state = State.BREAKING;
|
buildingState = BuildingState.BREAKING;
|
||||||
|
|
||||||
//Recalculate block positions, because start position has changed
|
//Use new start position for breaking, because we assumed the player was gonna place
|
||||||
onTick();
|
blocks.setStartPos(new BlockEntry(startPosForBreaking));
|
||||||
|
BuilderFilter.filterOnCoordinates(blocks, player);
|
||||||
|
findExistingBlockStates(player.level);
|
||||||
|
BuilderFilter.filterOnExistingBlockStates(blocks, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
||||||
|
|
||||||
//Find out if we should break blocks now
|
//Find out if we should break blocks now
|
||||||
if (buildMode.instance.onClick(blocks)) {
|
if (buildMode.instance.onClick(blocks)) {
|
||||||
state = State.IDLE;
|
buildingState = BuildingState.IDLE;
|
||||||
|
|
||||||
if (!blocks.isEmpty()) {
|
if (!blocks.isEmpty()) {
|
||||||
EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksBroken(blocks);
|
EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksBroken(blocks);
|
||||||
@@ -120,40 +124,45 @@ public class BuilderChain {
|
|||||||
public void onTick() {
|
public void onTick() {
|
||||||
var previousCoordinates = new HashSet<>(blocks.getCoordinates());
|
var previousCoordinates = new HashSet<>(blocks.getCoordinates());
|
||||||
blocks.clear();
|
blocks.clear();
|
||||||
|
startPosForPlacing = null;
|
||||||
|
startPosForBreaking = null;
|
||||||
|
lookingAtNear = null;
|
||||||
|
|
||||||
var mc = Minecraft.getInstance();
|
var mc = Minecraft.getInstance();
|
||||||
var player = mc.player;
|
var player = mc.player;
|
||||||
var world = mc.level;
|
var world = mc.level;
|
||||||
|
|
||||||
//Check if we have a BlockItem in hand
|
abilitiesState = determineAbilities(mc, player, world);
|
||||||
var itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
|
if (abilitiesState == AbilitiesState.NONE) return;
|
||||||
blockInHand = CompatHelper.isItemBlockProxy(itemStack);
|
|
||||||
|
|
||||||
lookingAtInteractiveObject = BlockUtilities.determineIfLookingAtInteractiveObject(mc, world);
|
|
||||||
if (lookingAtInteractiveObject) return;
|
|
||||||
|
|
||||||
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
||||||
var modifierSettings = ModifierSettingsManager.getModifierSettings(player);
|
var modifierSettings = ModifierSettingsManager.getModifierSettings(player);
|
||||||
|
|
||||||
if (state == State.IDLE) {
|
if (buildingState == BuildingState.IDLE) {
|
||||||
//Find start position
|
//Find start position
|
||||||
BlockHitResult lookingAt = ClientEvents.getLookingAtFar(player);
|
BlockEntry startEntry = findStartPosition(player, buildMode);
|
||||||
BlockEntry startEntry = findStartPosition(player, lookingAt);
|
|
||||||
if (startEntry != null) {
|
if (startEntry != null) {
|
||||||
blocks.add(startEntry);
|
blocks.setStartPos(startEntry);
|
||||||
blocks.firstPos = startEntry.blockPos;
|
} else {
|
||||||
blocks.lastPos = startEntry.blockPos;
|
//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_MODES.findCoordinates(blocks, player, buildMode);
|
||||||
EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player, modifierSettings);
|
EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player, modifierSettings);
|
||||||
|
|
||||||
BuilderFilter.filterOnCoordinates(blocks, player);
|
BuilderFilter.filterOnCoordinates(blocks, player);
|
||||||
|
|
||||||
|
if (buildMode == BuildModeEnum.DISABLED && blocks.size() <= 1) {
|
||||||
|
abilitiesState = AbilitiesState.NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
findExistingBlockStates(world);
|
findExistingBlockStates(world);
|
||||||
BuilderFilter.filterOnExistingBlockStates(blocks, player);
|
BuilderFilter.filterOnExistingBlockStates(blocks, player);
|
||||||
|
|
||||||
|
var itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
|
||||||
findNewBlockStates(player, itemStack);
|
findNewBlockStates(player, itemStack);
|
||||||
BuilderFilter.filterOnNewBlockStates(blocks, player);
|
BuilderFilter.filterOnNewBlockStates(blocks, player);
|
||||||
|
|
||||||
@@ -165,6 +174,28 @@ public class BuilderChain {
|
|||||||
previousHeldItem = itemStack.getItem();
|
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) {
|
private void onBlocksChanged(Player player) {
|
||||||
|
|
||||||
//Renew randomness of randomizer bag
|
//Renew randomness of randomizer bag
|
||||||
@@ -177,64 +208,77 @@ public class BuilderChain {
|
|||||||
if (blocks.getLastBlockEntry() != null && blocks.getLastBlockEntry().newBlockState != null) {
|
if (blocks.getLastBlockEntry() != null && blocks.getLastBlockEntry().newBlockState != null) {
|
||||||
var lastBlockState = blocks.getLastBlockEntry().newBlockState;
|
var lastBlockState = blocks.getLastBlockEntry().newBlockState;
|
||||||
SoundType soundType = lastBlockState.getBlock().getSoundType(lastBlockState, player.level, blocks.lastPos, player);
|
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);
|
player.level.playSound(player, player.blockPosition(), soundEvent, SoundSource.BLOCKS, 0.3f, 0.8f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
if (state == State.IDLE) return;
|
if (buildingState == BuildingState.IDLE) return;
|
||||||
state = State.IDLE;
|
buildingState = BuildingState.IDLE;
|
||||||
EffortlessBuildingClient.BUILD_MODES.onCancel();
|
EffortlessBuildingClient.BUILD_MODES.onCancel();
|
||||||
Minecraft.getInstance().player.playSound(SoundEvents.UI_TOAST_OUT, 4, 1);
|
Minecraft.getInstance().player.playSound(SoundEvents.UI_TOAST_OUT, 4, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlockEntry findStartPosition(Player player, BlockHitResult lookingAtFar) {
|
private BlockEntry findStartPosition(Player player, BuildModeEnum buildMode) {
|
||||||
if (lookingAtFar == null || lookingAtFar.getType() == HitResult.Type.MISS) return null;
|
|
||||||
|
|
||||||
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
|
//Check if out of reach
|
||||||
int maxReach = ReachHelper.getMaxReach(player);
|
int maxReach = ReachHelper.getMaxReach(player);
|
||||||
if (player.blockPosition().distSqr(startPos) > maxReach * maxReach) return null;
|
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
|
startPosForBreaking = startPos;
|
||||||
if (state != State.BREAKING) {
|
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
|
//Offset in direction of sidehit if not quickreplace and not replaceable
|
||||||
boolean shouldOffsetStartPosition = EffortlessBuildingClient.BUILD_SETTINGS.shouldOffsetStartPosition();
|
boolean shouldOffsetStartPosition = EffortlessBuildingClient.BUILD_SETTINGS.shouldOffsetStartPosition();
|
||||||
boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable();
|
boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable();
|
||||||
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos);
|
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos);
|
||||||
if (!shouldOffsetStartPosition && !replaceable && !becomesDoubleSlab) {
|
if (!shouldOffsetStartPosition && !replaceable && !becomesDoubleSlab) {
|
||||||
startPos = startPos.relative(lookingAtFar.getDirection());
|
startPos = startPos.relative(lookingAt.getDirection());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get under tall grass and other replaceable blocks
|
//Get under tall grass and other replaceable blocks
|
||||||
if (shouldOffsetStartPosition && replaceable) {
|
if (shouldOffsetStartPosition && replaceable) {
|
||||||
startPos = startPos.below();
|
startPos = startPos.below();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
//We can only break
|
||||||
|
|
||||||
//Do not break far if we are not allowed to
|
//Do not break far if we are not allowed to
|
||||||
if (!ReachHelper.canBreakFar(player)) {
|
if (startPosForBreaking == null) return null;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var blockEntry = new BlockEntry(startPos);
|
var blockEntry = new BlockEntry(startPos);
|
||||||
|
|
||||||
//Place upside-down stairs if we aim high at block
|
//Place upside-down stairs if we aim high at block
|
||||||
var hitVec = lookingAtFar.getLocation();
|
var hitVec = lookingAt.getLocation();
|
||||||
//Format hitvec to 0.x
|
//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)));
|
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) {
|
if (hitVec.y > 0.5) {
|
||||||
blockEntry.mirrorY = true;
|
blockEntry.mirrorY = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startPosForPlacing = blockEntry;
|
||||||
|
|
||||||
return blockEntry;
|
return blockEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +289,7 @@ public class BuilderChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void findNewBlockStates(Player player, ItemStack itemStack) {
|
private void findNewBlockStates(Player player, ItemStack itemStack) {
|
||||||
if (state == State.BREAKING) return;
|
if (buildingState == BuildingState.BREAKING) return;
|
||||||
|
|
||||||
if (itemStack.getItem() instanceof BlockItem) {
|
if (itemStack.getItem() instanceof BlockItem) {
|
||||||
|
|
||||||
@@ -264,20 +308,39 @@ public class BuilderChain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public State getState() {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockSet getBlocks() {
|
public BlockSet getBlocks() {
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBlockInHand() {
|
public BuildingState getBuildingState() {
|
||||||
return blockInHand;
|
return buildingState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLookingAtInteractiveObject() {
|
public AbilitiesState getAbilitiesState() {
|
||||||
return lookingAtInteractiveObject;
|
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 net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||||
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
|
||||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||||
import nl.requios.effortlessbuilding.utilities.PlaceChecker;
|
import nl.requios.effortlessbuilding.utilities.PlaceChecker;
|
||||||
|
|
||||||
@@ -17,7 +16,8 @@ public class BuilderFilter {
|
|||||||
|
|
||||||
public static void filterOnExistingBlockStates(BlockSet blocks, Player player) {
|
public static void filterOnExistingBlockStates(BlockSet blocks, Player player) {
|
||||||
var buildSettings = EffortlessBuildingClient.BUILD_SETTINGS;
|
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();
|
var iter = blocks.entrySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
@@ -25,12 +25,13 @@ public class BuilderFilter {
|
|||||||
var blockState = blockEntry.existingBlockState;
|
var blockState = blockEntry.existingBlockState;
|
||||||
boolean remove = false;
|
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;
|
if (!buildSettings.shouldReplaceAir() && blockState.isAir()) remove = true;
|
||||||
boolean isSolid = blockState.isRedstoneConductor(player.level, blockEntry.blockPos);
|
boolean isReplaceable = blockState.getMaterial().isReplaceable();
|
||||||
if (!buildSettings.shouldReplaceSolid() && isSolid) remove = true;
|
// boolean isSolid = blockState.isRedstoneConductor(player.level, blockEntry.blockPos);
|
||||||
|
if (!buildSettings.shouldReplaceBlocks() && !isReplaceable) remove = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buildSettings.shouldReplaceFiltered()) {
|
if (buildSettings.shouldReplaceFiltered()) {
|
||||||
@@ -43,13 +44,16 @@ public class BuilderFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void filterOnNewBlockStates(BlockSet blocks, Player player) {
|
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();
|
var iter = blocks.entrySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
var blockEntry = iter.next().getValue();
|
var blockEntry = iter.next().getValue();
|
||||||
boolean remove = false;
|
boolean remove = false;
|
||||||
|
|
||||||
if (!PlaceChecker.shouldPlaceBlock(player.level, blockEntry)) remove = true;
|
if (placing && !PlaceChecker.shouldPlaceBlock(player.level, blockEntry)) remove = true;
|
||||||
|
|
||||||
if (remove) iter.remove();
|
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.Level;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.UndoRedoBlockSet;
|
import nl.requios.effortlessbuilding.utilities.UndoRedoBlockSet;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
|
|
||||||
import nl.requios.effortlessbuilding.utilities.InventoryHelper;
|
import nl.requios.effortlessbuilding.utilities.InventoryHelper;
|
||||||
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class ServerBlockPlacer {
|
|||||||
private boolean isPlacingOrBreakingBlocks = false;
|
private boolean isPlacingOrBreakingBlocks = false;
|
||||||
|
|
||||||
public void placeBlocks(Player player, BlockSet blocks) {
|
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) {
|
for (BlockEntry block : blocks) {
|
||||||
placeBlock(player, block);
|
placeBlock(player, block);
|
||||||
@@ -47,7 +47,7 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void breakBlocks(Player player, BlockSet blocks) {
|
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) {
|
for (BlockEntry block : blocks) {
|
||||||
breakBlock(player, block);
|
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_USING_BUILD_MODE_KEY = EffortlessBuilding.MODID + ":isUsingBuildMode";
|
||||||
private static final String IS_QUICK_REPLACING_KEY = EffortlessBuilding.MODID + ":isQuickReplacing";
|
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) {
|
public static boolean isUsingBuildMode(Player player) {
|
||||||
return player.getPersistentData().contains(IS_USING_BUILD_MODE_KEY);
|
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.Block;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
@@ -10,12 +10,14 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import nl.requios.effortlessbuilding.CommonConfig;
|
import nl.requios.effortlessbuilding.CommonConfig;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.UndoRedoBlockSet;
|
||||||
import nl.requios.effortlessbuilding.utilities.FixedStack;
|
import nl.requios.effortlessbuilding.utilities.FixedStack;
|
||||||
import nl.requios.effortlessbuilding.utilities.InventoryHelper;
|
import nl.requios.effortlessbuilding.utilities.InventoryHelper;
|
||||||
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
//Server only
|
||||||
public class UndoRedo {
|
public class UndoRedo {
|
||||||
|
|
||||||
//Undo and redo stacks per player
|
//Undo and redo stacks per player
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package nl.requios.effortlessbuilding.utilities;
|
package nl.requios.effortlessbuilding.utilities;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.nbt.NbtUtils;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
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 nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ import java.util.HashSet;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
//Common
|
||||||
public class BlockSet extends HashMap<BlockPos, BlockEntry> implements Iterable<BlockEntry> {
|
public class BlockSet extends HashMap<BlockPos, BlockEntry> implements Iterable<BlockEntry> {
|
||||||
public static boolean logging = true;
|
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) {
|
public void add(BlockEntry blockEntry) {
|
||||||
if (!containsKey(blockEntry.blockPos)) {
|
if (!containsKey(blockEntry.blockPos)) {
|
||||||
|
if (!DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> ClientSide.isFull(this))) {
|
||||||
//Limit number of blocks you can place
|
put(blockEntry.blockPos, blockEntry);
|
||||||
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(Minecraft.getInstance().player);
|
|
||||||
if (size() >= limit) {
|
|
||||||
if (logging) EffortlessBuilding.log("BlockSet limit reached, not adding block at " + blockEntry.blockPos);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
put(blockEntry.blockPos, blockEntry);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (logging) EffortlessBuilding.log("BlockSet already contains block at " + blockEntry.blockPos);
|
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) {
|
public static BlockSet decode(FriendlyByteBuf buf) {
|
||||||
return new BlockSet(buf.readList(BlockEntry::decode));
|
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;
|
package nl.requios.effortlessbuilding.utilities;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.sounds.SoundEvent;
|
import net.minecraft.sounds.SoundEvent;
|
||||||
import net.minecraft.sounds.SoundSource;
|
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.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
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.Block;
|
||||||
import net.minecraft.world.level.block.SoundType;
|
import net.minecraft.world.level.block.SoundType;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
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.HitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
//Common
|
||||||
public class BlockUtilities {
|
public class BlockUtilities {
|
||||||
|
|
||||||
public static BlockState getBlockState(Player player, InteractionHand hand, ItemStack blockItemStack, BlockEntry blockEntry) {
|
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));
|
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
|
//Check if we are looking at an interactive object
|
||||||
var result = false;
|
var result = false;
|
||||||
if (mc.hitResult != null) {
|
if (mc.hitResult != null) {
|
||||||
|
|||||||
@@ -17,13 +17,16 @@ public class PlaceChecker {
|
|||||||
|
|
||||||
//SchematicPrinter::shouldPlaceBlock
|
//SchematicPrinter::shouldPlaceBlock
|
||||||
public static boolean shouldPlaceBlock(Level world, BlockEntry blockEntry) {
|
public static boolean shouldPlaceBlock(Level world, BlockEntry blockEntry) {
|
||||||
if (world == null)
|
if (world == null || blockEntry == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var pos = blockEntry.blockPos;
|
var pos = blockEntry.blockPos;
|
||||||
var state = blockEntry.newBlockState;
|
var state = blockEntry.newBlockState;
|
||||||
BlockEntity tileEntity = null;
|
BlockEntity tileEntity = null;
|
||||||
|
|
||||||
|
if (state == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
BlockState toReplace = world.getBlockState(pos);
|
BlockState toReplace = world.getBlockState(pos);
|
||||||
BlockEntity toReplaceTE = world.getBlockEntity(pos);
|
BlockEntity toReplaceTE = world.getBlockEntity(pos);
|
||||||
BlockState toReplaceOther = null;
|
BlockState toReplaceOther = null;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import nl.requios.effortlessbuilding.CommonConfig;
|
|||||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||||
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
|
||||||
|
|
||||||
|
//Common
|
||||||
public class ReachHelper {
|
public class ReachHelper {
|
||||||
private static final String REACH_UPGRADE_KEY = EffortlessBuilding.MODID + ":reachUpgrade";
|
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.world.level.block.state.BlockState;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
//Used only for Undo
|
//Server only
|
||||||
|
@Deprecated
|
||||||
public class UndoRedoBlockSet {
|
public class UndoRedoBlockSet {
|
||||||
private final List<BlockPos> coordinates;
|
private final List<BlockPos> coordinates;
|
||||||
private final List<BlockState> previousBlockStates;
|
private final List<BlockState> previousBlockStates;
|
||||||
@@ -1,79 +1,87 @@
|
|||||||
{
|
{
|
||||||
"effortlessbuilding.screen.modifier_settings": "Modifier Settings",
|
"effortlessbuilding.screen.modifier_settings": "Modifier Settings",
|
||||||
"effortlessbuilding.screen.radial_menu": "Build Modes",
|
"effortlessbuilding.screen.radial_menu": "Build Modes",
|
||||||
"effortlessbuilding.screen.player_settings": "Player Settings",
|
"effortlessbuilding.screen.player_settings": "Player Settings",
|
||||||
|
|
||||||
"key.effortlessbuilding.category": "Effortless Building",
|
"key.effortlessbuilding.category": "Effortless Building",
|
||||||
"key.effortlessbuilding.hud.desc": "Modifier Menu",
|
"key.effortlessbuilding.hud.desc": "Modifier Menu",
|
||||||
"key.effortlessbuilding.replace.desc": "Toggle QuickReplace",
|
"key.effortlessbuilding.replace.desc": "Toggle QuickReplace",
|
||||||
"key.effortlessbuilding.mode.desc": "Radial Menu",
|
"key.effortlessbuilding.mode.desc": "Radial Menu",
|
||||||
"key.effortlessbuilding.undo.desc": "Undo",
|
"key.effortlessbuilding.undo.desc": "Undo",
|
||||||
"key.effortlessbuilding.redo.desc": "Redo",
|
"key.effortlessbuilding.redo.desc": "Redo",
|
||||||
"key.effortlessbuilding.altplacement.desc": "Alternative placement",
|
"key.effortlessbuilding.altplacement.desc": "Alternative placement",
|
||||||
|
|
||||||
"item.effortlessbuilding.randomizer_bag": "Leather Randomizer Bag",
|
"item.effortlessbuilding.randomizer_bag": "Leather Randomizer Bag",
|
||||||
"item.effortlessbuilding.golden_randomizer_bag": "Golden Randomizer Bag",
|
"item.effortlessbuilding.golden_randomizer_bag": "Golden Randomizer Bag",
|
||||||
"item.effortlessbuilding.diamond_randomizer_bag": "Diamond Randomizer Bag",
|
"item.effortlessbuilding.diamond_randomizer_bag": "Diamond Randomizer Bag",
|
||||||
"item.effortlessbuilding.reach_upgrade1": "Reach Upgrade 1",
|
"item.effortlessbuilding.reach_upgrade1": "Reach Upgrade 1",
|
||||||
"item.effortlessbuilding.reach_upgrade2": "Reach Upgrade 2",
|
"item.effortlessbuilding.reach_upgrade2": "Reach Upgrade 2",
|
||||||
"item.effortlessbuilding.reach_upgrade3": "Reach Upgrade 3",
|
"item.effortlessbuilding.reach_upgrade3": "Reach Upgrade 3",
|
||||||
|
|
||||||
"effortlessbuilding.mode.normal": "Disable",
|
"effortlessbuilding.mode.normal": "Disable",
|
||||||
"effortlessbuilding.mode.normal_plus": "Single",
|
"effortlessbuilding.mode.normal_plus": "Single",
|
||||||
"effortlessbuilding.mode.line": "Line",
|
"effortlessbuilding.mode.line": "Line",
|
||||||
"effortlessbuilding.mode.wall": "Wall",
|
"effortlessbuilding.mode.wall": "Wall",
|
||||||
"effortlessbuilding.mode.floor": "Floor",
|
"effortlessbuilding.mode.floor": "Floor",
|
||||||
"effortlessbuilding.mode.diagonal_line": "Diagonal Line",
|
"effortlessbuilding.mode.diagonal_line": "Diagonal Line",
|
||||||
"effortlessbuilding.mode.diagonal_wall": "Diagonal Wall",
|
"effortlessbuilding.mode.diagonal_wall": "Diagonal Wall",
|
||||||
"effortlessbuilding.mode.slope_floor": "Slope Floor",
|
"effortlessbuilding.mode.slope_floor": "Slope Floor",
|
||||||
"effortlessbuilding.mode.cube": "Cube",
|
"effortlessbuilding.mode.cube": "Cube",
|
||||||
"effortlessbuilding.mode.circle": "Circle",
|
"effortlessbuilding.mode.circle": "Circle",
|
||||||
"effortlessbuilding.mode.cylinder": "Cylinder",
|
"effortlessbuilding.mode.cylinder": "Cylinder",
|
||||||
"effortlessbuilding.mode.sphere": "Sphere",
|
"effortlessbuilding.mode.sphere": "Sphere",
|
||||||
"effortlessbuilding.mode.pyramid": "Pyramid",
|
"effortlessbuilding.mode.pyramid": "Pyramid",
|
||||||
"effortlessbuilding.mode.cone": "Cone",
|
"effortlessbuilding.mode.cone": "Cone",
|
||||||
"effortlessbuilding.mode.dome": "Dome",
|
"effortlessbuilding.mode.dome": "Dome",
|
||||||
|
|
||||||
"effortlessbuilding.modedescription.normal": "Disable mod and use vanilla placement rules",
|
"effortlessbuilding.modedescription.normal": "Disable mod and use vanilla placement rules",
|
||||||
"effortlessbuilding.modedescription.normal_plus": "Like vanilla, but with increased reach and placement preview",
|
"effortlessbuilding.modedescription.normal_plus": "Like vanilla, but with increased reach and placement preview",
|
||||||
"effortlessbuilding.modedescription.line": "",
|
"effortlessbuilding.modedescription.line": "",
|
||||||
"effortlessbuilding.modedescription.wall": "",
|
"effortlessbuilding.modedescription.wall": "",
|
||||||
"effortlessbuilding.modedescription.floor": "",
|
"effortlessbuilding.modedescription.floor": "",
|
||||||
"effortlessbuilding.modedescription.diagonal_line": "",
|
"effortlessbuilding.modedescription.diagonal_line": "",
|
||||||
"effortlessbuilding.modedescription.diagonal_wall": "",
|
"effortlessbuilding.modedescription.diagonal_wall": "",
|
||||||
"effortlessbuilding.modedescription.slope_floor": "",
|
"effortlessbuilding.modedescription.slope_floor": "",
|
||||||
"effortlessbuilding.modedescription.cube": "",
|
"effortlessbuilding.modedescription.cube": "",
|
||||||
"effortlessbuilding.modedescription.circle": "",
|
"effortlessbuilding.modedescription.circle": "",
|
||||||
"effortlessbuilding.modedescription.cylinder": "",
|
"effortlessbuilding.modedescription.cylinder": "",
|
||||||
"effortlessbuilding.modedescription.sphere": "",
|
"effortlessbuilding.modedescription.sphere": "",
|
||||||
"effortlessbuilding.modedescription.pyramid": "",
|
"effortlessbuilding.modedescription.pyramid": "",
|
||||||
"effortlessbuilding.modedescription.cone": "",
|
"effortlessbuilding.modedescription.cone": "",
|
||||||
"effortlessbuilding.modedescription.dome": "",
|
"effortlessbuilding.modedescription.dome": "",
|
||||||
|
|
||||||
"effortlessbuilding.action.undo": "Undo",
|
"effortlessbuilding.action.undo": "Undo",
|
||||||
"effortlessbuilding.action.redo": "Redo",
|
"effortlessbuilding.action.redo": "Redo",
|
||||||
"effortlessbuilding.action.replace": "Replace",
|
"effortlessbuilding.action.open_modifier_settings": "Open Modifier Settings",
|
||||||
"effortlessbuilding.action.open_modifier_settings": "Open Modifier Settings",
|
"effortlessbuilding.action.open_player_settings": "Open Build Settings",
|
||||||
"effortlessbuilding.action.open_player_settings": "Open Settings",
|
|
||||||
|
|
||||||
"effortlessbuilding.action.build_speed": "Build Speed",
|
"effortlessbuilding.action.replace_only_air": "Don't Replace Blocks",
|
||||||
"effortlessbuilding.action.filling": "Filling",
|
"effortlessbuilding.action.replace_only_air.description": "You will only place blocks where there is no block already. Replaceables such as grass will still be replaced.",
|
||||||
"effortlessbuilding.action.raised_edge": "Raised Edge",
|
"effortlessbuilding.action.replace_blocks_and_air": "Replace Blocks And Air",
|
||||||
"effortlessbuilding.action.thickness": "Line Thickness",
|
"effortlessbuilding.action.replace_blocks_and_air.description": "You will replace blocks and air.",
|
||||||
"effortlessbuilding.action.circle_start": "Start Point",
|
"effortlessbuilding.action.replace_only_blocks": "Replace Only Blocks",
|
||||||
|
"effortlessbuilding.action.replace_only_blocks.description": "You will only replace blocks, not air.",
|
||||||
|
"effortlessbuilding.action.replace_filtered_by_offhand": "Filter By Offhand",
|
||||||
|
"effortlessbuilding.action.replace_filtered_by_offhand.description": "You will only replace blocks that match the block in your offhand. If you don't have a block in your offhand, you will only replace air. If you have a randomizer bag in your offhand, you will only replace blocks that are contained in the bag.",
|
||||||
|
"effortlessbuilding.action.toggle_protect_tile_entities": "Protect Tile Entities",
|
||||||
|
"effortlessbuilding.action.toggle_protect_tile_entities.description": "Blocks that hold data such as chests, furnaces, and hoppers will not be replaced.",
|
||||||
|
|
||||||
"effortlessbuilding.action.normal_speed": "Normal",
|
"effortlessbuilding.action.build_speed": "Build Speed",
|
||||||
"effortlessbuilding.action.fast_speed": "Fast",
|
"effortlessbuilding.action.filling": "Filling",
|
||||||
"effortlessbuilding.action.full": "Filled",
|
"effortlessbuilding.action.raised_edge": "Raised Edge",
|
||||||
"effortlessbuilding.action.hollow": "Hollow",
|
"effortlessbuilding.action.thickness": "Line Thickness",
|
||||||
"effortlessbuilding.action.skeleton": "Skeleton",
|
"effortlessbuilding.action.circle_start": "Start Point",
|
||||||
"effortlessbuilding.action.short_edge": "Short Edge",
|
|
||||||
"effortlessbuilding.action.long_edge": "Long Edge",
|
|
||||||
"effortlessbuilding.action.thickness_1": "1 Block Thick",
|
|
||||||
"effortlessbuilding.action.thickness_3": "3 Blocks Thick",
|
|
||||||
"effortlessbuilding.action.thickness_5": "5 Blocks Thick",
|
|
||||||
"effortlessbuilding.action.start_center": "Middle",
|
|
||||||
"effortlessbuilding.action.start_corner": "Corner",
|
|
||||||
|
|
||||||
"commands.reach.usage": "/reach <level>"
|
"effortlessbuilding.action.normal_speed": "Normal",
|
||||||
|
"effortlessbuilding.action.fast_speed": "Fast",
|
||||||
|
"effortlessbuilding.action.full": "Filled",
|
||||||
|
"effortlessbuilding.action.hollow": "Hollow",
|
||||||
|
"effortlessbuilding.action.skeleton": "Skeleton",
|
||||||
|
"effortlessbuilding.action.short_edge": "Short Edge",
|
||||||
|
"effortlessbuilding.action.long_edge": "Long Edge",
|
||||||
|
"effortlessbuilding.action.thickness_1": "1 Block Thick",
|
||||||
|
"effortlessbuilding.action.thickness_3": "3 Blocks Thick",
|
||||||
|
"effortlessbuilding.action.thickness_5": "5 Blocks Thick",
|
||||||
|
"effortlessbuilding.action.start_center": "Middle",
|
||||||
|
"effortlessbuilding.action.start_corner": "Corner"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user