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:
@@ -2,18 +2,22 @@ package nl.requios.effortlessbuilding;
|
||||
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
|
||||
import static net.minecraftforge.common.ForgeConfigSpec.*;
|
||||
|
||||
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 ForgeConfigSpec spec = builder.build();
|
||||
|
||||
public static class Visuals {
|
||||
public final ForgeConfigSpec.ConfigValue<Boolean> showBlockPreviews;
|
||||
public final ForgeConfigSpec.ConfigValue<Boolean> onlyShowBlockPreviewsWhenBuilding;
|
||||
public final ForgeConfigSpec.ConfigValue<Integer> maxBlockPreviews;
|
||||
public final BooleanValue showBlockPreviews;
|
||||
public final BooleanValue onlyShowBlockPreviewsWhenBuilding;
|
||||
public final IntValue maxBlockPreviews;
|
||||
public final IntValue appearAnimationLength;
|
||||
public final IntValue breakAnimationLength;
|
||||
|
||||
public Visuals(ForgeConfigSpec.Builder builder) {
|
||||
public Visuals(Builder builder) {
|
||||
builder.push("Visuals");
|
||||
|
||||
showBlockPreviews = builder
|
||||
@@ -27,8 +31,17 @@ public class ClientConfig {
|
||||
maxBlockPreviews = builder
|
||||
.comment("Don't show block previews when placing more than this many blocks. " +
|
||||
"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();
|
||||
}
|
||||
|
||||
@@ -3,23 +3,24 @@ package nl.requios.effortlessbuilding;
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
import nl.requios.effortlessbuilding.create.foundation.render.SuperByteBufferCache;
|
||||
|
||||
import static net.minecraftforge.common.ForgeConfigSpec.*;
|
||||
|
||||
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 SurvivalBalancers survivalBalancers = new SurvivalBalancers(builder);
|
||||
public static final Visuals visuals = new Visuals(builder);
|
||||
public static final ForgeConfigSpec spec = builder.build();
|
||||
|
||||
public static class Reach {
|
||||
public final ForgeConfigSpec.ConfigValue<Boolean> enableReachUpgrades;
|
||||
public final ForgeConfigSpec.ConfigValue<Integer> maxReachCreative;
|
||||
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel0;
|
||||
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel1;
|
||||
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel2;
|
||||
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel3;
|
||||
public final BooleanValue enableReachUpgrades;
|
||||
public final IntValue maxReachCreative;
|
||||
public final IntValue maxReachLevel0;
|
||||
public final IntValue maxReachLevel1;
|
||||
public final IntValue maxReachLevel2;
|
||||
public final IntValue maxReachLevel3;
|
||||
|
||||
public Reach(ForgeConfigSpec.Builder builder) {
|
||||
public Reach(Builder builder) {
|
||||
builder.push("Reach");
|
||||
enableReachUpgrades = builder
|
||||
.comment("Reach: how far away the player can place blocks using mirror/array etc.",
|
||||
@@ -30,35 +31,34 @@ public class CommonConfig {
|
||||
maxReachCreative = builder
|
||||
.comment("Maximum reach in creative",
|
||||
"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
|
||||
.comment("Maximum reach in survival without upgrades",
|
||||
"Reach upgrades are craftable consumables that permanently increase reach.",
|
||||
"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
|
||||
.comment("Maximum reach in survival with one upgrade")
|
||||
.define("maxReachLevel1", 50);
|
||||
.defineInRange("maxReachLevel1", 50, 0, 1000);
|
||||
|
||||
maxReachLevel2 = builder
|
||||
.comment("Maximum reach in survival with two upgrades")
|
||||
.define("maxReachLevel2", 100);
|
||||
.defineInRange("maxReachLevel2", 100, 0, 1000);
|
||||
|
||||
maxReachLevel3 = builder
|
||||
.comment("Maximum reach in survival with three upgrades")
|
||||
.define("maxReachLevel3", 200);
|
||||
.defineInRange("maxReachLevel3", 200, 0, 1000);
|
||||
|
||||
builder.pop();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SurvivalBalancers {
|
||||
public final ForgeConfigSpec.ConfigValue<Integer> quickReplaceMiningLevel;
|
||||
public final ForgeConfigSpec.ConfigValue<Integer> undoStackSize;
|
||||
public final IntValue quickReplaceMiningLevel;
|
||||
|
||||
public SurvivalBalancers(ForgeConfigSpec.Builder builder) {
|
||||
public SurvivalBalancers(Builder builder) {
|
||||
builder.push("SurvivalBalancers");
|
||||
|
||||
quickReplaceMiningLevel = builder
|
||||
@@ -71,32 +71,6 @@ public class CommonConfig {
|
||||
"4: blocks that can be harvested with netherite tools")
|
||||
.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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ public class EffortlessBuilding {
|
||||
//Register config
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, CommonConfig.spec);
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ClientConfig.spec);
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ServerConfig.spec);
|
||||
}
|
||||
|
||||
public static void setup(final FMLCommonSetupEvent event) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public class BlockPreviews {
|
||||
if (ClientConfig.visuals.showBlockPreviews.get()) {
|
||||
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;
|
||||
|
||||
float dissolve = (ClientEvents.ticksInGame - placed.time) / (float) totalTime;
|
||||
@@ -50,7 +50,7 @@ public class BlockPreviews {
|
||||
|
||||
//Expire
|
||||
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;
|
||||
});
|
||||
}
|
||||
@@ -228,7 +228,7 @@ public class BlockPreviews {
|
||||
|
||||
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) {
|
||||
@@ -237,7 +237,7 @@ public class BlockPreviews {
|
||||
|
||||
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) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import nl.requios.effortlessbuilding.ClientConfig;
|
||||
import nl.requios.effortlessbuilding.ClientEvents;
|
||||
import nl.requios.effortlessbuilding.CommonConfig;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||
@@ -87,7 +88,8 @@ public class BuilderChain {
|
||||
player.swing(InteractionHand.MAIN_HAND);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
package nl.requios.effortlessbuilding.systems;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.ChatFormatting;
|
||||
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.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.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 nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.ServerConfig;
|
||||
import nl.requios.effortlessbuilding.create.foundation.utility.BlockHelper;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||
import nl.requios.effortlessbuilding.utilities.BlockUtilities;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -31,6 +22,7 @@ public class ServerBlockPlacer {
|
||||
private boolean isPlacingOrBreakingBlocks = false;
|
||||
|
||||
public void placeBlocksDelayed(Player player, BlockSet blocks, long placeTime) {
|
||||
if (!checkAndNotifyAllowedToUseMod(player)) return;
|
||||
|
||||
delayedEntries.add(new DelayedEntry(player, blocks, placeTime));
|
||||
}
|
||||
@@ -46,6 +38,7 @@ public class ServerBlockPlacer {
|
||||
}
|
||||
|
||||
public void placeBlocks(Player player, BlockSet blocks) {
|
||||
if (!checkAndNotifyAllowedToUseMod(player)) return;
|
||||
// EffortlessBuilding.log(player, "Placing " + blocks.size() + " 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;
|
||||
if (!world.isLoaded(block.blockPos)) return;
|
||||
|
||||
isPlacingOrBreakingBlocks = true;
|
||||
boolean placedBlock = onPlaceItemIntoWorld(player, block) == InteractionResult.SUCCESS;
|
||||
boolean placedBlock = BlockUtilities.placeBlockEntry(player, block) == InteractionResult.SUCCESS;
|
||||
isPlacingOrBreakingBlocks = false;
|
||||
}
|
||||
|
||||
public void breakBlocks(Player player, BlockSet blocks) {
|
||||
if (!checkAndNotifyAllowedToUseMod(player)) return;
|
||||
// EffortlessBuilding.log(player, "Breaking " + blocks.size() + " 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;
|
||||
if (!world.isLoaded(block.blockPos) || world.isEmptyBlock(block.blockPos)) return;
|
||||
|
||||
@@ -85,6 +79,24 @@ public class ServerBlockPlacer {
|
||||
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() {
|
||||
return delayedEntriesView;
|
||||
}
|
||||
@@ -95,96 +107,4 @@ public class ServerBlockPlacer {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import nl.requios.effortlessbuilding.CommonConfig;
|
||||
import nl.requios.effortlessbuilding.EffortlessBuilding;
|
||||
import nl.requios.effortlessbuilding.ServerConfig;
|
||||
import nl.requios.effortlessbuilding.utilities.UndoRedoBlockSet;
|
||||
import nl.requios.effortlessbuilding.utilities.FixedStack;
|
||||
import nl.requios.effortlessbuilding.utilities.InventoryHelper;
|
||||
@@ -49,7 +50,7 @@ public class UndoRedo {
|
||||
|
||||
//If no stack exists, make one
|
||||
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);
|
||||
@@ -62,7 +63,7 @@ public class UndoRedo {
|
||||
|
||||
//If no stack exists, make one
|
||||
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);
|
||||
|
||||
@@ -1,22 +1,35 @@
|
||||
package nl.requios.effortlessbuilding.utilities;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.stats.Stats;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
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.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.*;
|
||||
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.SlabType;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
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
|
||||
public class BlockUtilities {
|
||||
@@ -47,6 +60,98 @@ public class BlockUtilities {
|
||||
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) {
|
||||
|
||||
if (Minecraft.getInstance().hitResult != null && Minecraft.getInstance().hitResult.getType() == HitResult.Type.BLOCK)
|
||||
|
||||
Reference in New Issue
Block a user