Overhauled block previews to work with ticks. Added place and break animation.

Added DelayedBlockPlacer to play appear animation, then place.
Split BuildConfig into CommonConfig and ClientConfig.
Fixed itemstack not found error in creative.
Added scale and color options to ghost blocks.
This commit is contained in:
Christian Knaapen
2023-01-17 02:30:08 +01:00
parent fa1aadcd86
commit cd3afbbb82
32 changed files with 761 additions and 668 deletions

View File

@@ -0,0 +1,36 @@
package nl.requios.effortlessbuilding;
import net.minecraftforge.common.ForgeConfigSpec;
public class ClientConfig {
private static final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.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> alwaysShowBlockPreview;
public final ForgeConfigSpec.ConfigValue<Integer> maxBlockPreviews;
public Visuals(ForgeConfigSpec.Builder builder) {
builder.push("Visuals");
showBlockPreviews = builder
.comment("Show previews of the blocks while placing them")
.define("useShaders", true);
alwaysShowBlockPreview = builder
.comment("Show a block preview if you have a block in hand even in the 'Disabled' build mode")
.define("alwaysShowBlockPreview", false);
maxBlockPreviews = builder
.comment("Don't show block previews when placing more than this many blocks. " +
"The outline will always be rendered.")
.define("shaderTreshold", 500);
builder.pop();
}
}
}

View File

@@ -133,7 +133,7 @@ public class ClientEvents {
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
if (mc.screen != null || if (mc.screen != null ||
buildMode == BuildModes.BuildModeEnum.NORMAL || buildMode == BuildModes.BuildModeEnum.DISABLED ||
RadialMenu.instance.isVisible()) { RadialMenu.instance.isVisible()) {
return; return;
} }
@@ -175,7 +175,7 @@ public class ClientEvents {
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage()); PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage());
} }
} }
} else if (buildMode == BuildModes.BuildModeEnum.NORMAL_PLUS) { } else if (buildMode == BuildModes.BuildModeEnum.SINGLE) {
placeCooldown--; placeCooldown--;
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) placeCooldown = 0; if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) placeCooldown = 0;
} }
@@ -210,7 +210,7 @@ public class ClientEvents {
BuildModes.onBlockBrokenMessage(player, new BlockBrokenMessage()); BuildModes.onBlockBrokenMessage(player, new BlockBrokenMessage());
PacketHandler.INSTANCE.sendToServer(new BlockBrokenMessage()); PacketHandler.INSTANCE.sendToServer(new BlockBrokenMessage());
} }
} else if (buildMode == BuildModes.BuildModeEnum.NORMAL_PLUS) { } else if (buildMode == BuildModes.BuildModeEnum.SINGLE) {
breakCooldown--; breakCooldown--;
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) breakCooldown = 0; if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) breakCooldown = 0;
} }

View File

@@ -1,8 +1,9 @@
package nl.requios.effortlessbuilding; package nl.requios.effortlessbuilding;
import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec;
import nl.requios.effortlessbuilding.create.foundation.render.SuperByteBufferCache;
public class BuildConfig { public class CommonConfig {
private static final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder(); private static final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();
public static final Reach reach = new Reach(builder); public static final Reach reach = new Reach(builder);
@@ -80,33 +81,21 @@ public class BuildConfig {
} }
public static class Visuals { public static class Visuals {
public final ForgeConfigSpec.ConfigValue<Boolean> alwaysShowBlockPreview; public final ForgeConfigSpec.ConfigValue<Integer> appearAnimationLength;
public final ForgeConfigSpec.ConfigValue<Double> dissolveTimeMultiplier; public final ForgeConfigSpec.ConfigValue<Integer> breakAnimationLength;
public final ForgeConfigSpec.ConfigValue<Integer> shaderThreshold;
public final ForgeConfigSpec.ConfigValue<Boolean> useShaders;
public Visuals(ForgeConfigSpec.Builder builder) { public Visuals(ForgeConfigSpec.Builder builder) {
builder.push("Visuals"); builder.push("Visuals");
alwaysShowBlockPreview = builder appearAnimationLength = builder
.comment("Show a block preview if you have a block in hand even in the 'Normal' build mode") .comment("How long it takes for a block to appear when placed in ticks.",
.define("alwaysShowBlockPreview", false); "Set to 0 to disable animation.")
.define("appearAnimationLength", 5);
dissolveTimeMultiplier = builder breakAnimationLength = builder
.comment("How long the dissolve effect takes when placing blocks.", .comment("How long the break animation is in ticks.",
"Default between 30 and 60 ticks, you can multiply that here.", "Set to 0 to disable animation.")
"Recommended values:", .define("breakAnimationLength", 10);
"Snappy: 0.7",
"Relaxing: 1.5")
.define("dissolveTimeMultiplier", 1.0);
shaderThreshold = builder
.comment("Switch to using the simple performance shader when placing more than this many blocks.")
.define("shaderTreshold", 1500);
useShaders = builder
.comment("Use fancy shaders while placing blocks")
.define("useShaders", true);
builder.pop(); builder.pop();
} }

View File

@@ -11,6 +11,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.event.level.BlockEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -52,6 +53,13 @@ public class CommonEvents {
} }
} }
@SubscribeEvent
public static void onTick(TickEvent.LevelTickEvent event) {
if (event.phase != TickEvent.Phase.START) return;
EffortlessBuilding.DELAYED_BLOCK_PLACER.tick();
}
@SubscribeEvent @SubscribeEvent
public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) { public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) {
if (event.getLevel().isClientSide()) return; if (event.getLevel().isClientSide()) return;
@@ -65,7 +73,7 @@ public class CommonEvents {
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
if (buildMode != BuildModes.BuildModeEnum.NORMAL) { if (buildMode != BuildModes.BuildModeEnum.DISABLED) {
//Only cancel if itemblock in hand //Only cancel if itemblock in hand
//Fixed issue with e.g. Create Wrench shift-rightclick disassembling being cancelled. //Fixed issue with e.g. Create Wrench shift-rightclick disassembling being cancelled.
@@ -104,7 +112,7 @@ public class CommonEvents {
//Cancel event if necessary //Cancel event if necessary
//If cant break far then dont cancel event ever //If cant break far then dont cancel event ever
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(event.getPlayer()).getBuildMode(); BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(event.getPlayer()).getBuildMode();
if (buildMode != BuildModes.BuildModeEnum.NORMAL && ReachHelper.canBreakFar(event.getPlayer())) { if (buildMode != BuildModes.BuildModeEnum.DISABLED && ReachHelper.canBreakFar(event.getPlayer())) {
event.setCanceled(true); event.setCanceled(true);
} else { } else {
//NORMAL mode, let vanilla handle block breaking //NORMAL mode, let vanilla handle block breaking
@@ -155,7 +163,7 @@ public class CommonEvents {
//Set build mode to normal //Set build mode to normal
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
modeSettings.setBuildMode(BuildModes.BuildModeEnum.NORMAL); modeSettings.setBuildMode(BuildModes.BuildModeEnum.DISABLED);
ModeSettingsManager.setModeSettings(player, modeSettings); ModeSettingsManager.setModeSettings(player, modeSettings);
//Disable modifiers //Disable modifiers

View File

@@ -22,6 +22,7 @@ import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagContainer; import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagContainer;
import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagContainer; import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagContainer;
import nl.requios.effortlessbuilding.gui.RandomizerBagContainer; import nl.requios.effortlessbuilding.gui.RandomizerBagContainer;
import nl.requios.effortlessbuilding.helper.DelayedBlockPlacer;
import nl.requios.effortlessbuilding.item.*; import nl.requios.effortlessbuilding.item.*;
import nl.requios.effortlessbuilding.network.PacketHandler; import nl.requios.effortlessbuilding.network.PacketHandler;
import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.proxy.ClientProxy;
@@ -39,6 +40,8 @@ public class EffortlessBuilding {
public static EffortlessBuilding instance; public static EffortlessBuilding instance;
public static IProxy proxy = DistExecutor.safeRunForDist(() -> ClientProxy::new, () -> ServerProxy::new); public static IProxy proxy = DistExecutor.safeRunForDist(() -> ClientProxy::new, () -> ServerProxy::new);
public static final DelayedBlockPlacer DELAYED_BLOCK_PLACER = new DelayedBlockPlacer();
//Registration //Registration
private static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID); private static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID);
private static final DeferredRegister<MenuType<?>> CONTAINERS = DeferredRegister.create(ForgeRegistries.MENU_TYPES, EffortlessBuilding.MODID); private static final DeferredRegister<MenuType<?>> CONTAINERS = DeferredRegister.create(ForgeRegistries.MENU_TYPES, EffortlessBuilding.MODID);
@@ -69,7 +72,8 @@ public class EffortlessBuilding {
CONTAINERS.register(FMLJavaModLoadingContext.get().getModEventBus()); CONTAINERS.register(FMLJavaModLoadingContext.get().getModEventBus());
//Register config //Register config
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, BuildConfig.spec); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, CommonConfig.spec);
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ClientConfig.spec);
} }
public static void setup(final FMLCommonSetupEvent event) { public static void setup(final FMLCommonSetupEvent event) {

View File

@@ -66,7 +66,7 @@ public class BuildModes {
//Check if player reach does not exceed startpos //Check if player reach does not exceed startpos
int maxReach = ReachHelper.getMaxReach(player); int maxReach = ReachHelper.getMaxReach(player);
if (buildMode != BuildModeEnum.NORMAL && player.blockPosition().distSqr(startPos) > maxReach * maxReach) { if (buildMode != BuildModeEnum.DISABLED && player.blockPosition().distSqr(startPos) > maxReach * maxReach) {
EffortlessBuilding.log(player, "Placement exceeds your reach."); EffortlessBuilding.log(player, "Placement exceeds your reach.");
return; return;
} }
@@ -186,9 +186,6 @@ public class BuildModes {
return new Vec3(x, y, z); return new Vec3(x, y, z);
} }
//-- Common build mode functionality --//
public static Vec3 findYBound(double y, Vec3 start, Vec3 look) { public static Vec3 findYBound(double y, Vec3 start, Vec3 look) {
//then x and z are //then x and z are
double x = (y - start.y) / look.y * look.x + start.x; double x = (y - start.y) / look.y * look.x + start.x;
@@ -246,8 +243,8 @@ public class BuildModes {
} }
public enum BuildModeEnum { public enum BuildModeEnum {
NORMAL("normal", new Normal(), BuildModeCategoryEnum.BASIC), DISABLED("normal", new Disabled(), BuildModeCategoryEnum.BASIC),
NORMAL_PLUS("normal_plus", new NormalPlus(), BuildModeCategoryEnum.BASIC, OptionEnum.BUILD_SPEED), SINGLE("normal_plus", new Single(), BuildModeCategoryEnum.BASIC, OptionEnum.BUILD_SPEED),
LINE("line", new Line(), BuildModeCategoryEnum.BASIC /*, OptionEnum.THICKNESS*/), LINE("line", new Line(), BuildModeCategoryEnum.BASIC /*, OptionEnum.THICKNESS*/),
WALL("wall", new Wall(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL), WALL("wall", new Wall(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL),
FLOOR("floor", new Floor(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL), FLOOR("floor", new Floor(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL),

View File

@@ -77,7 +77,7 @@ public class ModeSettingsManager {
} }
public static class ModeSettings { public static class ModeSettings {
private BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.NORMAL; private BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.DISABLED;
public ModeSettings() { public ModeSettings() {
} }

View File

@@ -9,7 +9,7 @@ import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class NormalPlus implements IBuildMode { public class Disabled implements IBuildMode {
@Override @Override
public void initialize(Player player) { public void initialize(Player player) {

View File

@@ -9,7 +9,7 @@ import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Normal implements IBuildMode { public class Single implements IBuildMode {
@Override @Override
public void initialize(Player player) { public void initialize(Player player) {

View File

@@ -14,11 +14,13 @@ import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import nl.requios.effortlessbuilding.CommonConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.helper.InventoryHelper; import nl.requios.effortlessbuilding.helper.DelayedBlockPlacer;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; import nl.requios.effortlessbuilding.render.BlockPreviews;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -42,55 +44,17 @@ public class BuildModifiers {
//check if valid blockstates //check if valid blockstates
if (blockStates.size() == 0 || coordinates.size() != blockStates.size()) return; if (blockStates.size() == 0 || coordinates.size() != blockStates.size()) return;
//remember previous blockstates for undo
List<BlockState> previousBlockStates = new ArrayList<>(coordinates.size());
List<BlockState> newBlockStates = new ArrayList<>(coordinates.size());
for (BlockPos coordinate : coordinates) {
previousBlockStates.add(world.getBlockState(coordinate));
}
if (world.isClientSide) { if (world.isClientSide) {
BlockPreviewRenderer.onBlocksPlaced(); BlockPreviews.onBlocksPlaced();
newBlockStates = blockStates;
} else { } else {
//place blocks int delay = CommonConfig.visuals.appearAnimationLength.get() * 3; //DelayedBlockPlacer is called 3 times per tick?
for (int i = placeStartPos ? 0 : 1; i < coordinates.size(); i++) {
BlockPos blockPos = coordinates.get(i);
BlockState blockState = blockStates.get(i);
ItemStack itemStack = itemStacks.get(i);
if (world.isLoaded(blockPos)) { //place blocks after delay
//check itemstack empty EffortlessBuilding.DELAYED_BLOCK_PLACER.placeBlocksDelayed(new DelayedBlockPlacer.Entry(world, player, coordinates,
if (itemStack.isEmpty()) { blockStates, itemStacks, hitVec, placeStartPos, delay));
//try to find new stack, otherwise continue
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
if (itemStack.isEmpty()) continue;
}
SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, Direction.UP, hitVec, false, false, false);
}
}
//find actual new blockstates for undo
for (BlockPos coordinate : coordinates) {
newBlockStates.add(world.getBlockState(coordinate));
}
}
//Set first previousBlockState to empty if in NORMAL mode, to make undo/redo work
//(Block is placed by the time it gets here, and unplaced after this)
if (!placeStartPos) previousBlockStates.set(0, Blocks.AIR.defaultBlockState());
//If all new blockstates are air then no use in adding it, no block was actually placed
//Can happen when e.g. placing one block in yourself
if (Collections.frequency(newBlockStates, Blocks.AIR.defaultBlockState()) != newBlockStates.size()) {
//add to undo stack
BlockPos firstPos = startCoordinates.get(0);
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1);
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
} }
} }
@@ -109,7 +73,7 @@ public class BuildModifiers {
} }
if (world.isClientSide) { if (world.isClientSide) {
BlockPreviewRenderer.onBlocksBroken(); BlockPreviews.onBlocksBroken();
//list of air blockstates //list of air blockstates
for (int i = 0; i < coordinates.size(); i++) { for (int i = 0; i < coordinates.size(); i++) {
@@ -237,6 +201,7 @@ public class BuildModifiers {
} }
public static boolean isEnabled(ModifierSettingsManager.ModifierSettings modifierSettings, BlockPos startPos) { public static boolean isEnabled(ModifierSettingsManager.ModifierSettings modifierSettings, BlockPos startPos) {
//startPos can be null
return Mirror.isEnabled(modifierSettings.getMirrorSettings(), startPos) || return Mirror.isEnabled(modifierSettings.getMirrorSettings(), startPos) ||
Array.isEnabled(modifierSettings.getArraySettings()) || Array.isEnabled(modifierSettings.getArraySettings()) ||
RadialMirror.isEnabled(modifierSettings.getRadialMirrorSettings(), startPos) || RadialMirror.isEnabled(modifierSettings.getRadialMirrorSettings(), startPos) ||

View File

@@ -5,7 +5,7 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.PacketDistributor;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.CommonConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager; import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
@@ -192,16 +192,16 @@ public class ModifierSettingsManager {
int reach = 10; int reach = 10;
switch (reachUpgrade) { switch (reachUpgrade) {
case 0: case 0:
reach = BuildConfig.reach.maxReachLevel0.get(); reach = CommonConfig.reach.maxReachLevel0.get();
break; break;
case 1: case 1:
reach = BuildConfig.reach.maxReachLevel1.get(); reach = CommonConfig.reach.maxReachLevel1.get();
break; break;
case 2: case 2:
reach = BuildConfig.reach.maxReachLevel2.get(); reach = CommonConfig.reach.maxReachLevel2.get();
break; break;
case 3: case 3:
reach = BuildConfig.reach.maxReachLevel3.get(); reach = CommonConfig.reach.maxReachLevel3.get();
break; break;
} }

View File

@@ -10,12 +10,12 @@ import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.CommonConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.helper.FixedStack; import nl.requios.effortlessbuilding.helper.FixedStack;
import nl.requios.effortlessbuilding.helper.InventoryHelper; import nl.requios.effortlessbuilding.helper.InventoryHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; import nl.requios.effortlessbuilding.render.BlockPreviews;
import java.util.*; import java.util.*;
@@ -50,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 BlockSet[BuildConfig.survivalBalancers.undoStackSize.get()])); undoStacks.put(player.getUUID(), new FixedStack<>(new BlockSet[CommonConfig.survivalBalancers.undoStackSize.get()]));
} }
undoStacks.get(player.getUUID()).push(blockSet); undoStacks.get(player.getUUID()).push(blockSet);
@@ -63,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 BlockSet[BuildConfig.survivalBalancers.undoStackSize.get()])); redoStacks.put(player.getUUID(), new FixedStack<>(new BlockSet[CommonConfig.survivalBalancers.undoStackSize.get()]));
} }
redoStacks.get(player.getUUID()).push(blockSet); redoStacks.get(player.getUUID()).push(blockSet);
@@ -88,7 +88,7 @@ public class UndoRedo {
List<ItemStack> itemStacks = findItemStacksInInventory(player, previousBlockStates); List<ItemStack> itemStacks = findItemStacksInInventory(player, previousBlockStates);
if (player.level.isClientSide) { if (player.level.isClientSide) {
BlockPreviewRenderer.onBlocksBroken(coordinates, itemStacks, newBlockStates, blockSet.getSecondPos(), blockSet.getFirstPos()); BlockPreviews.onBlocksBroken(coordinates, itemStacks, newBlockStates, blockSet.getSecondPos(), blockSet.getFirstPos());
} else { } else {
//break all those blocks, reset to what they were //break all those blocks, reset to what they were
for (int i = 0; i < coordinates.size(); i++) { for (int i = 0; i < coordinates.size(); i++) {
@@ -148,7 +148,7 @@ public class UndoRedo {
List<ItemStack> itemStacks = findItemStacksInInventory(player, newBlockStates); List<ItemStack> itemStacks = findItemStacksInInventory(player, newBlockStates);
if (player.level.isClientSide) { if (player.level.isClientSide) {
BlockPreviewRenderer.onBlocksPlaced(coordinates, itemStacks, newBlockStates, blockSet.getFirstPos(), blockSet.getSecondPos()); BlockPreviews.onBlocksPlaced(coordinates, itemStacks, newBlockStates, blockSet.getFirstPos(), blockSet.getSecondPos());
} else { } else {
//place blocks //place blocks
for (int i = 0; i < coordinates.size(); i++) { for (int i = 0; i < coordinates.size(); i++) {

View File

@@ -100,7 +100,7 @@ public class ModeCapabilityManager {
//TODO add mode settings //TODO add mode settings
ModeSettings modeSettings = new ModeSettings(BuildModes.BuildModeEnum.NORMAL); ModeSettings modeSettings = new ModeSettings(BuildModes.BuildModeEnum.DISABLED);
instance.setModeData(modeSettings); instance.setModeData(modeSettings);
} }

View File

@@ -3,6 +3,8 @@ package nl.requios.effortlessbuilding.create.foundation.utility.ghost;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
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 nl.requios.effortlessbuilding.create.foundation.utility.Color;
import nl.requios.effortlessbuilding.create.foundation.utility.outliner.Outline;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -11,11 +13,15 @@ public class GhostBlockParams {
protected final BlockState state; protected final BlockState state;
protected BlockPos pos; protected BlockPos pos;
protected Supplier<Float> alphaSupplier; protected Supplier<Float> alphaSupplier;
protected Supplier<Float> scaleSupplier;
public Supplier<Color> rgbSupplier;
private GhostBlockParams(BlockState state) { private GhostBlockParams(BlockState state) {
this.state = state; this.state = state;
this.pos = BlockPos.ZERO; this.pos = BlockPos.ZERO;
this.alphaSupplier = () -> 1f; this.alphaSupplier = () -> 1f;
this.scaleSupplier = () -> 0.85f;
this.rgbSupplier = () -> Color.WHITE;
} }
public static GhostBlockParams of(BlockState state) { public static GhostBlockParams of(BlockState state) {
@@ -47,4 +53,31 @@ public class GhostBlockParams {
public GhostBlockParams breathingAlpha() { public GhostBlockParams breathingAlpha() {
return this.alpha(() -> (float) GhostBlocks.getBreathingAlpha()); return this.alpha(() -> (float) GhostBlocks.getBreathingAlpha());
} }
public GhostBlockParams scale(Supplier<Float> scaleSupplier) {
this.scaleSupplier = scaleSupplier;
return this;
}
public GhostBlockParams scale(float scale) {
return this.scale(() -> scale);
}
public GhostBlockParams colored(Supplier<Color> colorSupplier) {
this.rgbSupplier = colorSupplier;
return this;
}
public GhostBlockParams colored(Color color) {
return this.colored(() -> color);
}
public GhostBlockParams colored(int color) {
var color2 = new Color(color, false);
return this.colored(() -> color2);
}
public GhostBlockParams breathingCyan() {
return this.colored(() -> new Color((float) GhostBlocks.getBreathingColor(), 1f, 1f, 1f));
}
} }

View File

@@ -19,6 +19,7 @@ import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelData; import net.minecraftforge.client.model.data.ModelData;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; import java.util.List;
@@ -76,6 +77,8 @@ public abstract class GhostBlockRenderer {
BlockState state = params.state; BlockState state = params.state;
BlockPos pos = params.pos; BlockPos pos = params.pos;
float alpha = params.alphaSupplier.get()/* * .75f* PlacementHelpers.getCurrentAlpha()*/; float alpha = params.alphaSupplier.get()/* * .75f* PlacementHelpers.getCurrentAlpha()*/;
float scale = params.scaleSupplier.get();
Color color = params.rgbSupplier.get();
BakedModel model = dispatcher.getBlockModel(state); BakedModel model = dispatcher.getBlockModel(state);
RenderType layer = RenderType.translucent(); RenderType layer = RenderType.translucent();
@@ -85,10 +88,10 @@ public abstract class GhostBlockRenderer {
ms.translate(pos.getX(), pos.getY(), pos.getZ()); ms.translate(pos.getX(), pos.getY(), pos.getZ());
ms.translate(.5, .5, .5); ms.translate(.5, .5, .5);
ms.scale(.85f, .85f, .85f); ms.scale(scale, scale, scale);
ms.translate(-.5, -.5, -.5); ms.translate(-.5, -.5, -.5);
renderModel(ms.last(), vb, state, model, 0f, 1f, 1f, alpha, renderModel(ms.last(), vb, state, model, color.getRedAsFloat(), color.getGreenAsFloat(), color.getBlueAsFloat(), alpha,
LevelRenderer.getLightColor(mc.level, pos), OverlayTexture.NO_OVERLAY, LevelRenderer.getLightColor(mc.level, pos), OverlayTexture.NO_OVERLAY,
ModelUtil.VIRTUAL_DATA, layer); ModelUtil.VIRTUAL_DATA, layer);
@@ -120,15 +123,15 @@ public abstract class GhostBlockRenderer {
float f; float f;
float f1; float f1;
float f2; float f2;
if (quad.isTinted()) { // if (quad.isTinted()) {
f = Mth.clamp(red, 0.0F, 1.0F); f = Mth.clamp(red, 0.0F, 1.0F);
f1 = Mth.clamp(green, 0.0F, 1.0F); f1 = Mth.clamp(green, 0.0F, 1.0F);
f2 = Mth.clamp(blue, 0.0F, 1.0F); f2 = Mth.clamp(blue, 0.0F, 1.0F);
} else { // } else {
f = 1.0F; // f = 1.0F;
f1 = 1.0F; // f1 = 1.0F;
f2 = 1.0F; // f2 = 1.0F;
} // }
consumer.putBulkData(pose, quad, f, f1, f2, alpha, packedLight, packedOverlay, true); consumer.putBulkData(pose, quad, f, f1, f2, alpha, packedLight, packedOverlay, true);
} }

View File

@@ -17,6 +17,13 @@ public class GhostBlocks {
return 0.55d - 0.2d * offset; return 0.55d - 0.2d * offset;
} }
public static double getBreathingColor() {
double period = 2500;
double timer = System.currentTimeMillis() % period;
double offset = Mth.cos((float) ((2d/period) * Math.PI * timer));
return 0.35d + 0.35d * offset;
}
final Map<Object, Entry> ghosts; final Map<Object, Entry> ghosts;
public GhostBlockParams showGhostState(Object slot, BlockState state) { public GhostBlockParams showGhostState(Object slot, BlockState state) {

View File

@@ -0,0 +1,108 @@
package nl.requios.effortlessbuilding.helper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.buildmodifier.BlockSet;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.create.foundation.utility.AnimationTickHolder;
import java.util.*;
public class DelayedBlockPlacer {
private final Set<Entry> entries = Collections.synchronizedSet(new HashSet<>());
private final Set<Entry> entriesView = Collections.unmodifiableSet(entries);
public void placeBlocksDelayed(Entry entry) {
if (entry.world.isClientSide) return;
entries.add(entry);
}
public void tick() {
for (Entry entry : entries) {
entry.ticksTillPlacement--;
if (entry.ticksTillPlacement <= 0) {
entry.place();
entries.remove(entry);
}
}
}
public Set<Entry> getEntries() {
return entriesView;
}
public static class Entry {
private Level world;
private Player player;
private List<BlockPos> coordinates;
private List<BlockState> blockStates;
private List<ItemStack> itemStacks;
private Vec3 hitVec;
private boolean placeStartPos;
private int ticksTillPlacement;
public Entry(Level world, Player player, List<BlockPos> coordinates, List<BlockState> blockStates,
List<ItemStack> itemStacks, Vec3 hitVec, boolean placeStartPos, int ticksTillPlacement) {
this.world = world;
this.player = player;
this.coordinates = coordinates;
this.blockStates = blockStates;
this.itemStacks = itemStacks;
this.hitVec = hitVec;
this.placeStartPos = placeStartPos;
this.ticksTillPlacement = ticksTillPlacement;
}
public void place() {
//remember previous blockstates for undo
List<BlockState> previousBlockStates = new ArrayList<>(coordinates.size());
for (BlockPos coordinate : coordinates) {
previousBlockStates.add(world.getBlockState(coordinate));
}
for (int i = placeStartPos ? 0 : 1; i < coordinates.size(); i++) {
BlockPos blockPos = coordinates.get(i);
BlockState blockState = blockStates.get(i);
ItemStack itemStack = itemStacks.get(i);
if (world.isLoaded(blockPos)) {
//check itemstack empty
if (itemStack.isEmpty()) {
//try to find new stack, otherwise continue
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
if (itemStack.isEmpty()) continue;
}
SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, Direction.UP, hitVec, false, false, false);
}
}
//find actual new blockstates for undo
List<BlockState> newBlockStates = new ArrayList<>(coordinates.size());
for (BlockPos coordinate : coordinates) {
newBlockStates.add(world.getBlockState(coordinate));
}
//Set first previousBlockState to empty if in NORMAL mode, to make undo/redo work
//(Block is placed by the time it gets here, and unplaced after this)
if (!placeStartPos) previousBlockStates.set(0, Blocks.AIR.defaultBlockState());
//If all new blockstates are air then no use in adding it, no block was actually placed
//Can happen when e.g. placing one block in yourself
if (Collections.frequency(newBlockStates, Blocks.AIR.defaultBlockState()) != newBlockStates.size()) {
//add to undo stack
BlockPos firstPos = coordinates.get(0);
BlockPos secondPos = coordinates.get(coordinates.size() - 1);
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
}
}
}
}

View File

@@ -2,28 +2,28 @@ package nl.requios.effortlessbuilding.helper;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.CommonConfig;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
public class ReachHelper { public class ReachHelper {
public static int getMaxReach(Player player) { public static int getMaxReach(Player player) {
if (player.isCreative()) return BuildConfig.reach.maxReachCreative.get(); if (player.isCreative()) return CommonConfig.reach.maxReachCreative.get();
if (!BuildConfig.reach.enableReachUpgrades.get()) return BuildConfig.reach.maxReachLevel3.get(); if (!CommonConfig.reach.enableReachUpgrades.get()) return CommonConfig.reach.maxReachLevel3.get();
//Check buildsettings for reachUpgrade //Check buildsettings for reachUpgrade
int reachUpgrade = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade(); int reachUpgrade = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade();
switch (reachUpgrade) { switch (reachUpgrade) {
case 0: case 0:
return BuildConfig.reach.maxReachLevel0.get(); return CommonConfig.reach.maxReachLevel0.get();
case 1: case 1:
return BuildConfig.reach.maxReachLevel1.get(); return CommonConfig.reach.maxReachLevel1.get();
case 2: case 2:
return BuildConfig.reach.maxReachLevel2.get(); return CommonConfig.reach.maxReachLevel2.get();
case 3: case 3:
return BuildConfig.reach.maxReachLevel3.get(); return CommonConfig.reach.maxReachLevel3.get();
} }
return BuildConfig.reach.maxReachLevel0.get(); return CommonConfig.reach.maxReachLevel0.get();
} }
public static int getPlacementReach(Player player) { public static int getPlacementReach(Player player) {

View File

@@ -23,7 +23,7 @@ import net.minecraft.world.level.material.Material;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.ForgeEventFactory;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.CommonConfig;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.compatibility.CompatHelper;
@@ -187,17 +187,21 @@ public class SurvivalHelper {
*/ */
public static boolean canPlace(Level world, Player player, BlockPos pos, BlockState newBlockState, ItemStack itemStack, boolean skipCollisionCheck, Direction sidePlacedOn) { public static boolean canPlace(Level world, Player player, BlockPos pos, BlockState newBlockState, ItemStack itemStack, boolean skipCollisionCheck, Direction sidePlacedOn) {
if (!player.isCreative()) {
//Check if itemstack is correct //Check if itemstack is correct
if (!(itemStack.getItem() instanceof BlockItem) || Block.byItem(itemStack.getItem()) != newBlockState.getBlock()) { if (itemStack.isEmpty() || !(itemStack.getItem() instanceof BlockItem) ||
// EffortlessBuilding.log(player, "Cannot (re)place block", true); Block.byItem(itemStack.getItem()) != newBlockState.getBlock()) {
// EffortlessBuilding.log("SurvivalHelper#canPlace: itemstack " + itemStack.toString() + " does not match blockstate " + newBlockState.toString());
//Happens when breaking blocks, no need to notify in that case
return false; return false;
} }
}
Block block = ((BlockItem) itemStack.getItem()).getBlock(); Block block = null;
if (itemStack != null && !itemStack.isEmpty() && itemStack.getItem() instanceof BlockItem)
block = ((BlockItem) itemStack.getItem()).getBlock();
else //In creative we might not have an itemstack
block = newBlockState.getBlock();
return !itemStack.isEmpty() && canPlayerEdit(player, world, pos, itemStack) && return canPlayerEdit(player, world, pos, itemStack) &&
mayPlace(world, block, newBlockState, pos, skipCollisionCheck, sidePlacedOn, player) && mayPlace(world, block, newBlockState, pos, skipCollisionCheck, sidePlacedOn, player) &&
canReplace(world, player, pos); canReplace(world, player, pos);
} }
@@ -208,7 +212,7 @@ public class SurvivalHelper {
BlockState state = world.getBlockState(pos); BlockState state = world.getBlockState(pos);
int miningLevel = BuildConfig.survivalBalancers.quickReplaceMiningLevel.get(); int miningLevel = CommonConfig.survivalBalancers.quickReplaceMiningLevel.get();
switch (miningLevel) { switch (miningLevel) {
case -1: case -1:
return !state.requiresCorrectToolForDrops(); return !state.requiresCorrectToolForDrops();
@@ -245,7 +249,7 @@ public class SurvivalHelper {
//From World#mayPlace //From World#mayPlace
private static boolean mayPlace(Level world, Block blockIn, BlockState newBlockState, BlockPos pos, boolean skipCollisionCheck, Direction sidePlacedOn, @Nullable Entity placer) { private static boolean mayPlace(Level world, Block blockIn, BlockState newBlockState, BlockPos pos, boolean skipCollisionCheck, Direction sidePlacedOn, @Nullable Entity placer) {
BlockState iblockstate1 = world.getBlockState(pos); BlockState currentBlockState = world.getBlockState(pos);
VoxelShape voxelShape = skipCollisionCheck ? null : blockIn.defaultBlockState().getCollisionShape(world, pos); VoxelShape voxelShape = skipCollisionCheck ? null : blockIn.defaultBlockState().getCollisionShape(world, pos);
if (voxelShape != null && !world.isUnobstructed(placer, voxelShape)) { if (voxelShape != null && !world.isUnobstructed(placer, voxelShape)) {
@@ -259,22 +263,20 @@ public class SurvivalHelper {
//Check if same block //Check if same block
//Necessary otherwise extra items will be dropped //Necessary otherwise extra items will be dropped
if (iblockstate1 == newBlockState) { if (currentBlockState == newBlockState) {
return false; return false;
} }
//TODO 1.14 check what Material.CIRCUITS has become if (currentBlockState.getMaterial() == Material.BUILDABLE_GLASS && blockIn == Blocks.ANVIL) {
if (iblockstate1.getMaterial() == Material.BUILDABLE_GLASS && blockIn == Blocks.ANVIL) {
return true; return true;
} }
//Check quickreplace //Check quickreplace
if (placer instanceof Player && ModifierSettingsManager.getModifierSettings(((Player) placer)).doQuickReplace()) { if (placer != null && ModifierSettingsManager.getModifierSettings(((Player) placer)).doQuickReplace()) {
return true; return true;
} }
//TODO 1.13 replaceable return currentBlockState.getMaterial().isReplaceable() /*&& canPlaceBlockOnSide(world, pos, sidePlacedOn)*/;
return iblockstate1.getMaterial().isReplaceable() /*&& canPlaceBlockOnSide(world, pos, sidePlacedOn)*/;
} }

View File

@@ -136,7 +136,7 @@ public abstract class AbstractRandomizerBagItem extends Item {
//Only place manually if in normal vanilla mode //Only place manually if in normal vanilla mode
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
if (buildMode != BuildModes.BuildModeEnum.NORMAL || modifierSettings.doQuickReplace()) { if (buildMode != BuildModes.BuildModeEnum.DISABLED || modifierSettings.doQuickReplace()) {
return InteractionResult.FAIL; return InteractionResult.FAIL;
} }

View File

@@ -9,7 +9,7 @@ import net.minecraft.world.item.ItemStack;
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 nl.requios.effortlessbuilding.BuildConfig; 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;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
@@ -63,7 +63,7 @@ public class ReachUpgrade1Item 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.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + BuildConfig.reach.maxReachLevel1.get())); tooltip.add(Component.literal(ChatFormatting.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + CommonConfig.reach.maxReachLevel1.get()));
} }
} }

View File

@@ -9,14 +9,13 @@ import net.minecraft.world.item.ItemStack;
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 nl.requios.effortlessbuilding.BuildConfig; 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;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import java.awt.*;
import java.util.List; import java.util.List;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@@ -68,7 +67,7 @@ public class ReachUpgrade2Item 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.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + BuildConfig.reach.maxReachLevel2.get())); tooltip.add(Component.literal(ChatFormatting.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + CommonConfig.reach.maxReachLevel2.get()));
tooltip.add(Component.literal(ChatFormatting.GRAY + "Previous upgrades need to be consumed first")); tooltip.add(Component.literal(ChatFormatting.GRAY + "Previous upgrades need to be consumed first"));
} }
} }

View File

@@ -9,7 +9,7 @@ import net.minecraft.world.item.ItemStack;
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 nl.requios.effortlessbuilding.BuildConfig; 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;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
@@ -70,7 +70,7 @@ public class ReachUpgrade3Item 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.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + BuildConfig.reach.maxReachLevel3.get())); tooltip.add(Component.literal(ChatFormatting.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + CommonConfig.reach.maxReachLevel3.get()));
tooltip.add(Component.literal(ChatFormatting.GRAY + "Previous upgrades need to be consumed first")); tooltip.add(Component.literal(ChatFormatting.GRAY + "Previous upgrades need to be consumed first"));
} }

View File

@@ -14,7 +14,6 @@ import net.minecraftforge.network.NetworkEvent;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.BlockSet; import nl.requios.effortlessbuilding.buildmodifier.BlockSet;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.function.Supplier; import java.util.function.Supplier;

View File

@@ -12,7 +12,7 @@ import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.network.NetworkEvent; import net.minecraftforge.network.NetworkEvent;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; import nl.requios.effortlessbuilding.render.BlockPreviews;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -112,7 +112,7 @@ public class BlockPlacedMessage {
public static class ClientHandler { public static class ClientHandler {
public static void handle(BlockPlacedMessage message, Supplier<NetworkEvent.Context> ctx) { public static void handle(BlockPlacedMessage message, Supplier<NetworkEvent.Context> ctx) {
//Nod RenderHandler to do the dissolve shader effect //Nod RenderHandler to do the dissolve shader effect
BlockPreviewRenderer.onBlocksPlaced(); BlockPreviews.onBlocksPlaced();
} }
} }
} }

View File

@@ -9,7 +9,6 @@ import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.network.NetworkEvent; import net.minecraftforge.network.NetworkEvent;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer;
import java.util.function.Supplier; import java.util.function.Supplier;

View File

@@ -11,8 +11,6 @@ import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.network.NetworkEvent; import net.minecraftforge.network.NetworkEvent;
import nl.requios.effortlessbuilding.ClientEvents; import nl.requios.effortlessbuilding.ClientEvents;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer;
import java.util.function.Supplier; import java.util.function.Supplier;

View File

@@ -1,412 +0,0 @@
package nl.requios.effortlessbuilding.render;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundSource;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.ClientEvents;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.create.AllSpecialTextures;
import nl.requios.effortlessbuilding.create.CreateClient;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@OnlyIn(Dist.CLIENT)
public class BlockPreviewRenderer {
private static final List<PlacedData> placedDataList = new ArrayList<>();
private static List<BlockPos> previousCoordinates;
private static List<BlockState> previousBlockStates;
private static List<ItemStack> previousItemStacks;
private static BlockPos previousFirstPos;
private static BlockPos previousSecondPos;
private static int soundTime = 0;
public static void render(PoseStack ms, MultiBufferSource.BufferSource buffer, Player player, ModifierSettings modifierSettings, ModeSettings modeSettings) {
//Render placed blocks with dissolve effect
//Use fancy shader if config allows, otherwise no dissolve
if (BuildConfig.visuals.useShaders.get()) {
for (int i = 0; i < placedDataList.size(); i++) {
PlacedData placed = placedDataList.get(i);
if (placed.coordinates != null && !placed.coordinates.isEmpty()) {
double totalTime = Mth.clampedLerp(30, 60, placed.firstPos.distSqr(placed.secondPos) / 100.0) * BuildConfig.visuals.dissolveTimeMultiplier.get();
float dissolve = (ClientEvents.ticksInGame - placed.time) / (float) totalTime;
renderBlockPreviews(ms, buffer, placed.coordinates, placed.blockStates, placed.itemStacks, dissolve, placed.firstPos, placed.secondPos, false, placed.breaking);
}
}
}
//Expire
placedDataList.removeIf(placed -> {
double totalTime = Mth.clampedLerp(30, 60, placed.firstPos.distSqr(placed.secondPos) / 100.0) * BuildConfig.visuals.dissolveTimeMultiplier.get();
return placed.time + totalTime < ClientEvents.ticksInGame;
});
//Render block previews
HitResult lookingAt = ClientEvents.getLookingAt(player);
if (modeSettings.getBuildMode() == BuildModes.BuildModeEnum.NORMAL)
lookingAt = Minecraft.getInstance().hitResult;
ItemStack mainhand = player.getMainHandItem();
boolean noBlockInHand = !(!mainhand.isEmpty() && CompatHelper.isItemBlockProxy(mainhand));
BlockPos startPos = null;
Direction sideHit = null;
Vec3 hitVec = null;
//Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS)
if (lookingAt != null && lookingAt.getType() == HitResult.Type.BLOCK) {
BlockHitResult blockLookingAt = (BlockHitResult) lookingAt;
startPos = blockLookingAt.getBlockPos();
//Check if tool (or none) in hand
//TODO 1.13 replaceable
boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable();
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos, blockLookingAt.getDirection());
if (!modifierSettings.doQuickReplace() && !noBlockInHand && !replaceable && !becomesDoubleSlab) {
startPos = startPos.relative(blockLookingAt.getDirection());
}
//Get under tall grass and other replaceable blocks
if (modifierSettings.doQuickReplace() && !noBlockInHand && replaceable) {
startPos = startPos.below();
}
sideHit = blockLookingAt.getDirection();
hitVec = blockLookingAt.getLocation();
}
//Dont render if in normal mode and modifiers are disabled
//Unless alwaysShowBlockPreview is true in config
if (doRenderBlockPreviews(modifierSettings, modeSettings, startPos)) {
//Keep blockstate the same for every block in the buildmode
//So dont rotate blocks when in the middle of placing wall etc.
if (BuildModes.isActive(player)) {
IBuildMode buildModeInstance = modeSettings.getBuildMode().instance;
if (buildModeInstance.getSideHit(player) != null) sideHit = buildModeInstance.getSideHit(player);
if (buildModeInstance.getHitVec(player) != null) hitVec = buildModeInstance.getHitVec(player);
}
if (sideHit != null) {
//Should be red?
boolean breaking = BuildModes.currentlyBreakingClient.get(player) != null && BuildModes.currentlyBreakingClient.get(player);
//get coordinates
List<BlockPos> startCoordinates = BuildModes.findCoordinates(player, startPos, breaking || modifierSettings.doQuickReplace());
//Remember first and last point for the shader
BlockPos firstPos = BlockPos.ZERO, secondPos = BlockPos.ZERO;
if (!startCoordinates.isEmpty()) {
firstPos = startCoordinates.get(0);
secondPos = startCoordinates.get(startCoordinates.size() - 1);
}
//Limit number of blocks you can place
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
if (startCoordinates.size() > limit) {
startCoordinates = startCoordinates.subList(0, limit);
}
List<BlockPos> newCoordinates = BuildModifiers.findCoordinates(player, startCoordinates);
sortOnDistanceToPlayer(newCoordinates, player);
hitVec = new Vec3(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)),
Math.abs(hitVec.z - ((int) hitVec.z)));
//Get blockstates
List<ItemStack> itemStacks = new ArrayList<>();
List<BlockState> blockStates = new ArrayList<>();
if (breaking) {
//Find blockstate of world
for (BlockPos coordinate : newCoordinates) {
blockStates.add(player.level.getBlockState(coordinate));
}
} else {
blockStates = BuildModifiers.findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks);
}
//Check if they are different from previous
//TODO fix triggering when moving player
if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) {
previousCoordinates = newCoordinates;
//remember the rest for placed blocks
previousBlockStates = blockStates;
previousItemStacks = itemStacks;
previousFirstPos = firstPos;
previousSecondPos = secondPos;
//if so, renew randomness of randomizer bag
AbstractRandomizerBagItem.renewRandomness();
//and play sound (max once every tick)
if (newCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientEvents.ticksInGame - 0) {
soundTime = ClientEvents.ticksInGame;
if (blockStates.get(0) != null) {
SoundType soundType = blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.level,
newCoordinates.get(0), player);
player.level.playSound(player, player.blockPosition(), breaking ? soundType.getBreakSound() : soundType.getPlaceSound(),
SoundSource.BLOCKS, 0.3f, 0.8f);
}
}
}
//Render block previews
if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) {
int blockCount;
if (!breaking) {
//Use fancy shader if config allows, otherwise outlines
if (BuildConfig.visuals.useShaders.get() && newCoordinates.size() < BuildConfig.visuals.shaderThreshold.get()) {
blockCount = renderBlockPreviews(ms, buffer, newCoordinates, blockStates, itemStacks, 0f, firstPos, secondPos, !breaking, breaking);
CreateClient.OUTLINER.showCluster("blockpreviews", newCoordinates)
.withFaceTexture(AllSpecialTextures.CHECKERED)
.disableNormals()
.lineWidth(1 / 32f)
.colored(new Color(1f, 1f, 1f, 1f));
} else {
// VertexConsumer vc = RenderHandler.beginLines(buffer);
//
// Vec3 color = new Vec3(1f, 1f, 1f);
// if (breaking) color = new Vec3(1f, 0f, 0f);
//
// for (int i = newCoordinates.size() - 1; i >= 0; i--) {
// VoxelShape collisionShape = blockStates.get(i).getCollisionShape(player.level, newCoordinates.get(i));
// RenderHandler.renderBlockOutline(ms, vc, newCoordinates.get(i), collisionShape, color);
// }
//
// RenderHandler.endLines(buffer);
CreateClient.OUTLINER.showCluster("blockpreviews", newCoordinates)
.withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED)
.disableNormals()
.lineWidth(1 / 16f)
.colored(new Color(1f, 1f, 1f, 1f));
blockCount = newCoordinates.size();
}
} else {
//Breaking
CreateClient.OUTLINER.showCluster("blockpreviews", newCoordinates)
.withFaceTexture(AllSpecialTextures.THIN_CHECKERED)
.disableNormals()
.lineWidth(1 / 16f)
.colored(new Color(0.8f, 0.1f, 0.1f, 1f));
blockCount = newCoordinates.size();
}
//Display block count and dimensions in actionbar
if (BuildModes.isActive(player)) {
//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 minY = Integer.MAX_VALUE, maxY = Integer.MIN_VALUE;
int minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE;
for (BlockPos pos : startCoordinates) {
if (pos.getX() < minX) minX = pos.getX();
if (pos.getX() > maxX) maxX = pos.getX();
if (pos.getY() < minY) minY = pos.getY();
if (pos.getY() > maxY) maxY = pos.getY();
if (pos.getZ() < minZ) minZ = pos.getZ();
if (pos.getZ() > maxZ) maxZ = pos.getZ();
}
BlockPos dim = new BlockPos(maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1);
String dimensions = "(";
if (dim.getX() > 1) dimensions += dim.getX() + "x";
if (dim.getZ() > 1) dimensions += dim.getZ() + "x";
if (dim.getY() > 1) dimensions += dim.getY() + "x";
dimensions = dimensions.substring(0, dimensions.length() - 1);
if (dimensions.length() > 1) dimensions += ")";
EffortlessBuilding.log(player, blockCount + " blocks " + dimensions, true);
}
}
}
//Draw outlines if no block in hand
//Find proper raytrace: either normal range or increased range depending on canBreakFar
// VertexConsumer vc = RenderHandler.beginLines(buffer);
// HitResult objectMouseOver = Minecraft.getInstance().hitResult;
// HitResult breakingRaytrace = ReachHelper.canBreakFar(player) ? lookingAt : objectMouseOver;
//
// if (player.isCreative() && noBlockInHand && breakingRaytrace != null && breakingRaytrace.getType() == HitResult.Type.BLOCK) {
// BlockHitResult blockBreakingRaytrace = (BlockHitResult) breakingRaytrace;
// List<BlockPos> breakCoordinates = BuildModifiers.findCoordinates(player, blockBreakingRaytrace.getBlockPos());
//
// //Only render first outline if further than normal reach
// boolean excludeFirst = objectMouseOver != null && objectMouseOver.getType() == HitResult.Type.BLOCK;
// for (int i = excludeFirst ? 1 : 0; i < breakCoordinates.size(); i++) {
// BlockPos coordinate = breakCoordinates.get(i);
//
// BlockState blockState = player.level.getBlockState(coordinate);
// if (!blockState.isAir()) {
// if (SurvivalHelper.canBreak(player.level, player, coordinate) || i == 0) {
// VoxelShape collisionShape = blockState.getCollisionShape(player.level, coordinate);
// RenderHandler.renderBlockOutline(ms, vc, coordinate, collisionShape, new Vec3(0f, 0f, 0f));
// }
// }
// }
// }
// RenderHandler.endLines(buffer);
}
}
//Whether to draw any block previews or outlines
public static boolean doRenderBlockPreviews(ModifierSettings modifierSettings, ModeSettings modeSettings, BlockPos startPos) {
return modeSettings.getBuildMode() != BuildModes.BuildModeEnum.NORMAL ||
(startPos != null && BuildModifiers.isEnabled(modifierSettings, startPos)) ||
BuildConfig.visuals.alwaysShowBlockPreview.get();
}
protected static int renderBlockPreviews(PoseStack matrixStack, MultiBufferSource.BufferSource renderTypeBuffer, List<BlockPos> coordinates, List<BlockState> blockStates,
List<ItemStack> itemStacks, float dissolve, BlockPos firstPos,
BlockPos secondPos, boolean checkCanPlace, boolean red) {
Player player = Minecraft.getInstance().player;
ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
BlockRenderDispatcher dispatcher = Minecraft.getInstance().getBlockRenderer();
int blocksValid = 0;
if (coordinates.isEmpty()) return blocksValid;
for (int i = coordinates.size() - 1; i >= 0; i--) {
BlockPos blockPos = coordinates.get(i);
BlockState blockState = blockStates.get(i);
ItemStack itemstack = itemStacks.isEmpty() ? ItemStack.EMPTY : itemStacks.get(i);
if (CompatHelper.isItemBlockProxy(itemstack))
itemstack = CompatHelper.getItemBlockByState(itemstack, blockState);
//Check if we can place
//If check is turned off, check if blockstate is the same (for dissolve effect)
if ((!checkCanPlace && player.level.getBlockState(blockPos) == blockState) || //TODO enable (breaks the breaking shader)
SurvivalHelper.canPlace(player.level, player, blockPos, blockState, itemstack, modifierSettings.doQuickReplace(), Direction.UP)) {
RenderHandler.renderBlockPreview(matrixStack, renderTypeBuffer, dispatcher, blockPos, blockState, dissolve, firstPos, secondPos, red);
blocksValid++;
}
}
return blocksValid;
}
public static void onBlocksPlaced() {
onBlocksPlaced(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos);
}
public static void onBlocksPlaced(List<BlockPos> coordinates, List<ItemStack> itemStacks, List<BlockState> blockStates,
BlockPos firstPos, BlockPos secondPos) {
LocalPlayer player = Minecraft.getInstance().player;
ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Check if block previews are enabled
if (doRenderBlockPreviews(modifierSettings, modeSettings, firstPos)) {
//Save current coordinates, blockstates and itemstacks
if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() &&
coordinates.size() > 1 && coordinates.size() < BuildConfig.visuals.shaderThreshold.get()) {
placedDataList.add(new PlacedData(ClientEvents.ticksInGame, coordinates, blockStates,
itemStacks, firstPos, secondPos, false));
}
}
}
public static void onBlocksBroken() {
onBlocksBroken(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos);
}
public static void onBlocksBroken(List<BlockPos> coordinates, List<ItemStack> itemStacks, List<BlockState> blockStates,
BlockPos firstPos, BlockPos secondPos) {
LocalPlayer player = Minecraft.getInstance().player;
ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Check if block previews are enabled
if (doRenderBlockPreviews(modifierSettings, modeSettings, firstPos)) {
//Save current coordinates, blockstates and itemstacks
if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() &&
coordinates.size() > 1 && coordinates.size() < BuildConfig.visuals.shaderThreshold.get()) {
sortOnDistanceToPlayer(coordinates, player);
placedDataList.add(new PlacedData(ClientEvents.ticksInGame, coordinates, blockStates,
itemStacks, firstPos, secondPos, true));
}
}
}
private static void sortOnDistanceToPlayer(List<BlockPos> coordinates, Player player) {
Collections.sort(coordinates, (lhs, rhs) -> {
// -1 - less than, 1 - greater than, 0 - equal
double lhsDistanceToPlayer = Vec3.atLowerCornerOf(lhs).subtract(player.getEyePosition(1f)).lengthSqr();
double rhsDistanceToPlayer = Vec3.atLowerCornerOf(rhs).subtract(player.getEyePosition(1f)).lengthSqr();
return (int) Math.signum(lhsDistanceToPlayer - rhsDistanceToPlayer);
});
}
static class PlacedData {
float time;
List<BlockPos> coordinates;
List<BlockState> blockStates;
List<ItemStack> itemStacks;
BlockPos firstPos;
BlockPos secondPos;
boolean breaking;
public PlacedData(float time, List<BlockPos> coordinates, List<BlockState> blockStates,
List<ItemStack> itemStacks, BlockPos firstPos, BlockPos secondPos, boolean breaking) {
this.time = time;
this.coordinates = coordinates;
this.blockStates = blockStates;
this.itemStacks = itemStacks;
this.firstPos = firstPos;
this.secondPos = secondPos;
this.breaking = breaking;
}
}
}

View File

@@ -0,0 +1,414 @@
package nl.requios.effortlessbuilding.render;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundSource;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.util.Mth;
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.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.create.AllSpecialTextures;
import nl.requios.effortlessbuilding.create.CreateClient;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@OnlyIn(Dist.CLIENT)
public class BlockPreviews {
private static final List<PlacedData> placedDataList = new ArrayList<>();
private static List<BlockPos> previousCoordinates;
private static List<BlockState> previousBlockStates;
private static List<ItemStack> previousItemStacks;
private static BlockPos previousFirstPos;
private static BlockPos previousSecondPos;
private static int soundTime = 0;
public static void drawPlacedBlocks(Player player, ModifierSettings modifierSettings) {
//Render placed blocks with appear animation
if (ClientConfig.visuals.showBlockPreviews.get()) {
for (PlacedData placed : placedDataList) {
if (placed.coordinates != null && !placed.coordinates.isEmpty()) {
int totalTime = placed.breaking ? CommonConfig.visuals.breakAnimationLength.get() : CommonConfig.visuals.appearAnimationLength.get();
if (totalTime <= 0) continue;
float dissolve = (ClientEvents.ticksInGame - placed.time) / (float) totalTime;
renderBlockPreviews(player, modifierSettings, placed.coordinates, placed.blockStates, placed.itemStacks, dissolve, placed.firstPos, placed.secondPos, false, placed.breaking);
CreateClient.OUTLINER.showCluster(placed.time, placed.coordinates);
}
}
}
//Expire
placedDataList.removeIf(placed -> {
int totalTime = placed.breaking ? CommonConfig.visuals.breakAnimationLength.get() : CommonConfig.visuals.appearAnimationLength.get();
return placed.time + totalTime < ClientEvents.ticksInGame;
});
}
public static void drawLookAtPreview(Player player, ModeSettings modeSettings, ModifierSettings modifierSettings, BlockPos startPos, Direction sideHit, Vec3 hitVec) {
if (!doShowBlockPreviews(modifierSettings, modeSettings, startPos)) return;
//Keep blockstate the same for every block in the buildmode
//So dont rotate blocks when in the middle of placing wall etc.
if (BuildModes.isActive(player)) {
IBuildMode buildModeInstance = modeSettings.getBuildMode().instance;
if (buildModeInstance.getSideHit(player) != null) sideHit = buildModeInstance.getSideHit(player);
if (buildModeInstance.getHitVec(player) != null) hitVec = buildModeInstance.getHitVec(player);
}
if (sideHit == null) return;
//Should be red?
boolean breaking = BuildModes.currentlyBreakingClient.get(player) != null && BuildModes.currentlyBreakingClient.get(player);
//get coordinates
List<BlockPos> startCoordinates = BuildModes.findCoordinates(player, startPos, breaking || modifierSettings.doQuickReplace());
//Remember first and last point for the shader
BlockPos firstPos = BlockPos.ZERO, secondPos = BlockPos.ZERO;
if (!startCoordinates.isEmpty()) {
firstPos = startCoordinates.get(0);
secondPos = startCoordinates.get(startCoordinates.size() - 1);
}
//Limit number of blocks you can place
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
if (startCoordinates.size() > limit) {
startCoordinates = startCoordinates.subList(0, limit);
}
List<BlockPos> newCoordinates = BuildModifiers.findCoordinates(player, startCoordinates);
sortOnDistanceToPlayer(newCoordinates, player);
hitVec = new Vec3(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)),
Math.abs(hitVec.z - ((int) hitVec.z)));
//Get blockstates
List<ItemStack> itemStacks = new ArrayList<>();
List<BlockState> blockStates = new ArrayList<>();
if (breaking) {
//Find blockstate of world
for (BlockPos coordinate : newCoordinates) {
blockStates.add(player.level.getBlockState(coordinate));
}
} else {
blockStates = BuildModifiers.findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks);
}
//Check if they are different from previous
//TODO fix triggering when moving player
if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) {
previousCoordinates = newCoordinates;
//remember the rest for placed blocks
previousBlockStates = blockStates;
previousItemStacks = itemStacks;
previousFirstPos = firstPos;
previousSecondPos = secondPos;
//if so, renew randomness of randomizer bag
AbstractRandomizerBagItem.renewRandomness();
//and play sound (max once every tick)
if (newCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientEvents.ticksInGame - 0) {
soundTime = ClientEvents.ticksInGame;
if (blockStates.get(0) != null) {
SoundType soundType = blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.level,
newCoordinates.get(0), player);
player.level.playSound(player, player.blockPosition(), breaking ? soundType.getBreakSound() : soundType.getPlaceSound(),
SoundSource.BLOCKS, 0.3f, 0.8f);
}
}
}
if (blockStates.size() == 0 || newCoordinates.size() != blockStates.size()) return;
int blockCount;
Object outlineID = firstPos;
//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)
if (newCoordinates.size() == 1 || BuildModifiers.isEnabled(modifierSettings, firstPos)) outlineID = "single";
if (!breaking) {
//Use fancy shader if config allows, otherwise outlines
if (ClientConfig.visuals.showBlockPreviews.get() && newCoordinates.size() < ClientConfig.visuals.maxBlockPreviews.get()) {
blockCount = renderBlockPreviews(player, modifierSettings, newCoordinates, blockStates, itemStacks, 0f, firstPos, secondPos, !breaking, breaking);
CreateClient.OUTLINER.showCluster(outlineID, newCoordinates)
.withFaceTexture(AllSpecialTextures.CHECKERED)
.disableNormals()
.lineWidth(1 / 32f)
.colored(new Color(1f, 1f, 1f, 1f));
} else {
//Thicker outline without block previews
CreateClient.OUTLINER.showCluster(outlineID, newCoordinates)
.withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED)
.disableNormals()
.lineWidth(1 / 16f)
.colored(new Color(1f, 1f, 1f, 1f));
blockCount = newCoordinates.size();
}
} else {
//Breaking
CreateClient.OUTLINER.showCluster(outlineID, newCoordinates)
.withFaceTexture(AllSpecialTextures.THIN_CHECKERED)
.disableNormals()
.lineWidth(1 / 16f)
.colored(new Color(0.8f, 0.1f, 0.1f, 1f));
blockCount = newCoordinates.size();
}
//Display block count and dimensions in actionbar
if (BuildModes.isActive(player)) {
//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 minY = Integer.MAX_VALUE, maxY = Integer.MIN_VALUE;
int minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE;
for (BlockPos pos : startCoordinates) {
if (pos.getX() < minX) minX = pos.getX();
if (pos.getX() > maxX) maxX = pos.getX();
if (pos.getY() < minY) minY = pos.getY();
if (pos.getY() > maxY) maxY = pos.getY();
if (pos.getZ() < minZ) minZ = pos.getZ();
if (pos.getZ() > maxZ) maxZ = pos.getZ();
}
BlockPos dim = new BlockPos(maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1);
String dimensions = "(";
if (dim.getX() > 1) dimensions += dim.getX() + "x";
if (dim.getZ() > 1) dimensions += dim.getZ() + "x";
if (dim.getY() > 1) dimensions += dim.getY() + "x";
dimensions = dimensions.substring(0, dimensions.length() - 1);
if (dimensions.length() > 1) dimensions += ")";
EffortlessBuilding.log(player, blockCount + " blocks " + dimensions, true);
}
}
public static void drawOutlinesIfNoBlockInHand(Player player, HitResult lookingAt) {
//Draw outlines if no block in hand
//Find proper raytrace: either normal range or increased range depending on canBreakFar
HitResult objectMouseOver = Minecraft.getInstance().hitResult;
HitResult breakingRaytrace = ReachHelper.canBreakFar(player) ? lookingAt : objectMouseOver;
if (player.isCreative() && breakingRaytrace != null && breakingRaytrace.getType() == HitResult.Type.BLOCK) {
BlockHitResult blockBreakingRaytrace = (BlockHitResult) breakingRaytrace;
List<BlockPos> breakCoordinates = BuildModifiers.findCoordinates(player, blockBreakingRaytrace.getBlockPos());
//Only render first outline if further than normal reach
if (objectMouseOver != null && objectMouseOver.getType() == HitResult.Type.BLOCK)
breakCoordinates.remove(0);
breakCoordinates.removeIf(pos -> {
BlockState blockState = player.level.getBlockState(pos);
if (blockState.isAir() || blockState.getMaterial().isLiquid()) return true;
return !SurvivalHelper.canBreak(player.level, player, pos);
});
if (!breakCoordinates.isEmpty()) {
CreateClient.OUTLINER.showCluster("break", breakCoordinates)
.disableNormals()
.lineWidth(1 / 64f)
.colored(0x222222);
}
}
}
//Whether to draw any block previews or outlines
public static boolean doShowBlockPreviews(ModifierSettings modifierSettings, ModeSettings modeSettings, BlockPos startPos) {
if (!ClientConfig.visuals.showBlockPreviews.get()) return false;
return modeSettings.getBuildMode() != BuildModes.BuildModeEnum.DISABLED ||
(startPos != null && BuildModifiers.isEnabled(modifierSettings, startPos)) ||
ClientConfig.visuals.alwaysShowBlockPreview.get();
}
protected static int renderBlockPreviews(Player player, ModifierSettings modifierSettings, List<BlockPos> coordinates,
List<BlockState> blockStates, List<ItemStack> itemStacks, float dissolve,
BlockPos firstPos, BlockPos secondPos, boolean checkCanPlace, boolean red) {
int blocksValid = 0;
if (coordinates.isEmpty()) return blocksValid;
for (int i = coordinates.size() - 1; i >= 0; i--) {
BlockPos blockPos = coordinates.get(i);
BlockState blockState = blockStates.get(i);
ItemStack itemstack = itemStacks.isEmpty() ? ItemStack.EMPTY : itemStacks.get(i);
if (CompatHelper.isItemBlockProxy(itemstack))
itemstack = CompatHelper.getItemBlockByState(itemstack, blockState);
//Check if we can place
boolean canPlace = true;
if (checkCanPlace) {
canPlace = SurvivalHelper.canPlace(player.level, player, blockPos, blockState, itemstack, modifierSettings.doQuickReplace(), Direction.UP);
} else {
//If check is turned off, check if blockstate is the same (for dissolve effect)
canPlace = player.level.getBlockState(blockPos) != blockState;
}
if (canPlace) {
renderBlockPreview(blockPos, blockState, dissolve, firstPos, secondPos, red);
blocksValid++;
}
}
return blocksValid;
}
protected static void renderBlockPreview(BlockPos blockPos, BlockState blockState, float dissolve, BlockPos firstPos, BlockPos secondPos, boolean breaking) {
if (blockState == null) return;
float scale = 0.5f;
float alpha = 0.7f;
if (dissolve > 0f) {
float animationLength = 0.7f;
double firstToSecond = secondPos.distSqr(firstPos);
double place = 0;
if (firstToSecond > 0.5) {
double placeFromFirst = firstPos.distSqr(blockPos) / firstToSecond;
double placeFromSecond = secondPos.distSqr(blockPos) / firstToSecond;
place = (placeFromFirst + (1.0 - placeFromSecond)) / 2.0;
} //else only one block
//Scale place so we start first animation at 0 and end last animation at 1
place *= 1f - animationLength;
float diff = dissolve - (float) place;
float t = diff / animationLength;
t = Mth.clamp(t, 0, 1);
//Now we got a usable t value for this block
float sine = Mth.sin((t + (1/7f) * t) * Mth.TWO_PI - (3/4f) * Mth.PI); // -1 to 1
sine = (sine + 1f) / 2f; // 0 to 1
// scale = 1f + (sine * 0.5f);
t = (float) Mth.smoothstep(t);
if (!breaking) {
scale = 0.5f + (t * 0.3f);
alpha = 0.7f + (t * 0.3f);
} else {
t = 1f - t;
scale = 0.5f + (t * 0.5f);
alpha = t;
}
}
CreateClient.GHOST_BLOCKS.showGhostState(blockPos.toShortString(), blockState)
.at(blockPos)
.alpha(alpha)
.scale(scale);
}
public static void onBlocksPlaced() {
onBlocksPlaced(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos);
}
public static void onBlocksPlaced(List<BlockPos> coordinates, List<ItemStack> itemStacks, List<BlockState> blockStates,
BlockPos firstPos, BlockPos secondPos) {
LocalPlayer player = Minecraft.getInstance().player;
ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Check if block previews are enabled
if (doShowBlockPreviews(modifierSettings, modeSettings, firstPos)) {
//Save current coordinates, blockstates and itemstacks
if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() &&
coordinates.size() > 1 && coordinates.size() < ClientConfig.visuals.maxBlockPreviews.get()) {
placedDataList.add(new PlacedData(ClientEvents.ticksInGame, coordinates, blockStates,
itemStacks, firstPos, secondPos, false));
}
}
}
public static void onBlocksBroken() {
onBlocksBroken(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos);
}
public static void onBlocksBroken(List<BlockPos> coordinates, List<ItemStack> itemStacks, List<BlockState> blockStates,
BlockPos firstPos, BlockPos secondPos) {
LocalPlayer player = Minecraft.getInstance().player;
ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Check if block previews are enabled
if (doShowBlockPreviews(modifierSettings, modeSettings, firstPos)) {
//Save current coordinates, blockstates and itemstacks
if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() &&
coordinates.size() > 1 && coordinates.size() < ClientConfig.visuals.maxBlockPreviews.get()) {
sortOnDistanceToPlayer(coordinates, player);
placedDataList.add(new PlacedData(ClientEvents.ticksInGame, coordinates, blockStates,
itemStacks, firstPos, secondPos, true));
}
}
}
private static void sortOnDistanceToPlayer(List<BlockPos> coordinates, Player player) {
Collections.sort(coordinates, (lhs, rhs) -> {
// -1 - less than, 1 - greater than, 0 - equal
double lhsDistanceToPlayer = Vec3.atLowerCornerOf(lhs).subtract(player.getEyePosition(1f)).lengthSqr();
double rhsDistanceToPlayer = Vec3.atLowerCornerOf(rhs).subtract(player.getEyePosition(1f)).lengthSqr();
return (int) Math.signum(lhsDistanceToPlayer - rhsDistanceToPlayer);
});
}
static class PlacedData {
float time;
List<BlockPos> coordinates;
List<BlockState> blockStates;
List<ItemStack> itemStacks;
BlockPos firstPos;
BlockPos secondPos;
boolean breaking;
public PlacedData(float time, List<BlockPos> coordinates, List<BlockState> blockStates,
List<ItemStack> itemStacks, BlockPos firstPos, BlockPos secondPos, boolean breaking) {
this.time = time;
this.coordinates = coordinates;
this.blockStates = blockStates;
this.itemStacks = itemStacks;
this.firstPos = firstPos;
this.secondPos = secondPos;
this.breaking = breaking;
}
}
}

View File

@@ -5,32 +5,25 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.Sheets;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderLevelLastEvent;
import net.minecraftforge.client.event.RenderLevelStageEvent; import net.minecraftforge.client.event.RenderLevelStageEvent;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.ClientEvents;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.create.CreateClient; import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.create.events.ClientEvents; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
/*** /***
* Main render class for Effortless Building * Main render class for Effortless Building
@@ -40,26 +33,64 @@ public class RenderHandler {
@SubscribeEvent @SubscribeEvent
public static void onTick(TickEvent.ClientTickEvent event) { public static void onTick(TickEvent.ClientTickEvent event) {
if (!ClientEvents.isGameActive()) return; if (!nl.requios.effortlessbuilding.create.events.ClientEvents.isGameActive()) return;
Player player = Minecraft.getInstance().player; var player = Minecraft.getInstance().player;
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); var modeSettings = ModeSettingsManager.getModeSettings(player);
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); var modifierSettings = ModifierSettingsManager.getModifierSettings(player);
BlockPreviewRenderer.render(null, null, player, modifierSettings, modeSettings); BlockPreviews.drawPlacedBlocks(player, modifierSettings);
HitResult lookingAt = ClientEvents.getLookingAt(player);
if (modeSettings.getBuildMode() == BuildModes.BuildModeEnum.DISABLED)
lookingAt = Minecraft.getInstance().hitResult;
ItemStack mainhand = player.getMainHandItem();
boolean noBlockInHand = !(!mainhand.isEmpty() && CompatHelper.isItemBlockProxy(mainhand));
//Find start position, side hit and hit vector
BlockPos startPos = null;
Direction sideHit = null;
Vec3 hitVec = null;
//Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS)
if (lookingAt != null && lookingAt.getType() == HitResult.Type.BLOCK) {
BlockHitResult blockLookingAt = (BlockHitResult) lookingAt;
startPos = blockLookingAt.getBlockPos();
//Check if tool (or none) in hand
boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable();
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos, blockLookingAt.getDirection());
if (!modifierSettings.doQuickReplace() && !noBlockInHand && !replaceable && !becomesDoubleSlab) {
startPos = startPos.relative(blockLookingAt.getDirection());
}
//Get under tall grass and other replaceable blocks
if (modifierSettings.doQuickReplace() && !noBlockInHand && replaceable) {
startPos = startPos.below();
}
sideHit = blockLookingAt.getDirection();
hitVec = blockLookingAt.getLocation();
}
BlockPreviews.drawLookAtPreview(player, modeSettings, modifierSettings, startPos, sideHit, hitVec);
if (noBlockInHand) BlockPreviews.drawOutlinesIfNoBlockInHand(player, lookingAt);
} }
@SubscribeEvent @SubscribeEvent
public static void onRender(RenderLevelLastEvent event) { public static void onRender(RenderLevelStageEvent event) {
if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) return;
Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition(); Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition();
// float pt = AnimationTickHolder.getPartialTicks();
PoseStack ms = event.getPoseStack(); PoseStack ms = event.getPoseStack();
BufferBuilder bufferBuilder = Tesselator.getInstance().getBuilder(); BufferBuilder bufferBuilder = Tesselator.getInstance().getBuilder();
MultiBufferSource.BufferSource buffer = MultiBufferSource.immediate(bufferBuilder); MultiBufferSource.BufferSource buffer = MultiBufferSource.immediate(bufferBuilder);
// SuperRenderTypeBuffer superBuffer = SuperRenderTypeBuffer.getInstance();
Player player = Minecraft.getInstance().player; Player player = Minecraft.getInstance().player;
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
@@ -70,15 +101,6 @@ public class RenderHandler {
//Mirror and radial mirror lines and areas //Mirror and radial mirror lines and areas
ModifierRenderer.render(ms, buffer, modifierSettings); ModifierRenderer.render(ms, buffer, modifierSettings);
//Render block previews
BlockPreviewRenderer.render(ms, buffer, player, modifierSettings, modeSettings);
//Create
// CreateClient.GHOST_BLOCKS.renderAll(ms, superBuffer);
// EffortlessBuildingClient.OUTLINER.renderOutlines(ms, superBuffer, pt);
// superBuffer.draw();
// RenderSystem.enableCull();
ms.popPose(); ms.popPose();
} }
@@ -98,82 +120,4 @@ public class RenderHandler {
renderTypeBuffer.endBatch(); renderTypeBuffer.endBatch();
} }
protected static void renderBlockPreview(PoseStack ms, MultiBufferSource.BufferSource buffer, BlockRenderDispatcher dispatcher,
BlockPos blockPos, BlockState blockState, float dissolve, BlockPos firstPos, BlockPos secondPos, boolean red) {
if (blockState == null) return;
CreateClient.GHOST_BLOCKS.showGhostState(blockPos.toShortString(), blockState)
// .breathingAlpha()
.alpha(0.7f)
.at(blockPos);
// ms.pushPose();
// ms.translate(blockPos.getX(), blockPos.getY(), blockPos.getZ());
//// ms.rotate(Vector3f.YP.rotationDegrees(-90f));
// ms.translate(-0.01f, -0.01f, -0.01f);
// ms.scale(1.02f, 1.02f, 1.02f);
//
// //Begin block preview rendering
// RenderType blockPreviewRenderType = BuildRenderTypes.getBlockPreviewRenderType(dissolve, blockPos, firstPos, secondPos, red);
// VertexConsumer vc = buffer.getBuffer(blockPreviewRenderType);
//
// try {
// BakedModel model = dispatcher.getBlockModel(blockState);
// dispatcher.getModelRenderer().renderModel(ms.last(), vc, blockState, model,
// 1f, 1f, 1f, 0, OverlayTexture.NO_OVERLAY, ModelData.EMPTY, blockPreviewRenderType);
// } catch (NullPointerException e) {
// EffortlessBuilding.logger.warn("RenderHandler::renderBlockPreview cannot render " + blockState.getBlock().toString());
//
// //Render outline as backup, escape out of the current renderstack
// ms.popPose();
// buffer.endBatch();
// VertexConsumer lineBuffer = beginLines(buffer);
// renderBlockOutline(ms, lineBuffer, blockPos, new Vec3(1f, 1f, 1f));
// endLines(buffer);
// vc = buffer.getBuffer(Sheets.translucentCullBlockSheet()); //any type will do, as long as we have something on the stack
// ms.pushPose();
// }
//
// buffer.endBatch();
// ms.popPose();
}
protected static void renderBlockOutline(PoseStack matrixStack, VertexConsumer buffer, BlockPos pos, Vec3 color) {
renderBlockOutline(matrixStack, buffer, pos, pos, color);
}
//Renders outline. Pos1 has to be minimal x,y,z and pos2 maximal x,y,z
protected static void renderBlockOutline(PoseStack matrixStack, VertexConsumer buffer, BlockPos pos1, BlockPos pos2, Vec3 color) {
AABB aabb = new AABB(pos1, pos2.offset(1, 1, 1)).inflate(0.0020000000949949026);
LevelRenderer.renderLineBox(matrixStack, buffer, aabb, (float) color.x, (float) color.y, (float) color.z, 0.4f);
// WorldRenderer.drawSelectionBoundingBox(aabb, (float) color.x, (float) color.y, (float) color.z, 0.4f);
}
//Renders outline with given bounding box
protected static void renderBlockOutline(PoseStack matrixStack, VertexConsumer buffer, BlockPos pos, VoxelShape collisionShape, Vec3 color) {
// WorldRenderer.drawShape(collisionShape, pos.getX(), pos.getY(), pos.getZ(), (float) color.x, (float) color.y, (float) color.z, 0.4f);
LevelRenderer.renderVoxelShape(matrixStack, buffer, collisionShape, pos.getX(), pos.getY(), pos.getZ(), (float) color.x, (float) color.y, (float) color.z, 0.4f);
}
//TODO
//Sends breaking progress for all coordinates to renderglobal, so all blocks get visually broken
// @Override
// public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {
// Minecraft mc = Minecraft.getInstance();
//
// ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player);
// if (!BuildModifiers.isEnabled(modifierSettings, pos)) return;
//
// List<BlockPos> coordinates = BuildModifiers.findCoordinates(mc.player, pos);
// for (int i = 1; i < coordinates.size(); i++) {
// BlockPos coordinate = coordinates.get(i);
// if (SurvivalHelper.canBreak(mc.world, mc.player, coordinate)) {
// //Send i as entity id because only one block can be broken per id
// //Unless i happens to be the player id, then take something else
// int fakeId = mc.player.getEntityId() != i ? i : coordinates.size();
// mc.renderGlobal.sendBlockBreakProgress(fakeId, coordinate, progress);
// }
// }
// }
} }