Fixed redo and running on server.

This commit is contained in:
Christian Knaapen
2023-02-08 20:34:05 +01:00
parent df1efef63b
commit a7dd0823e1
6 changed files with 74 additions and 44 deletions

View File

@@ -40,14 +40,13 @@ public class ClientEvents {
EffortlessBuilding.log("Registering KeyMappings!"); EffortlessBuilding.log("Registering KeyMappings!");
// register key bindings // register key bindings
keyBindings = new KeyMapping[5]; keyBindings = new KeyMapping[4];
// instantiate the key bindings // instantiate the key bindings
keyBindings[0] = new KeyMapping("key.effortlessbuilding.mode.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_ALT, 0), "key.effortlessbuilding.category"); keyBindings[0] = new KeyMapping("key.effortlessbuilding.mode.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_ALT, 0), "key.effortlessbuilding.category");
keyBindings[1] = new KeyMapping("key.effortlessbuilding.hud.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_KP_ADD, 0), "key.effortlessbuilding.category"); keyBindings[1] = new KeyMapping("key.effortlessbuilding.hud.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_KP_ADD, 0), "key.effortlessbuilding.category");
keyBindings[2] = new KeyMapping("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Z, 0), "key.effortlessbuilding.category"); keyBindings[2] = new KeyMapping("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Z, 0), "key.effortlessbuilding.category");
keyBindings[3] = new KeyMapping("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Y, 0), "key.effortlessbuilding.category"); keyBindings[3] = new KeyMapping("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Y, 0), "key.effortlessbuilding.category");
keyBindings[4] = new KeyMapping("key.effortlessbuilding.altplacement.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_CONTROL, 0), "key.effortlessbuilding.category");
for (KeyMapping keyBinding : keyBindings) { for (KeyMapping keyBinding : keyBindings) {
event.register(keyBinding); event.register(keyBinding);
@@ -159,23 +158,6 @@ public class ClientEvents {
if (keyBindings[3].consumeClick()) { if (keyBindings[3].consumeClick()) {
ModeOptions.performAction(player, ModeOptions.ActionEnum.REDO); ModeOptions.performAction(player, ModeOptions.ActionEnum.REDO);
} }
//Change placement mode
if (keyBindings[4].isDown()) {
//Toggle between first two actions of the first option of the current build mode
BuildModeEnum currentBuildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
if (currentBuildMode.options.length > 0) {
ModeOptions.OptionEnum option = currentBuildMode.options[0];
if (option.actions.length >= 2) {
if (ModeOptions.getOptionSetting(option) == option.actions[0]) {
ModeOptions.performAction(player, option.actions[1]);
} else {
ModeOptions.performAction(player, option.actions[0]);
}
}
}
}
} }
public static void openModifierSettings() { public static void openModifierSettings() {

View File

@@ -19,7 +19,9 @@ import net.minecraft.world.phys.Vec3;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.network.NetworkHooks; import net.minecraftforge.network.NetworkHooks;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
@@ -206,10 +208,8 @@ public abstract class AbstractRandomizerBagItem extends Item {
@Override @Override
public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> tooltip, TooltipFlag flag) { public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> tooltip, TooltipFlag flag) {
tooltip.add(Component.literal(ChatFormatting.YELLOW + "*Experimental* Only works in singleplayer"));
tooltip.add(Component.literal(ChatFormatting.BLUE + "Rightclick" + ChatFormatting.GRAY + " to place a random block")); tooltip.add(Component.literal(ChatFormatting.BLUE + "Rightclick" + ChatFormatting.GRAY + " to place a random block"));
tooltip.add(Component.literal(ChatFormatting.BLUE + "Sneak + rightclick" + ChatFormatting.GRAY + " to open inventory")); tooltip.add(Component.literal(ChatFormatting.BLUE + "Sneak + rightclick" + ChatFormatting.GRAY + " to open inventory"));
if (world != null && world.players().size() > 1) {
tooltip.add(Component.literal(ChatFormatting.YELLOW + "Experimental on servers: may lose inventory"));
}
} }
} }

View File

@@ -66,11 +66,12 @@ public class ServerBlockPlacer {
undoSet.add(block); undoSet.add(block);
} }
} }
if (isAllowedToUndo(player, false))
EffortlessBuilding.UNDO_REDO.addUndo(player, undoSet); EffortlessBuilding.UNDO_REDO.addUndo(player, undoSet);
} }
public void undoBlockSet(Player player, BlockSet blocks) { public void undoBlockSet(Player player, BlockSet blocks) {
if (!isAllowedToUndo(player)) return; if (!isAllowedToUndo(player, true)) return;
var redoSet = new BlockSet(); var redoSet = new BlockSet();
for (BlockEntry block : blocks) { for (BlockEntry block : blocks) {
@@ -100,25 +101,27 @@ public class ServerBlockPlacer {
} }
private boolean undoBlockEntry(Player player, BlockEntry block) { private boolean undoBlockEntry(Player player, BlockEntry block) {
//Update newBlockState for future redo's
block.newBlockState = player.level.getBlockState(block.blockPos);
boolean breaking = BlockUtilities.isNullOrAir(block.existingBlockState); boolean breaking = BlockUtilities.isNullOrAir(block.existingBlockState);
var tempBlockEntry = new BlockEntry(block.blockPos); var tempBlockEntry = new BlockEntry(block.blockPos);
var newBlockState = block.existingBlockState; var temp = block.existingBlockState;
tempBlockEntry.existingBlockState = block.newBlockState; tempBlockEntry.existingBlockState = block.newBlockState;
tempBlockEntry.newBlockState = newBlockState; tempBlockEntry.newBlockState = temp;
if (!validateBlockEntry(player, tempBlockEntry, breaking)) return false; if (!validateBlockEntry(player, tempBlockEntry, breaking)) return false;
//Update newBlockState for future redo's
block.newBlockState = player.level.getBlockState(block.blockPos);
boolean success; boolean success;
isPlacingOrBreakingBlocks = true; isPlacingOrBreakingBlocks = true;
if (breaking) { if (breaking) {
success = BlockPlacerHelper.placeBlock(player, tempBlockEntry);
} else {
success = BlockPlacerHelper.breakBlock(player, tempBlockEntry); success = BlockPlacerHelper.breakBlock(player, tempBlockEntry);
} else {
success = BlockPlacerHelper.placeBlock(player, tempBlockEntry);
} }
isPlacingOrBreakingBlocks = false; isPlacingOrBreakingBlocks = false;
return success; return success;
} }
@@ -151,9 +154,9 @@ public class ServerBlockPlacer {
return true; return true;
} }
private boolean isAllowedToUndo(Player player) { private boolean isAllowedToUndo(Player player, boolean log) {
if (!player.isCreative()) { if (!player.isCreative()) {
EffortlessBuilding.log(player, ChatFormatting.RED + "Undo is not supported in survival mode."); if (log) EffortlessBuilding.log(player, ChatFormatting.RED + "Undo is not supported in survival mode.");
return false; return false;
} }
@@ -161,15 +164,30 @@ public class ServerBlockPlacer {
} }
private boolean validateBlockSet(Player player, BlockSet blocks) { private boolean validateBlockSet(Player player, BlockSet blocks) {
if (blocks.isEmpty()) {
EffortlessBuilding.log(player, ChatFormatting.RED + "No blocks to place.");
return false;
}
if (blocks.skipFirst && blocks.size() == 1 && blocks.iterator().next().blockPos == blocks.firstPos) {
EffortlessBuilding.log(player, ChatFormatting.RED + "No blocks to place because the first block was skipped.");
return false;
}
if (blocks.size() > ServerConfig.validation.maxBlocksPlacedAtOnce.get()) { if (blocks.size() > ServerConfig.validation.maxBlocksPlacedAtOnce.get()) {
EffortlessBuilding.log(player, ChatFormatting.RED + "Too many blocks to place. Max: " + ServerConfig.validation.maxBlocksPlacedAtOnce.get()); EffortlessBuilding.log(player, ChatFormatting.RED + "Too many blocks to place. Max: " + ServerConfig.validation.maxBlocksPlacedAtOnce.get());
return false; return false;
} }
//Dont allow mixing breaking and placing blocks //Dont allow mixing breaking and placing blocks
//TODO fix if skipping first block //First determine if we are breaking or placing
boolean breaking = blocks.getFirstBlockEntry().newBlockState == null || blocks.getFirstBlockEntry().newBlockState.isAir(); var iterator = blocks.iterator();
for (var iterator = blocks.iterator(); iterator.hasNext(); ) { //Get any block from the set, skip first if we have to
var anyBlock = iterator.next();
if (blocks.skipFirst && anyBlock.blockPos == blocks.firstPos) {
anyBlock = iterator.next();
}
boolean breaking = anyBlock.newBlockState == null || anyBlock.newBlockState.isAir();
while (iterator.hasNext()) {
var block = iterator.next(); var block = iterator.next();
if (block.newBlockState == null || block.newBlockState.isAir()) { if (block.newBlockState == null || block.newBlockState.isAir()) {
if (!breaking) { if (!breaking) {
@@ -183,6 +201,7 @@ public class ServerBlockPlacer {
} }
} }
} }
return true; return true;
} }

View File

@@ -1,5 +1,6 @@
package nl.requios.effortlessbuilding.systems; package nl.requios.effortlessbuilding.systems;
import net.minecraft.ChatFormatting;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
@@ -8,6 +9,7 @@ import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraftforge.common.util.BlockSnapshot;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.ServerConfig; import nl.requios.effortlessbuilding.ServerConfig;
import nl.requios.effortlessbuilding.utilities.*; import nl.requios.effortlessbuilding.utilities.*;
@@ -17,11 +19,27 @@ import java.util.*;
//Server only //Server only
public class UndoRedo { public class UndoRedo {
public class UndoSet {
public final List<BlockSnapshot> blockSnapshots;
public UndoSet(List<BlockSnapshot> blockSnapshots) {
this.blockSnapshots = blockSnapshots;
}
}
public final Map<UUID, FixedStack<BlockSet>> undoStacks = new HashMap<>(); public final Map<UUID, FixedStack<BlockSet>> undoStacks = new HashMap<>();
public final Map<UUID, FixedStack<BlockSet>> redoStacks = new HashMap<>(); public final Map<UUID, FixedStack<BlockSet>> redoStacks = new HashMap<>();
private boolean isAllowedToUndo(Player player) {
if (!player.isCreative()) {
return false;
}
return true;
}
public void addUndo(Player player, BlockSet blockSet) { public void addUndo(Player player, BlockSet blockSet) {
if (blockSet.isEmpty()) return; if (blockSet.isEmpty() || !isAllowedToUndo(player)) return;
//If no stack exists, make one //If no stack exists, make one
if (!undoStacks.containsKey(player.getUUID())) { if (!undoStacks.containsKey(player.getUUID())) {
@@ -32,7 +50,7 @@ public class UndoRedo {
} }
public void addRedo(Player player, BlockSet blockSet) { public void addRedo(Player player, BlockSet blockSet) {
if (blockSet.isEmpty()) return; if (blockSet.isEmpty() || !isAllowedToUndo(player)) return;
//If no stack exists, make one //If no stack exists, make one
if (!redoStacks.containsKey(player.getUUID())) { if (!redoStacks.containsKey(player.getUUID())) {
@@ -43,6 +61,11 @@ public class UndoRedo {
} }
public boolean undo(Player player) { public boolean undo(Player player) {
if (!isAllowedToUndo(player)) {
EffortlessBuilding.log(player, ChatFormatting.RED + "You are not allowed to undo.");
return false;
}
if (!undoStacks.containsKey(player.getUUID())) return false; if (!undoStacks.containsKey(player.getUUID())) return false;
FixedStack<BlockSet> undoStack = undoStacks.get(player.getUUID()); FixedStack<BlockSet> undoStack = undoStacks.get(player.getUUID());
@@ -55,6 +78,11 @@ public class UndoRedo {
} }
public boolean redo(Player player) { public boolean redo(Player player) {
if (!isAllowedToUndo(player)) {
EffortlessBuilding.log(player, ChatFormatting.RED + "You are not allowed to undo.");
return false;
}
if (!redoStacks.containsKey(player.getUUID())) return false; if (!redoStacks.containsKey(player.getUUID())) return false;
FixedStack<BlockSet> redoStack = redoStacks.get(player.getUUID()); FixedStack<BlockSet> redoStack = redoStacks.get(player.getUUID());

View File

@@ -47,7 +47,6 @@ public class BlockPlacerHelper {
return placeBlockWithoutItem(player, blockEntry); return placeBlockWithoutItem(player, blockEntry);
} else { } else {
var interactionResult = placeItem(player, blockEntry); var interactionResult = placeItem(player, blockEntry);
interactionResult.shouldSwing()
return interactionResult == InteractionResult.SUCCESS; return interactionResult == InteractionResult.SUCCESS;
} }
} }
@@ -106,10 +105,7 @@ public class BlockPlacerHelper {
ItemStack itemstack = block.itemStack; ItemStack itemstack = block.itemStack;
Level level = player.level; Level level = player.level;
if (player != null && !player.getAbilities().mayBuild) if (player != null && !player.getAbilities().mayBuild && !itemstack.hasAdventureModePlaceTagForBlock(level.registryAccess().registryOrThrow(Registry.BLOCK_REGISTRY), new BlockInWorld(level, block.blockPos, false)))
return InteractionResult.PASS;
if (itemstack != null && !itemstack.hasAdventureModePlaceTagForBlock(level.registryAccess().registryOrThrow(Registry.BLOCK_REGISTRY), new BlockInWorld(level, block.blockPos, false)))
return InteractionResult.PASS; return InteractionResult.PASS;
// handle all placement events here // handle all placement events here

View File

@@ -51,9 +51,14 @@ public class BlockSet extends HashMap<BlockPos, BlockEntry> implements Iterable<
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))) { //check if we are clientside
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
if (!ClientSide.isFull(this))
put(blockEntry.blockPos, blockEntry); put(blockEntry.blockPos, blockEntry);
} });
DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () -> {
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);
} }