Added server validation: allowInSurvival and whitelist.

Instantly placing blocksets of size 1.
Added server config and moved some config values around.
This commit is contained in:
Christian Knaapen
2023-02-03 21:14:29 +01:00
parent 589059fd44
commit bda0908731
9 changed files with 236 additions and 165 deletions

View File

@@ -2,18 +2,22 @@ package nl.requios.effortlessbuilding;
import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec;
import static net.minecraftforge.common.ForgeConfigSpec.*;
public class ClientConfig { public class ClientConfig {
private static final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder(); private static final Builder builder = new Builder();
public static final Visuals visuals = new Visuals(builder); public static final Visuals visuals = new Visuals(builder);
public static final ForgeConfigSpec spec = builder.build(); public static final ForgeConfigSpec spec = builder.build();
public static class Visuals { public static class Visuals {
public final ForgeConfigSpec.ConfigValue<Boolean> showBlockPreviews; public final BooleanValue showBlockPreviews;
public final ForgeConfigSpec.ConfigValue<Boolean> onlyShowBlockPreviewsWhenBuilding; public final BooleanValue onlyShowBlockPreviewsWhenBuilding;
public final ForgeConfigSpec.ConfigValue<Integer> maxBlockPreviews; public final IntValue maxBlockPreviews;
public final IntValue appearAnimationLength;
public final IntValue breakAnimationLength;
public Visuals(ForgeConfigSpec.Builder builder) { public Visuals(Builder builder) {
builder.push("Visuals"); builder.push("Visuals");
showBlockPreviews = builder showBlockPreviews = builder
@@ -27,8 +31,17 @@ public class ClientConfig {
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("maxBlockPreviews", 500); .defineInRange("maxBlockPreviews", 500, 0, 5000);
appearAnimationLength = builder
.comment("How long it takes for a block to appear when placed in ticks.",
"Set to 0 to disable animation.")
.defineInRange("appearAnimationLength", 5, 0, 100);
breakAnimationLength = builder
.comment("How long the break animation is in ticks.",
"Set to 0 to disable animation.")
.defineInRange("breakAnimationLength", 10, 0, 100);
builder.pop(); builder.pop();
} }

View File

@@ -3,23 +3,24 @@ package nl.requios.effortlessbuilding;
import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec;
import nl.requios.effortlessbuilding.create.foundation.render.SuperByteBufferCache; import nl.requios.effortlessbuilding.create.foundation.render.SuperByteBufferCache;
import static net.minecraftforge.common.ForgeConfigSpec.*;
public class CommonConfig { public class CommonConfig {
private static final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder(); private static final Builder builder = new Builder();
public static final Reach reach = new Reach(builder); public static final Reach reach = new Reach(builder);
public static final SurvivalBalancers survivalBalancers = new SurvivalBalancers(builder); public static final SurvivalBalancers survivalBalancers = new SurvivalBalancers(builder);
public static final Visuals visuals = new Visuals(builder);
public static final ForgeConfigSpec spec = builder.build(); public static final ForgeConfigSpec spec = builder.build();
public static class Reach { public static class Reach {
public final ForgeConfigSpec.ConfigValue<Boolean> enableReachUpgrades; public final BooleanValue enableReachUpgrades;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachCreative; public final IntValue maxReachCreative;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel0; public final IntValue maxReachLevel0;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel1; public final IntValue maxReachLevel1;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel2; public final IntValue maxReachLevel2;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel3; public final IntValue maxReachLevel3;
public Reach(ForgeConfigSpec.Builder builder) { public Reach(Builder builder) {
builder.push("Reach"); builder.push("Reach");
enableReachUpgrades = builder enableReachUpgrades = builder
.comment("Reach: how far away the player can place blocks using mirror/array etc.", .comment("Reach: how far away the player can place blocks using mirror/array etc.",
@@ -30,35 +31,34 @@ public class CommonConfig {
maxReachCreative = builder maxReachCreative = builder
.comment("Maximum reach in creative", .comment("Maximum reach in creative",
"Keep in mind that chunks need to be loaded to be able to place blocks inside.") "Keep in mind that chunks need to be loaded to be able to place blocks inside.")
.define("maxReachCreative", 200); .defineInRange("maxReachCreative", 200, 0, 1000);
maxReachLevel0 = builder maxReachLevel0 = builder
.comment("Maximum reach in survival without upgrades", .comment("Maximum reach in survival without upgrades",
"Reach upgrades are craftable consumables that permanently increase reach.", "Reach upgrades are craftable consumables that permanently increase reach.",
"Set to 0 to disable Effortless Building until the player has consumed a reach upgrade.") "Set to 0 to disable Effortless Building until the player has consumed a reach upgrade.")
.define("maxReachLevel0", 20); .defineInRange("maxReachLevel0", 20, 0, 1000);
maxReachLevel1 = builder maxReachLevel1 = builder
.comment("Maximum reach in survival with one upgrade") .comment("Maximum reach in survival with one upgrade")
.define("maxReachLevel1", 50); .defineInRange("maxReachLevel1", 50, 0, 1000);
maxReachLevel2 = builder maxReachLevel2 = builder
.comment("Maximum reach in survival with two upgrades") .comment("Maximum reach in survival with two upgrades")
.define("maxReachLevel2", 100); .defineInRange("maxReachLevel2", 100, 0, 1000);
maxReachLevel3 = builder maxReachLevel3 = builder
.comment("Maximum reach in survival with three upgrades") .comment("Maximum reach in survival with three upgrades")
.define("maxReachLevel3", 200); .defineInRange("maxReachLevel3", 200, 0, 1000);
builder.pop(); builder.pop();
} }
} }
public static class SurvivalBalancers { public static class SurvivalBalancers {
public final ForgeConfigSpec.ConfigValue<Integer> quickReplaceMiningLevel; public final IntValue quickReplaceMiningLevel;
public final ForgeConfigSpec.ConfigValue<Integer> undoStackSize;
public SurvivalBalancers(ForgeConfigSpec.Builder builder) { public SurvivalBalancers(Builder builder) {
builder.push("SurvivalBalancers"); builder.push("SurvivalBalancers");
quickReplaceMiningLevel = builder quickReplaceMiningLevel = builder
@@ -71,32 +71,6 @@ public class CommonConfig {
"4: blocks that can be harvested with netherite tools") "4: blocks that can be harvested with netherite tools")
.defineInRange("quickReplaceMiningLevel", -1, -1, 3); .defineInRange("quickReplaceMiningLevel", -1, -1, 3);
undoStackSize = builder
.comment("How many placements are remembered for the undo functionality.")
.worldRestart()
.define("undoStackSize", 50);
builder.pop();
}
}
public static class Visuals {
public final ForgeConfigSpec.ConfigValue<Integer> appearAnimationLength;
public final ForgeConfigSpec.ConfigValue<Integer> breakAnimationLength;
public Visuals(ForgeConfigSpec.Builder builder) {
builder.push("Visuals");
appearAnimationLength = builder
.comment("How long it takes for a block to appear when placed in ticks.",
"Set to 0 to disable animation.")
.define("appearAnimationLength", 5);
breakAnimationLength = builder
.comment("How long the break animation is in ticks.",
"Set to 0 to disable animation.")
.define("breakAnimationLength", 10);
builder.pop(); builder.pop();
} }
} }

View File

@@ -74,6 +74,7 @@ public class EffortlessBuilding {
//Register config //Register config
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, CommonConfig.spec); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, CommonConfig.spec);
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ClientConfig.spec); ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ClientConfig.spec);
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ServerConfig.spec);
} }
public static void setup(final FMLCommonSetupEvent event) { public static void setup(final FMLCommonSetupEvent event) {

View File

@@ -0,0 +1,55 @@
package nl.requios.effortlessbuilding;
import net.minecraftforge.common.ForgeConfigSpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static net.minecraftforge.common.ForgeConfigSpec.*;
public class ServerConfig {
private static final Builder builder = new Builder();
public static final ServerConfig.Validation validation = new ServerConfig.Validation(builder);
public static final ServerConfig.Memory memory = new ServerConfig.Memory(builder);
public static final ForgeConfigSpec spec = builder.build();
public static class Validation {
public final BooleanValue allowInSurvival;
public final BooleanValue useWhitelist;
public final ConfigValue<List<? extends String>> whitelist;
public Validation(Builder builder) {
builder.push("Validation");
allowInSurvival = builder
.comment("Allow use of the mod for players that are in survival mode. Otherwise, only creative mode players can use the mod.")
.define("allowInSurvival", true);
useWhitelist = builder
.comment("Use a whitelist to determine which players can use the mod. If false, all players can use the mod.")
.define("useWhitelist", false);
whitelist = builder
.comment("List of player names that can use the mod.")
.defineList("whitelist", Arrays.asList("Player1", "Player2"), o -> true);
builder.pop();
}
}
public static class Memory {
public final IntValue undoStackSize;
public Memory(Builder builder) {
builder.push("Memory");
undoStackSize = builder
.comment("How many placements are remembered for the undo functionality.")
.worldRestart()
.defineInRange("undoStackSize", 50, 10, 200);
builder.pop();
}
}
}

View File

@@ -40,7 +40,7 @@ public class BlockPreviews {
if (ClientConfig.visuals.showBlockPreviews.get()) { if (ClientConfig.visuals.showBlockPreviews.get()) {
for (PlacedBlocksEntry placed : placedBlocksList) { for (PlacedBlocksEntry placed : placedBlocksList) {
int totalTime = placed.breaking ? CommonConfig.visuals.breakAnimationLength.get() : CommonConfig.visuals.appearAnimationLength.get(); int totalTime = placed.breaking ? ClientConfig.visuals.breakAnimationLength.get() : ClientConfig.visuals.appearAnimationLength.get();
if (totalTime <= 0) continue; if (totalTime <= 0) continue;
float dissolve = (ClientEvents.ticksInGame - placed.time) / (float) totalTime; float dissolve = (ClientEvents.ticksInGame - placed.time) / (float) totalTime;
@@ -50,7 +50,7 @@ public class BlockPreviews {
//Expire //Expire
placedBlocksList.removeIf(placed -> { placedBlocksList.removeIf(placed -> {
int totalTime = placed.breaking ? CommonConfig.visuals.breakAnimationLength.get() : CommonConfig.visuals.appearAnimationLength.get(); int totalTime = placed.breaking ? ClientConfig.visuals.breakAnimationLength.get() : ClientConfig.visuals.appearAnimationLength.get();
return placed.time + totalTime < ClientEvents.ticksInGame; return placed.time + totalTime < ClientEvents.ticksInGame;
}); });
} }
@@ -228,7 +228,7 @@ public class BlockPreviews {
placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, false, new BlockSet(blocks))); placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, false, new BlockSet(blocks)));
CreateClient.OUTLINER.keep(blocks.firstPos, CommonConfig.visuals.appearAnimationLength.get()); CreateClient.OUTLINER.keep(blocks.firstPos, ClientConfig.visuals.appearAnimationLength.get());
} }
public void onBlocksBroken(BlockSet blocks) { public void onBlocksBroken(BlockSet blocks) {
@@ -237,7 +237,7 @@ public class BlockPreviews {
placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, true, new BlockSet(blocks))); placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, true, new BlockSet(blocks)));
CreateClient.OUTLINER.keep(blocks.firstPos, CommonConfig.visuals.breakAnimationLength.get()); CreateClient.OUTLINER.keep(blocks.firstPos, ClientConfig.visuals.breakAnimationLength.get());
} }
private void sortOnDistanceToPlayer(List<BlockPos> coordinates, Player player) { private void sortOnDistanceToPlayer(List<BlockPos> coordinates, Player player) {

View File

@@ -17,6 +17,7 @@ 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;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.ClientConfig;
import nl.requios.effortlessbuilding.ClientEvents; import nl.requios.effortlessbuilding.ClientEvents;
import nl.requios.effortlessbuilding.CommonConfig; import nl.requios.effortlessbuilding.CommonConfig;
import nl.requios.effortlessbuilding.EffortlessBuildingClient; import nl.requios.effortlessbuilding.EffortlessBuildingClient;
@@ -87,7 +88,8 @@ public class BuilderChain {
player.swing(InteractionHand.MAIN_HAND); player.swing(InteractionHand.MAIN_HAND);
blocks.skipFirst = buildMode == BuildModeEnum.DISABLED; blocks.skipFirst = buildMode == BuildModeEnum.DISABLED;
long placeTime = player.level.getGameTime() + CommonConfig.visuals.appearAnimationLength.get() - 3; long placeTime = player.level.getGameTime();
if (blocks.size() > 1) placeTime += ClientConfig.visuals.appearAnimationLength.get();
PacketHandler.INSTANCE.sendToServer(new ServerPlaceBlocksPacket(blocks, placeTime)); PacketHandler.INSTANCE.sendToServer(new ServerPlaceBlocksPacket(blocks, placeTime));
} }
} }

View File

@@ -1,26 +1,17 @@
package nl.requios.effortlessbuilding.systems; package nl.requios.effortlessbuilding.systems;
import com.google.common.collect.Lists; import net.minecraft.ChatFormatting;
import net.minecraft.core.Direction;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BucketItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
import net.minecraftforge.common.util.BlockSnapshot;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.ServerConfig;
import nl.requios.effortlessbuilding.create.foundation.utility.BlockHelper; import nl.requios.effortlessbuilding.create.foundation.utility.BlockHelper;
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.BlockUtilities;
import java.util.*; import java.util.*;
@@ -31,6 +22,7 @@ public class ServerBlockPlacer {
private boolean isPlacingOrBreakingBlocks = false; private boolean isPlacingOrBreakingBlocks = false;
public void placeBlocksDelayed(Player player, BlockSet blocks, long placeTime) { public void placeBlocksDelayed(Player player, BlockSet blocks, long placeTime) {
if (!checkAndNotifyAllowedToUseMod(player)) return;
delayedEntries.add(new DelayedEntry(player, blocks, placeTime)); delayedEntries.add(new DelayedEntry(player, blocks, placeTime));
} }
@@ -46,6 +38,7 @@ public class ServerBlockPlacer {
} }
public void placeBlocks(Player player, BlockSet blocks) { public void placeBlocks(Player player, BlockSet blocks) {
if (!checkAndNotifyAllowedToUseMod(player)) return;
// EffortlessBuilding.log(player, "Placing " + blocks.size() + " blocks"); // EffortlessBuilding.log(player, "Placing " + blocks.size() + " blocks");
for (BlockEntry block : blocks) { for (BlockEntry block : blocks) {
@@ -54,16 +47,17 @@ public class ServerBlockPlacer {
} }
} }
public void placeBlock(Player player, BlockEntry block) { private void placeBlock(Player player, BlockEntry block) {
Level world = player.level; Level world = player.level;
if (!world.isLoaded(block.blockPos)) return; if (!world.isLoaded(block.blockPos)) return;
isPlacingOrBreakingBlocks = true; isPlacingOrBreakingBlocks = true;
boolean placedBlock = onPlaceItemIntoWorld(player, block) == InteractionResult.SUCCESS; boolean placedBlock = BlockUtilities.placeBlockEntry(player, block) == InteractionResult.SUCCESS;
isPlacingOrBreakingBlocks = false; isPlacingOrBreakingBlocks = false;
} }
public void breakBlocks(Player player, BlockSet blocks) { public void breakBlocks(Player player, BlockSet blocks) {
if (!checkAndNotifyAllowedToUseMod(player)) return;
// EffortlessBuilding.log(player, "Breaking " + blocks.size() + " blocks"); // EffortlessBuilding.log(player, "Breaking " + blocks.size() + " blocks");
for (BlockEntry block : blocks) { for (BlockEntry block : blocks) {
@@ -72,7 +66,7 @@ public class ServerBlockPlacer {
} }
} }
public void breakBlock(Player player, BlockEntry block) { private void breakBlock(Player player, BlockEntry block) {
ServerLevel world = (ServerLevel) player.level; ServerLevel world = (ServerLevel) player.level;
if (!world.isLoaded(block.blockPos) || world.isEmptyBlock(block.blockPos)) return; if (!world.isLoaded(block.blockPos) || world.isEmptyBlock(block.blockPos)) return;
@@ -85,6 +79,24 @@ public class ServerBlockPlacer {
isPlacingOrBreakingBlocks = false; isPlacingOrBreakingBlocks = false;
} }
public boolean checkAndNotifyAllowedToUseMod(Player player) {
if (!isAllowedToUseMod(player)) {
EffortlessBuilding.log(player, ChatFormatting.RED + "You are not allowed to use Effortless Building.");
return false;
}
return true;
}
public boolean isAllowedToUseMod(Player player) {
if (!ServerConfig.validation.allowInSurvival.get() && !player.isCreative()) return false;
if (ServerConfig.validation.useWhitelist.get()) {
return ServerConfig.validation.whitelist.get().contains(player.getGameProfile().getName());
}
return true;
}
public Set<DelayedEntry> getDelayedEntries() { public Set<DelayedEntry> getDelayedEntries() {
return delayedEntriesView; return delayedEntriesView;
} }
@@ -95,96 +107,4 @@ public class ServerBlockPlacer {
public record DelayedEntry(Player player, BlockSet blocks, long placeTime) {} public record DelayedEntry(Player player, BlockSet blocks, long placeTime) {}
//ForgeHooks::onPlaceItemIntoWorld
private InteractionResult onPlaceItemIntoWorld(Player player, BlockEntry block) {
ItemStack itemstack = block.itemStack;
Level level = player.level;
if (player != null && !player.getAbilities().mayBuild && !itemstack.hasAdventureModePlaceTagForBlock(level.registryAccess().registryOrThrow(Registry.BLOCK_REGISTRY), new BlockInWorld(level, block.blockPos, false)))
return InteractionResult.PASS;
// handle all placement events here
Item item = itemstack.getItem();
int size = itemstack.getCount();
CompoundTag nbt = null;
if (itemstack.getTag() != null)
nbt = itemstack.getTag().copy();
if (!(itemstack.getItem() instanceof BucketItem)) // if not bucket
level.captureBlockSnapshots = true;
ItemStack copy = itemstack.copy();
////
BlockHelper.placeSchematicBlock(level, player, block.newBlockState, block.blockPos, block.itemStack, null);
////
InteractionResult ret = InteractionResult.SUCCESS;
if (itemstack.isEmpty())
ForgeEventFactory.onPlayerDestroyItem(player, copy, InteractionHand.MAIN_HAND);
level.captureBlockSnapshots = false;
if (ret.consumesAction())
{
// save new item data
int newSize = itemstack.getCount();
CompoundTag newNBT = null;
if (itemstack.getTag() != null)
{
newNBT = itemstack.getTag().copy();
}
@SuppressWarnings("unchecked")
List<BlockSnapshot> blockSnapshots = (List<BlockSnapshot>)level.capturedBlockSnapshots.clone();
level.capturedBlockSnapshots.clear();
// make sure to set pre-placement item data for event
itemstack.setCount(size);
itemstack.setTag(nbt);
Direction side = Direction.UP;
boolean eventResult = false;
if (blockSnapshots.size() > 1)
{
eventResult = ForgeEventFactory.onMultiBlockPlace(player, blockSnapshots, side);
}
else if (blockSnapshots.size() == 1)
{
eventResult = ForgeEventFactory.onBlockPlace(player, blockSnapshots.get(0), side);
}
if (eventResult)
{
ret = InteractionResult.FAIL; // cancel placement
// revert back all captured blocks
for (BlockSnapshot blocksnapshot : Lists.reverse(blockSnapshots))
{
level.restoringBlockSnapshots = true;
blocksnapshot.restore(true, false);
level.restoringBlockSnapshots = false;
}
}
else
{
// Change the stack to its new content
itemstack.setCount(newSize);
itemstack.setTag(newNBT);
for (BlockSnapshot snap : blockSnapshots)
{
int updateFlag = snap.getFlag();
BlockState oldBlock = snap.getReplacedBlock();
BlockState newBlock = level.getBlockState(snap.getPos());
newBlock.onPlace(level, snap.getPos(), oldBlock, false);
level.markAndNotifyBlock(snap.getPos(), level.getChunkAt(snap.getPos()), oldBlock, newBlock, updateFlag, 512);
}
if (player != null)
player.awardStat(Stats.ITEM_USED.get(item));
}
}
level.capturedBlockSnapshots.clear();
return ret;
}
} }

View File

@@ -10,6 +10,7 @@ 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.ServerConfig;
import nl.requios.effortlessbuilding.utilities.UndoRedoBlockSet; 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;
@@ -49,7 +50,7 @@ public class UndoRedo {
//If no stack exists, make one //If no stack exists, make one
if (!undoStacks.containsKey(player.getUUID())) { if (!undoStacks.containsKey(player.getUUID())) {
undoStacks.put(player.getUUID(), new FixedStack<>(new UndoRedoBlockSet[CommonConfig.survivalBalancers.undoStackSize.get()])); undoStacks.put(player.getUUID(), new FixedStack<>(new UndoRedoBlockSet[ServerConfig.memory.undoStackSize.get()]));
} }
undoStacks.get(player.getUUID()).push(blockSet); undoStacks.get(player.getUUID()).push(blockSet);
@@ -62,7 +63,7 @@ public class UndoRedo {
//If no stack exists, make one //If no stack exists, make one
if (!redoStacks.containsKey(player.getUUID())) { if (!redoStacks.containsKey(player.getUUID())) {
redoStacks.put(player.getUUID(), new FixedStack<>(new UndoRedoBlockSet[CommonConfig.survivalBalancers.undoStackSize.get()])); redoStacks.put(player.getUUID(), new FixedStack<>(new UndoRedoBlockSet[ServerConfig.memory.undoStackSize.get()]));
} }
redoStacks.get(player.getUUID()).push(blockSet); redoStacks.get(player.getUUID()).push(blockSet);

View File

@@ -1,22 +1,35 @@
package nl.requios.effortlessbuilding.utilities; package nl.requios.effortlessbuilding.utilities;
import com.google.common.collect.Lists;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BucketItem;
import net.minecraft.world.item.Item;
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.ClipContext; import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
import net.minecraft.world.level.block.state.properties.Half; import net.minecraft.world.level.block.state.properties.Half;
import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.block.state.properties.SlabType;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.util.BlockSnapshot;
import net.minecraftforge.event.ForgeEventFactory;
import nl.requios.effortlessbuilding.create.foundation.utility.BlockHelper;
import java.util.List;
//Common //Common
public class BlockUtilities { public class BlockUtilities {
@@ -47,6 +60,98 @@ public class BlockUtilities {
return result; return result;
} }
//ForgeHooks::onPlaceItemIntoWorld
public static InteractionResult placeBlockEntry(Player player, BlockEntry block) {
ItemStack itemstack = block.itemStack;
Level level = player.level;
if (player != null && !player.getAbilities().mayBuild && !itemstack.hasAdventureModePlaceTagForBlock(level.registryAccess().registryOrThrow(Registry.BLOCK_REGISTRY), new BlockInWorld(level, block.blockPos, false)))
return InteractionResult.PASS;
// handle all placement events here
Item item = itemstack.getItem();
int size = itemstack.getCount();
CompoundTag nbt = null;
if (itemstack.getTag() != null)
nbt = itemstack.getTag().copy();
if (!(itemstack.getItem() instanceof BucketItem)) // if not bucket
level.captureBlockSnapshots = true;
ItemStack copy = itemstack.copy();
////
BlockHelper.placeSchematicBlock(level, player, block.newBlockState, block.blockPos, block.itemStack, null);
////
InteractionResult ret = InteractionResult.SUCCESS;
if (itemstack.isEmpty())
ForgeEventFactory.onPlayerDestroyItem(player, copy, InteractionHand.MAIN_HAND);
level.captureBlockSnapshots = false;
if (ret.consumesAction())
{
// save new item data
int newSize = itemstack.getCount();
CompoundTag newNBT = null;
if (itemstack.getTag() != null)
{
newNBT = itemstack.getTag().copy();
}
@SuppressWarnings("unchecked")
List<BlockSnapshot> blockSnapshots = (List<BlockSnapshot>)level.capturedBlockSnapshots.clone();
level.capturedBlockSnapshots.clear();
// make sure to set pre-placement item data for event
itemstack.setCount(size);
itemstack.setTag(nbt);
Direction side = Direction.UP;
boolean eventResult = false;
if (blockSnapshots.size() > 1)
{
eventResult = ForgeEventFactory.onMultiBlockPlace(player, blockSnapshots, side);
}
else if (blockSnapshots.size() == 1)
{
eventResult = ForgeEventFactory.onBlockPlace(player, blockSnapshots.get(0), side);
}
if (eventResult)
{
ret = InteractionResult.FAIL; // cancel placement
// revert back all captured blocks
for (BlockSnapshot blocksnapshot : Lists.reverse(blockSnapshots))
{
level.restoringBlockSnapshots = true;
blocksnapshot.restore(true, false);
level.restoringBlockSnapshots = false;
}
}
else
{
// Change the stack to its new content
itemstack.setCount(newSize);
itemstack.setTag(newNBT);
for (BlockSnapshot snap : blockSnapshots)
{
int updateFlag = snap.getFlag();
BlockState oldBlock = snap.getReplacedBlock();
BlockState newBlock = level.getBlockState(snap.getPos());
newBlock.onPlace(level, snap.getPos(), oldBlock, false);
level.markAndNotifyBlock(snap.getPos(), level.getChunkAt(snap.getPos()), oldBlock, newBlock, updateFlag, 512);
}
if (player != null)
player.awardStat(Stats.ITEM_USED.get(item));
}
}
level.capturedBlockSnapshots.clear();
return ret;
}
public static void playSoundIfFurtherThanNormal(Player player, BlockEntry blockEntry, boolean breaking) { public static void playSoundIfFurtherThanNormal(Player player, BlockEntry blockEntry, boolean breaking) {
if (Minecraft.getInstance().hitResult != null && Minecraft.getInstance().hitResult.getType() == HitResult.Type.BLOCK) if (Minecraft.getInstance().hitResult != null && Minecraft.getInstance().hitResult.getType() == HitResult.Type.BLOCK)