Added shader on placement. Added sound on drag (block placement sound).

Added line.
Highlight currently selected in radial menu (with colors).
Fixed scaling of icons.
Refactored RenderHandler into 3 classes and SurvivalHelper.
Added classes and icons for diagonal line, diagonal wall, slope floor and cube.
This commit is contained in:
Christian Knaapen
2019-02-08 03:26:41 +01:00
parent 73c55578e7
commit 009f385054
40 changed files with 1440 additions and 975 deletions

View File

@@ -60,5 +60,8 @@ public class BuildConfig {
@Comment({"Use fancy shaders while placing blocks"}) @Comment({"Use fancy shaders while placing blocks"})
public boolean useShaders = true; public boolean useShaders = true;
@Comment({"How long the dissolve effect takes when placing blocks, in ticks."})
public int dissolveTime = 60;
} }
} }

View File

@@ -3,6 +3,8 @@ package nl.requios.effortlessbuilding;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.config.Config; import net.minecraftforge.common.config.Config;
@@ -55,6 +57,8 @@ public class EffortlessBuilding
public static final ItemReachUpgrade2 ITEM_REACH_UPGRADE_2 = new ItemReachUpgrade2(); public static final ItemReachUpgrade2 ITEM_REACH_UPGRADE_2 = new ItemReachUpgrade2();
public static final ItemReachUpgrade3 ITEM_REACH_UPGRADE_3 = new ItemReachUpgrade3(); public static final ItemReachUpgrade3 ITEM_REACH_UPGRADE_3 = new ItemReachUpgrade3();
public static final SoundEvent SOUND_BUILD_CLICK = createSoundEvent("build_click");
public static final Block[] BLOCKS = { public static final Block[] BLOCKS = {
}; };
@@ -65,6 +69,10 @@ public class EffortlessBuilding
ITEM_REACH_UPGRADE_3 ITEM_REACH_UPGRADE_3
}; };
public static final SoundEvent[] SOUND_EVENTS = {
SOUND_BUILD_CLICK
};
public static final int RANDOMIZER_BAG_GUI = 0; public static final int RANDOMIZER_BAG_GUI = 0;
@EventHandler @EventHandler
@@ -89,6 +97,8 @@ public class EffortlessBuilding
EffortlessBuilding.packetHandler.registerMessage(CancelModeMessage.MessageHandler.class, CancelModeMessage.class, 4, Side.SERVER); EffortlessBuilding.packetHandler.registerMessage(CancelModeMessage.MessageHandler.class, CancelModeMessage.class, 4, Side.SERVER);
EffortlessBuilding.packetHandler.registerMessage(RequestLookAtMessage.MessageHandler.class, RequestLookAtMessage.class, 5, Side.CLIENT);
proxy.preInit(event); proxy.preInit(event);
} }
@@ -128,4 +138,9 @@ public class EffortlessBuilding
public static void log(EntityPlayer player, String msg, boolean actionBar){ public static void log(EntityPlayer player, String msg, boolean actionBar){
player.sendStatusMessage(new TextComponentString(msg), actionBar); player.sendStatusMessage(new TextComponentString(msg), actionBar);
} }
private static SoundEvent createSoundEvent(String soundName) {
final ResourceLocation soundID = new ResourceLocation(EffortlessBuilding.MODID, soundName);
return new SoundEvent(soundID).setRegistryName(soundID);
}
} }

View File

@@ -8,6 +8,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemBlock;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.config.Config; import net.minecraftforge.common.config.Config;
@@ -26,6 +27,7 @@ import nl.requios.effortlessbuilding.capability.ModeCapabilityManager;
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager; import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.network.BlockPlacedMessage; import nl.requios.effortlessbuilding.network.BlockPlacedMessage;
import nl.requios.effortlessbuilding.network.RequestLookAtMessage;
import java.util.List; import java.util.List;
@@ -50,6 +52,12 @@ public class EventHandler
} }
} }
@SubscribeEvent
public static void registerSounds(RegistryEvent.Register<SoundEvent> event) {
EffortlessBuilding.log("testing");
event.getRegistry().registerAll(EffortlessBuilding.SOUND_EVENTS);
}
@SubscribeEvent @SubscribeEvent
public static void attachCapabilities(AttachCapabilitiesEvent<Entity> event) { public static void attachCapabilities(AttachCapabilitiesEvent<Entity> event) {
if (event.getObject() instanceof EntityPlayer) { if (event.getObject() instanceof EntityPlayer) {
@@ -81,7 +89,7 @@ public class EventHandler
event.setCanceled(true); event.setCanceled(true);
} else { } else {
//Send message to client, which sends message back with raytrace info //Send message to client, which sends message back with raytrace info
EffortlessBuilding.packetHandler.sendTo(new BlockPlacedMessage(), (EntityPlayerMP) event.getPlayer()); EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(), (EntityPlayerMP) event.getPlayer());
} }
} }

View File

@@ -24,16 +24,10 @@ public class BuildModes {
Line ("Line", new Line()), Line ("Line", new Line()),
Wall ("Wall", new Wall()), Wall ("Wall", new Wall()),
Floor ("Floor", new Floor()), Floor ("Floor", new Floor()),
Normal2 ("Normal", new Normal()), DiagonalLine ("Diagonal Line", new DiagonalLine()),
NormalPlus2 ("Normal+", new NormalPlus()), DiagonalWall ("Diagonal Wall", new DiagonalWall()),
Line2 ("Line", new Line()), SlopeFloor ("Slope Floor", new SlopeFloor()),
Wall2 ("Wall", new Wall()), Cube ("Cube", new Cube());
Floor2 ("Floor", new Floor())
;
// DiagonalLine,
// DiagonalWall,
// SlopedFloor,
// Cube;
public String name; public String name;
public final IBuildMode instance; public final IBuildMode instance;

View File

@@ -0,0 +1,36 @@
package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import java.util.ArrayList;
import java.util.List;
public class Cube implements IBuildMode {
@Override
public void initialize(EntityPlayer player) {
}
@Override
public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) {
return new ArrayList<>();
}
@Override
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos) {
return new ArrayList<>();
}
@Override
public EnumFacing getSideHit(EntityPlayer player) {
return null;
}
@Override
public Vec3d getHitVec(EntityPlayer player) {
return null;
}
}

View File

@@ -0,0 +1,36 @@
package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import java.util.ArrayList;
import java.util.List;
public class DiagonalLine implements IBuildMode {
@Override
public void initialize(EntityPlayer player) {
}
@Override
public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) {
return new ArrayList<>();
}
@Override
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos) {
return new ArrayList<>();
}
@Override
public EnumFacing getSideHit(EntityPlayer player) {
return null;
}
@Override
public Vec3d getHitVec(EntityPlayer player) {
return null;
}
}

View File

@@ -0,0 +1,36 @@
package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import java.util.ArrayList;
import java.util.List;
public class DiagonalWall implements IBuildMode {
@Override
public void initialize(EntityPlayer player) {
}
@Override
public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) {
return new ArrayList<>();
}
@Override
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos) {
return new ArrayList<>();
}
@Override
public EnumFacing getSideHit(EntityPlayer player) {
return null;
}
@Override
public Vec3d getHitVec(EntityPlayer player) {
return null;
}
}

View File

@@ -79,7 +79,7 @@ public class Floor implements IBuildMode {
double yDistSquared = yBound.subtract(start).lengthSquared(); double yDistSquared = yBound.subtract(start).lengthSquared();
int reach = ReachHelper.getMaxReach(player); //4 times as much as normal placement reach int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
//check if its not behind the player and its not too close and not too far //check if its not behind the player and its not too close and not too far
boolean yValid = yBound.subtract(start).dotProduct(look) > 0 && boolean yValid = yBound.subtract(start).dotProduct(look) > 0 &&

View File

@@ -3,34 +3,208 @@ package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList; import java.util.*;
import java.util.List;
public class Line implements IBuildMode { public class Line implements IBuildMode {
Dictionary<UUID, Integer> rightClickNrTable = new Hashtable<>();
Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
@Override @Override
public void initialize(EntityPlayer player) { public void initialize(EntityPlayer player) {
rightClickNrTable.put(player.getUniqueID(), 0);
firstPosTable.put(player.getUniqueID(), BlockPos.ORIGIN);
sideHitTable.put(player.getUniqueID(), EnumFacing.UP);
hitVecTable.put(player.getUniqueID(), Vec3d.ZERO);
} }
@Override @Override
public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) { public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) {
return new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
int rightClickNr = rightClickNrTable.get(player.getUniqueID());
rightClickNr++;
rightClickNrTable.put(player.getUniqueID(), rightClickNr);
if (rightClickNr == 1) {
//If clicking in air, reset and try again
if (blockPos == null) {
rightClickNrTable.put(player.getUniqueID(), 0);
return list;
}
//First click, remember starting position
firstPosTable.put(player.getUniqueID(), blockPos);
sideHitTable.put(player.getUniqueID(), sideHit);
hitVecTable.put(player.getUniqueID(), hitVec);
//Keep list empty, dont place any blocks yet
} else {
//Second click, place wall
list = findCoordinates(player, blockPos);
rightClickNrTable.put(player.getUniqueID(), 0);
}
return list;
} }
@Override @Override
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos) { public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos) {
return new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
int rightClickNr = rightClickNrTable.get(player.getUniqueID());
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
if (rightClickNr == 0) {
if (blockPos != null)
list.add(blockPos);
} else {
Vec3d look = player.getLookVec();
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
//try on x axis
double x = firstPos.getX();
//then y and z are
double y = (x - start.x) / look.x * look.y + start.y;
double z = (x - start.x) / look.x * look.z + start.z;
Vec3d xBound = new Vec3d(x, y, z);
Vec3d xBoundLine = toLongestLine(xBound, firstPos);
double xDistToLine = xBoundLine.subtract(xBound).lengthSquared();
//distance to player
double xDistSquared = xBound.subtract(start).lengthSquared();
//try on y axis
y = firstPos.getY();
//then x and z are
x = (y - start.y) / look.y * look.x + start.x;
z = (y - start.y) / look.y * look.z + start.z;
Vec3d yBound = new Vec3d(x, y, z);
Vec3d yBoundLine = toLongestLine(yBound, firstPos);
double yDistToLine = yBoundLine.subtract(yBound).lengthSquared();
//distance to player
double yDistSquared = yBound.subtract(start).lengthSquared();
//try on z axis
z = firstPos.getZ();
//then x and y are
x = (z - start.z) / look.z * look.x + start.x;
y = (z - start.z) / look.z * look.y + start.y;
Vec3d zBound = new Vec3d(x, y, z);
Vec3d zBoundLine = toLongestLine(zBound, firstPos);
double zDistToLine = zBoundLine.subtract(zBound).lengthSquared();
//distance to player
double zDistSquared = zBound.subtract(start).lengthSquared();
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
//check if its not behind the player and its not too close and not too far
boolean xValid = xBound.subtract(start).dotProduct(look) > 0 &&
xDistSquared > 4 && xDistSquared < reach * reach;
boolean yValid = yBound.subtract(start).dotProduct(look) > 0 &&
yDistSquared > 4 && yDistSquared < reach * reach;
boolean zValid = zBound.subtract(start).dotProduct(look) > 0 &&
zDistSquared > 4 && zDistSquared < reach * reach;
//select the one that is closest (from wall position to its line counterpart) and is valid
Vec3d selected = null;
double selectedDistToLine = 0;
if (xValid) {
selected = xBoundLine;
selectedDistToLine = xDistToLine;
} else if (yValid) {
selected = yBoundLine;
selectedDistToLine = yDistToLine;
} else if (zValid) {
selected = zBoundLine;
selectedDistToLine = yDistToLine;
}
if (yValid && yDistToLine < selectedDistToLine) selected = yBoundLine;
if (zValid && zDistToLine < selectedDistToLine) selected = zBoundLine;
if (selected == null) return list;
//TODO check if it doesnt go through blocks
RayTraceResult rayTraceResult = player.world.rayTraceBlocks(start, selected, false, false, false);
if (rayTraceResult != null && rayTraceResult.typeOfHit != RayTraceResult.Type.BLOCK) {
//return empty list
return list;
}
BlockPos secondPos = new BlockPos(selected);
//Add whole line
int x1 = firstPos.getX(), x2 = secondPos.getX();
int y1 = firstPos.getY(), y2 = secondPos.getY();
int z1 = firstPos.getZ(), z2 = secondPos.getZ();
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
list.add(new BlockPos(l, m, n));
}
}
}
}
return list;
}
//Make it into a line
//Select the axis that is longest
private Vec3d toLongestLine(Vec3d boundVec, BlockPos firstPos) {
BlockPos bound = new BlockPos(boundVec);
BlockPos firstToSecond = bound.subtract(firstPos);
firstToSecond = new BlockPos(Math.abs(firstToSecond.getX()), Math.abs(firstToSecond.getY()), Math.abs(firstToSecond.getZ()));
int longest = Math.max(firstToSecond.getX(), Math.max(firstToSecond.getY(), firstToSecond.getZ()));
if (longest == firstToSecond.getX()) {
return new Vec3d(bound.getX(), firstPos.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getY()) {
return new Vec3d(firstPos.getX(), bound.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getZ()) {
return new Vec3d(firstPos.getX(), firstPos.getY(), bound.getZ());
}
return null;
} }
@Override @Override
public EnumFacing getSideHit(EntityPlayer player) { public EnumFacing getSideHit(EntityPlayer player) {
return null; return sideHitTable.get(player.getUniqueID());
} }
@Override @Override
public Vec3d getHitVec(EntityPlayer player) { public Vec3d getHitVec(EntityPlayer player) {
return null; return hitVecTable.get(player.getUniqueID());
} }
} }

View File

@@ -0,0 +1,36 @@
package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import java.util.ArrayList;
import java.util.List;
public class SlopeFloor implements IBuildMode {
@Override
public void initialize(EntityPlayer player) {
}
@Override
public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) {
return new ArrayList<>();
}
@Override
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos) {
return new ArrayList<>();
}
@Override
public EnumFacing getSideHit(EntityPlayer player) {
return null;
}
@Override
public Vec3d getHitVec(EntityPlayer player) {
return null;
}
}

View File

@@ -78,6 +78,9 @@ public class Wall implements IBuildMode {
//distance to player //distance to player
double xDistSquared = xBound.subtract(start).lengthSquared(); double xDistSquared = xBound.subtract(start).lengthSquared();
//angle to look
//double xAngle = xBound.subtract(new Vec3d(firstPos)).normalize().dotProduct(look);
//try on z axis //try on z axis
z = firstPos.getZ(); z = firstPos.getZ();
@@ -90,7 +93,10 @@ public class Wall implements IBuildMode {
//distance to player //distance to player
double zDistSquared = zBound.subtract(start).lengthSquared(); double zDistSquared = zBound.subtract(start).lengthSquared();
int reach = ReachHelper.getMaxReach(player); //4 times as much as normal placement reach //angle to look
//double zAngle = zBound.subtract(new Vec3d(firstPos)).normalize().dotProduct(look);
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
//check if its not behind the player and its not too close and not too far //check if its not behind the player and its not too close and not too far
boolean xValid = xBound.subtract(start).dotProduct(look) > 0 && boolean xValid = xBound.subtract(start).dotProduct(look) > 0 &&
@@ -99,10 +105,13 @@ public class Wall implements IBuildMode {
boolean zValid = zBound.subtract(start).dotProduct(look) > 0 && boolean zValid = zBound.subtract(start).dotProduct(look) > 0 &&
zDistSquared > 4 && zDistSquared < reach * reach; zDistSquared > 4 && zDistSquared < reach * reach;
//select the one that is closest to the player and is valid //select the one that is closest and is valid
Vec3d selected = null; Vec3d selected = null;
if (xValid) selected = xBound; if (xValid)
if (zValid && zDistSquared < xDistSquared) selected = zBound; selected = xBound;
else if (zValid)
selected = zBound;
if (zValid && zDistSquared < xDistSquared/*Math.abs(zAngle) < Math.abs(xAngle)*/) selected = zBound;
if (selected == null) return list; if (selected == null) return list;

View File

@@ -2,6 +2,7 @@ package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemBlock;
@@ -18,6 +19,7 @@ import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import nl.requios.effortlessbuilding.network.BlockBrokenMessage; import nl.requios.effortlessbuilding.network.BlockBrokenMessage;
import nl.requios.effortlessbuilding.network.BlockPlacedMessage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -53,6 +55,9 @@ public class BuildModifiers {
SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, EnumFacing.UP, true, false); SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, EnumFacing.UP, true, false);
} }
} }
EffortlessBuilding.packetHandler.sendTo(new BlockPlacedMessage(), ((EntityPlayerMP) player));
} }
public static void onBlockBroken(EntityPlayer player, List<BlockPos> posList) { public static void onBlockBroken(EntityPlayer player, List<BlockPos> posList) {
@@ -117,13 +122,13 @@ public class BuildModifiers {
ItemStack itemBlock = ItemStack.EMPTY; ItemStack itemBlock = ItemStack.EMPTY;
if (itemStack.getItem() instanceof ItemBlock) itemBlock = itemStack; if (itemStack.getItem() instanceof ItemBlock) itemBlock = itemStack;
ItemRandomizerBag.resetRandomness(); ItemRandomizerBag.resetRandomness();
if (itemStack.getItem() instanceof ItemRandomizerBag) itemBlock = ItemRandomizerBag.pickRandomStack(ItemRandomizerBag.getBagInventory(itemStack));
//Add blocks in posList first //Add blocks in posList first
for (BlockPos blockPos : posList) { for (BlockPos blockPos : posList) {
if (itemStack.getItem() instanceof ItemRandomizerBag) itemBlock = ItemRandomizerBag.pickRandomStack(ItemRandomizerBag.getBagInventory(itemStack));
IBlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, EnumHand.MAIN_HAND); IBlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, EnumHand.MAIN_HAND);
blockStates.add(blockState); blockStates.add(blockState);
itemStacks.add(itemStack); itemStacks.add(itemBlock);
} }
for (BlockPos blockPos : posList) { for (BlockPos blockPos : posList) {

View File

@@ -1,9 +1,9 @@
package nl.requios.effortlessbuilding.gui.buildmode; package nl.requios.effortlessbuilding.gui.buildmode;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.proxy.ClientProxy;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
@@ -25,8 +25,7 @@ import static nl.requios.effortlessbuilding.buildmode.BuildModes.*;
* From Chisels and Bits by AlgorithmX2 * From Chisels and Bits by AlgorithmX2
* https://github.com/AlgorithmX2/Chisels-and-Bits/blob/1.12/src/main/java/mod/chiselsandbits/client/gui/ChiselsAndBitsMenu.java * https://github.com/AlgorithmX2/Chisels-and-Bits/blob/1.12/src/main/java/mod/chiselsandbits/client/gui/ChiselsAndBitsMenu.java
*/ */
public class RadialMenu extends GuiScreen public class RadialMenu extends GuiScreen {
{
private final float TIME_SCALE = 0.01f; private final float TIME_SCALE = 0.01f;
public static final RadialMenu instance = new RadialMenu(); public static final RadialMenu instance = new RadialMenu();
@@ -37,41 +36,32 @@ public class RadialMenu extends GuiScreen
//public ButtonAction doAction = null; //public ButtonAction doAction = null;
public boolean actionUsed = false; public boolean actionUsed = false;
private float clampVis( private float clampVis(final float f) {
final float f )
{
return Math.max( 0.0f, Math.min( 1.0f, f ) ); return Math.max( 0.0f, Math.min( 1.0f, f ) );
} }
public void raiseVisibility() public void raiseVisibility() {
{
visibility = clampVis( visibility + lastChange.elapsed( TimeUnit.MILLISECONDS ) * TIME_SCALE ); visibility = clampVis( visibility + lastChange.elapsed( TimeUnit.MILLISECONDS ) * TIME_SCALE );
lastChange = Stopwatch.createStarted(); lastChange = Stopwatch.createStarted();
} }
public void decreaseVisibility() public void decreaseVisibility() {
{
visibility = clampVis( visibility - lastChange.elapsed( TimeUnit.MILLISECONDS ) * TIME_SCALE ); visibility = clampVis( visibility - lastChange.elapsed( TimeUnit.MILLISECONDS ) * TIME_SCALE );
lastChange = Stopwatch.createStarted(); lastChange = Stopwatch.createStarted();
} }
public boolean isVisible() public boolean isVisible() {
{
return visibility > 0.001; return visibility > 0.001;
} }
public void configure( public void configure(final int scaledWidth, final int scaledHeight ) {
final int scaledWidth,
final int scaledHeight )
{
mc = Minecraft.getMinecraft(); mc = Minecraft.getMinecraft();
fontRenderer = mc.fontRenderer; fontRenderer = mc.fontRenderer;
width = scaledWidth; width = scaledWidth;
height = scaledHeight; height = scaledHeight;
} }
private static class MenuButton private static class MenuButton {
{
public double x1, x2; public double x1, x2;
public double y1, y2; public double y1, y2;
@@ -83,14 +73,8 @@ public class RadialMenu extends GuiScreen
public String name; public String name;
public EnumFacing textSide; public EnumFacing textSide;
public MenuButton( public MenuButton(final String name, /*final ButtonAction action,*/ final double x, final double y,
final String name, final TextureAtlasSprite ico, final EnumFacing textSide) {
//final ButtonAction action,
final double x,
final double y,
final TextureAtlasSprite ico,
final EnumFacing textSide )
{
this.name = name; this.name = name;
//this.action = action; //this.action = action;
x1 = x; x1 = x;
@@ -102,14 +86,8 @@ public class RadialMenu extends GuiScreen
this.textSide = textSide; this.textSide = textSide;
} }
public MenuButton( public MenuButton(final String name, /*final ButtonAction action,*/ final double x, final double y,
final String name, final int col, final EnumFacing textSide) {
//final ButtonAction action,
final double x,
final double y,
final int col,
final EnumFacing textSide )
{
this.name = name; this.name = name;
//this.action = action; //this.action = action;
x1 = x; x1 = x;
@@ -122,38 +100,21 @@ public class RadialMenu extends GuiScreen
} }
static class MenuRegion static class MenuRegion {
{
public final BuildModeEnum mode; public final BuildModeEnum mode;
public double x1, x2; public double x1, x2;
public double y1, y2; public double y1, y2;
public boolean highlighted; public boolean highlighted;
public MenuRegion( public MenuRegion(final BuildModeEnum mode) {
final BuildModeEnum mode )
{
this.mode = mode; this.mode = mode;
} }
} }
public static class SpriteIconPositioning
{
public TextureAtlasSprite sprite;
public double left;
public double top;
public double width;
public double height;
}
@Override @Override
public void drawScreen( public void drawScreen(final int mouseX, final int mouseY, final float partialTicks) {
final int mouseX,
final int mouseY,
final float partialTicks )
{
//TODO chisels compat //TODO chisels compat
// final ChiselToolType tool = ClientSide.instance.getHeldToolType( EnumHand.MAIN_HAND ); // final ChiselToolType tool = ClientSide.instance.getHeldToolType( EnumHand.MAIN_HAND );
// //
@@ -165,172 +126,173 @@ public class RadialMenu extends GuiScreen
GlStateManager.pushMatrix(); GlStateManager.pushMatrix();
GlStateManager.translate( 0.0F, 0.0F, 200.0F ); GlStateManager.translate( 0.0F, 0.0F, 200.0F );
final int start = (int) ( visibility * 98 ) << 24; final int startColor = (int) ( visibility * 98 ) << 24;
final int end = (int) ( visibility * 128 ) << 24; final int endColor = (int) ( visibility * 128 ) << 24;
drawGradientRect( 0, 0, width, height, start, end ); drawGradientRect(0, 0, width, height, startColor, endColor);
GlStateManager.disableTexture2D(); GlStateManager.disableTexture2D();
GlStateManager.enableBlend(); GlStateManager.enableBlend();
GlStateManager.disableAlpha(); GlStateManager.disableAlpha();
GlStateManager.tryBlendFuncSeparate( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0 ); GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0);
GlStateManager.shadeModel( GL11.GL_SMOOTH ); GlStateManager.shadeModel(GL11.GL_SMOOTH);
final Tessellator tessellator = Tessellator.getInstance(); final Tessellator tessellator = Tessellator.getInstance();
final BufferBuilder buffer = tessellator.getBuffer(); final BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR ); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
final double vecX = mouseX - width / 2; final double middleX = width / 2.0;
final double vecY = mouseY - height / 2; final double middleY = height / 2.0;
double radians = Math.atan2( vecY, vecX );
final double ring_inner_edge = 20; final double mouseXCenter = mouseX - middleX;
final double ring_outer_edge = 50; final double mouseYCenter = mouseY - middleY;
final double text_distnace = 65; double mouseRadians = Math.atan2(mouseYCenter, mouseXCenter);
final double ringInnerEdge = 20;
final double ringOuterEdge = 50;
final double textDistance = 65;
final double quarterCircle = Math.PI / 2.0; final double quarterCircle = Math.PI / 2.0;
if ( radians < -quarterCircle ) if ( mouseRadians < -quarterCircle ) {
{ mouseRadians = mouseRadians + Math.PI * 2;
radians = radians + Math.PI * 2;
} }
final double middle_x = width / 2;
final double middle_y = height / 2;
final ArrayList<MenuRegion> modes = new ArrayList<MenuRegion>(); final ArrayList<MenuRegion> modes = new ArrayList<MenuRegion>();
final ArrayList<MenuButton> btns = new ArrayList<MenuButton>(); final ArrayList<MenuButton> buttons = new ArrayList<MenuButton>();
// btns.add( new MenuButton( "mod.chiselsandbits.other.undo", ButtonAction.UNDO, text_distnace, -20, ClientSide.undoIcon, EnumFacing.EAST ) ); // buttons.add( new MenuButton( "mod.chiselsandbits.other.undo", ButtonAction.UNDO, textDistance, -20, ClientSide.undoIcon, EnumFacing.EAST ) );
// btns.add( new MenuButton( "mod.chiselsandbits.other.redo", ButtonAction.REDO, text_distnace, 4, ClientSide.redoIcon, EnumFacing.EAST ) ); // buttons.add( new MenuButton( "mod.chiselsandbits.other.redo", ButtonAction.REDO, textDistance, 4, ClientSide.redoIcon, EnumFacing.EAST ) );
for ( final BuildModeEnum mode : BuildModeEnum.values() ) for (final BuildModeEnum mode : BuildModeEnum.values()) {
{ modes.add(new MenuRegion(mode));
modes.add( new MenuRegion( mode ) );
} }
switchTo = null; switchTo = null;
//doAction = null; //doAction = null;
if ( !modes.isEmpty() ) if (!modes.isEmpty()) {
{
final int totalModes = Math.max( 3, modes.size() ); final int totalModes = Math.max( 3, modes.size() );
int currentMode = 0; int currentMode = 0;
final double fragment = Math.PI * 0.005; final double fragment = Math.PI * 0.005;
final double fragment2 = Math.PI * 0.0025; final double fragment2 = Math.PI * 0.0025;
final double perObject = 2.0 * Math.PI / totalModes; final double perObject = 2.0 * Math.PI / totalModes;
for ( final MenuRegion mnuRgn : modes ) for (int i = 0; i < modes.size(); i++) {
{ MenuRegion menuRegion = modes.get(i);
final double begin_rad = currentMode * perObject - quarterCircle; final double beginRadians = currentMode * perObject - quarterCircle;
final double end_rad = ( currentMode + 1 ) * perObject - quarterCircle; final double endRadians = (currentMode + 1) * perObject - quarterCircle;
mnuRgn.x1 = Math.cos( begin_rad ); menuRegion.x1 = Math.cos(beginRadians);
mnuRgn.x2 = Math.cos( end_rad ); menuRegion.x2 = Math.cos(endRadians);
mnuRgn.y1 = Math.sin( begin_rad ); menuRegion.y1 = Math.sin(beginRadians);
mnuRgn.y2 = Math.sin( end_rad ); menuRegion.y2 = Math.sin(endRadians);
final double x1m1 = Math.cos( begin_rad + fragment ) * ring_inner_edge; final double x1m1 = Math.cos(beginRadians + fragment) * ringInnerEdge;
final double x2m1 = Math.cos( end_rad - fragment ) * ring_inner_edge; final double x2m1 = Math.cos(endRadians - fragment) * ringInnerEdge;
final double y1m1 = Math.sin( begin_rad + fragment ) * ring_inner_edge; final double y1m1 = Math.sin(beginRadians + fragment) * ringInnerEdge;
final double y2m1 = Math.sin( end_rad - fragment ) * ring_inner_edge; final double y2m1 = Math.sin(endRadians - fragment) * ringInnerEdge;
final double x1m2 = Math.cos( begin_rad + fragment2 ) * ring_outer_edge; final double x1m2 = Math.cos(beginRadians + fragment2) * ringOuterEdge;
final double x2m2 = Math.cos( end_rad - fragment2 ) * ring_outer_edge; final double x2m2 = Math.cos(endRadians - fragment2) * ringOuterEdge;
final double y1m2 = Math.sin( begin_rad + fragment2 ) * ring_outer_edge; final double y1m2 = Math.sin(beginRadians + fragment2) * ringOuterEdge;
final double y2m2 = Math.sin( end_rad - fragment2 ) * ring_outer_edge; final double y2m2 = Math.sin(endRadians - fragment2) * ringOuterEdge;
final float a = 0.5f; float r = 0.0f;
float f = 0f; float g = 0.0f;
float b = 0.0f;
float a = 0.5f;
final boolean quad = inTriangle( //check if current mode
x1m1, y1m1, int buildMode = ModeSettingsManager.getModeSettings(Minecraft.getMinecraft().player).getBuildMode().ordinal();
x2m2, y2m2, if (buildMode == i) {
x2m1, y2m1, r = 0f;
vecX, vecY ) || inTriangle( g = 0.5f;
x1m1, y1m1, b = 1f;
x1m2, y1m2, a = 0.5f;
x2m2, y2m2, //menuRegion.highlighted = true; //draw text
vecX, vecY );
if ( begin_rad <= radians && radians <= end_rad && quad )
{
f = 1;
mnuRgn.highlighted = true;
switchTo = mnuRgn.mode;
} }
buffer.pos( middle_x + x1m1, middle_y + y1m1, zLevel ).color( f, f, f, a ).endVertex(); //check if mouse is over this region
buffer.pos( middle_x + x2m1, middle_y + y2m1, zLevel ).color( f, f, f, a ).endVertex(); final boolean isMouseInQuad = inTriangle(x1m1, y1m1, x2m2, y2m2, x2m1, y2m1, mouseXCenter, mouseYCenter)
buffer.pos( middle_x + x2m2, middle_y + y2m2, zLevel ).color( f, f, f, a ).endVertex(); || inTriangle(x1m1, y1m1, x1m2, y1m2, x2m2, y2m2, mouseXCenter, mouseYCenter);
buffer.pos( middle_x + x1m2, middle_y + y1m2, zLevel ).color( f, f, f, a ).endVertex();
if (beginRadians <= mouseRadians && mouseRadians <= endRadians && isMouseInQuad) {
r = 0.6f;//0.6f;
g = 0.8f;//0.3f;
b = 1f;//0.0f;
a = 0.6f;
menuRegion.highlighted = true;
switchTo = menuRegion.mode;
}
buffer.pos(middleX + x1m1, middleY + y1m1, zLevel).color(r, g, b, a).endVertex();
buffer.pos(middleX + x2m1, middleY + y2m1, zLevel).color(r, g, b, a).endVertex();
buffer.pos(middleX + x2m2, middleY + y2m2, zLevel).color(r, g, b, a).endVertex();
buffer.pos(middleX + x1m2, middleY + y1m2, zLevel).color(r, g, b, a).endVertex();
currentMode++; currentMode++;
} }
} }
for ( final MenuButton btn : btns ) for (final MenuButton btn : buttons) {
{
final float a = 0.5f; final float a = 0.5f;
float f = 0f; float f = 0f;
if ( btn.x1 <= vecX && btn.x2 >= vecX && btn.y1 <= vecY && btn.y2 >= vecY ) if (btn.x1 <= mouseXCenter && btn.x2 >= mouseXCenter && btn.y1 <= mouseYCenter && btn.y2 >= mouseYCenter) {
{
f = 1; f = 1;
btn.highlighted = true; btn.highlighted = true;
//doAction = btn.action; //doAction = btn.action;
} }
buffer.pos( middle_x + btn.x1, middle_y + btn.y1, zLevel ).color( f, f, f, a ).endVertex(); buffer.pos(middleX + btn.x1, middleY + btn.y1, zLevel).color(f, f, f, a).endVertex();
buffer.pos( middle_x + btn.x1, middle_y + btn.y2, zLevel ).color( f, f, f, a ).endVertex(); buffer.pos(middleX + btn.x1, middleY + btn.y2, zLevel).color(f, f, f, a).endVertex();
buffer.pos( middle_x + btn.x2, middle_y + btn.y2, zLevel ).color( f, f, f, a ).endVertex(); buffer.pos(middleX + btn.x2, middleY + btn.y2, zLevel).color(f, f, f, a).endVertex();
buffer.pos( middle_x + btn.x2, middle_y + btn.y1, zLevel ).color( f, f, f, a ).endVertex(); buffer.pos(middleX + btn.x2, middleY + btn.y1, zLevel).color(f, f, f, a).endVertex();
} }
tessellator.draw(); tessellator.draw();
GlStateManager.shadeModel( GL11.GL_FLAT ); GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.translate( 0.0F, 0.0F, 5.0F ); GlStateManager.translate(0f, 0f, 5f);
GlStateManager.enableTexture2D(); GlStateManager.enableTexture2D();
GlStateManager.color( 1, 1, 1, 1.0f ); GlStateManager.color(1f, 1f, 1f, 1f);
GlStateManager.disableBlend(); GlStateManager.disableBlend();
GlStateManager.enableAlpha(); GlStateManager.enableAlpha();
GlStateManager.bindTexture( Minecraft.getMinecraft().getTextureMapBlocks().getGlTextureId() ); GlStateManager.bindTexture(Minecraft.getMinecraft().getTextureMapBlocks().getGlTextureId());
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR ); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
for ( final MenuRegion mnuRgn : modes ) for (final MenuRegion mnuRgn : modes) {
{
final double x = ( mnuRgn.x1 + mnuRgn.x2 ) * 0.5 * ( ring_outer_edge * 0.6 + 0.4 * ring_inner_edge );
final double y = ( mnuRgn.y1 + mnuRgn.y2 ) * 0.5 * ( ring_outer_edge * 0.6 + 0.4 * ring_inner_edge );
final SpriteIconPositioning sip = ClientProxy.getBuildModeIcon(mnuRgn.mode); final double x = (mnuRgn.x1 + mnuRgn.x2) * 0.5 * (ringOuterEdge * 0.6 + 0.4 * ringInnerEdge);
final double y = (mnuRgn.y1 + mnuRgn.y2) * 0.5 * (ringOuterEdge * 0.6 + 0.4 * ringInnerEdge);
final double scalex = 15 * sip.width * 0.5; final TextureAtlasSprite sprite = ClientProxy.getBuildModeIcon(mnuRgn.mode);
final double scaley = 15 * sip.height * 0.5;
final double scalex = 16 * 0.5;
final double scaley = 16 * 0.5;
final double x1 = x - scalex; final double x1 = x - scalex;
final double x2 = x + scalex; final double x2 = x + scalex;
final double y1 = y - scaley; final double y1 = y - scaley;
final double y2 = y + scaley; final double y2 = y + scaley;
final TextureAtlasSprite sprite = sip.sprite; final float f = 1f;
final float a = 1f;
final float f = 1.0f; final double u1 = 0f;
final float a = 1.0f; final double u2 = 16f;
final double v1 = 0f;
final double v2 = 16f;
final double u1 = sip.left * 16.0; buffer.pos(middleX + x1, middleY + y1, zLevel).tex( sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v1)).color(f, f, f, a).endVertex();
final double u2 = ( sip.left + sip.width ) * 16.0; buffer.pos(middleX + x1, middleY + y2, zLevel).tex( sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v2)).color(f, f, f, a).endVertex();
final double v1 = sip.top * 16.0; buffer.pos(middleX + x2, middleY + y2, zLevel).tex( sprite.getInterpolatedU(u2), sprite.getInterpolatedV(v2)).color(f, f, f, a).endVertex();
final double v2 = ( sip.top + sip.height ) * 16.0; buffer.pos(middleX + x2, middleY + y1, zLevel).tex( sprite.getInterpolatedU(u2), sprite.getInterpolatedV(v1)).color(f, f, f, a).endVertex();
buffer.pos( middle_x + x1, middle_y + y1, zLevel ).tex( sprite.getInterpolatedU( u1 ), sprite.getInterpolatedV( v1 ) ).color( f, f, f, a ).endVertex();
buffer.pos( middle_x + x1, middle_y + y2, zLevel ).tex( sprite.getInterpolatedU( u1 ), sprite.getInterpolatedV( v2 ) ).color( f, f, f, a ).endVertex();
buffer.pos( middle_x + x2, middle_y + y2, zLevel ).tex( sprite.getInterpolatedU( u2 ), sprite.getInterpolatedV( v2 ) ).color( f, f, f, a ).endVertex();
buffer.pos( middle_x + x2, middle_y + y1, zLevel ).tex( sprite.getInterpolatedU( u2 ), sprite.getInterpolatedV( v1 ) ).color( f, f, f, a ).endVertex();
} }
for ( final MenuButton btn : btns ) for (final MenuButton btn : buttons) {
{
final float f = switchTo == null ? 1.0f : 0.5f; final float f = switchTo == null ? 1.0f : 0.5f;
final float a = 1.0f; final float a = 1.0f;
@@ -339,70 +301,69 @@ public class RadialMenu extends GuiScreen
final double v1 = 0; final double v1 = 0;
final double v2 = 16; final double v2 = 16;
final TextureAtlasSprite sprite = btn.icon == null ? Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( ModelLoader.White.LOCATION.toString() ) : btn.icon; final TextureAtlasSprite sprite = btn.icon == null ? Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(ModelLoader.White.LOCATION.toString()) : btn.icon;
final double btnx1 = btn.x1 + 1; final double btnx1 = btn.x1 + 1;
final double btnx2 = btn.x2 - 1; final double btnx2 = btn.x2 - 1;
final double btny1 = btn.y1 + 1; final double btny1 = btn.y1 + 1;
final double btny2 = btn.y2 - 1; final double btny2 = btn.y2 - 1;
final float red = f * ( ( btn.color >> 16 & 0xff ) / 255.0f ); final float red = f * ((btn.color >> 16 & 0xff) / 255.0f);
final float green = f * ( ( btn.color >> 8 & 0xff ) / 255.0f ); final float green = f * ((btn.color >> 8 & 0xff) / 255.0f);
final float blue = f * ( ( btn.color & 0xff ) / 255.0f ); final float blue = f * ((btn.color & 0xff) / 255.0f);
buffer.pos( middle_x + btnx1, middle_y + btny1, zLevel ).tex( sprite.getInterpolatedU( u1 ), sprite.getInterpolatedV( v1 ) ).color( red, green, blue, a ).endVertex(); buffer.pos(middleX + btnx1, middleY + btny1, zLevel).tex(sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v1)).color(red, green, blue, a).endVertex();
buffer.pos( middle_x + btnx1, middle_y + btny2, zLevel ).tex( sprite.getInterpolatedU( u1 ), sprite.getInterpolatedV( v2 ) ).color( red, green, blue, a ).endVertex(); buffer.pos(middleX + btnx1, middleY + btny2, zLevel).tex(sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v2)).color(red, green, blue, a).endVertex();
buffer.pos( middle_x + btnx2, middle_y + btny2, zLevel ).tex( sprite.getInterpolatedU( u2 ), sprite.getInterpolatedV( v2 ) ).color( red, green, blue, a ).endVertex(); buffer.pos(middleX + btnx2, middleY + btny2, zLevel).tex(sprite.getInterpolatedU(u2), sprite.getInterpolatedV(v2)).color(red, green, blue, a).endVertex();
buffer.pos( middle_x + btnx2, middle_y + btny1, zLevel ).tex( sprite.getInterpolatedU( u2 ), sprite.getInterpolatedV( v1 ) ).color( red, green, blue, a ).endVertex(); buffer.pos(middleX + btnx2, middleY + btny1, zLevel).tex(sprite.getInterpolatedU(u2), sprite.getInterpolatedV(v1)).color(red, green, blue, a).endVertex();
} }
tessellator.draw(); tessellator.draw();
for ( final MenuRegion mnuRgn : modes ) for (final MenuRegion mnuRgn : modes) {
{
if ( mnuRgn.highlighted )
{
final double x = ( mnuRgn.x1 + mnuRgn.x2 ) * 0.5;
final double y = ( mnuRgn.y1 + mnuRgn.y2 ) * 0.5;
int fixed_x = (int) ( x * text_distnace ); if (mnuRgn.highlighted) {
final int fixed_y = (int) ( y * text_distnace ); final double x = (mnuRgn.x1 + mnuRgn.x2) * 0.5;
final double y = (mnuRgn.y1 + mnuRgn.y2) * 0.5;
int fixed_x = (int) (x * textDistance);
final int fixed_y = (int) (y * textDistance);
final String text = mnuRgn.mode.name; final String text = mnuRgn.mode.name;
if ( x <= -0.2 ) if ( x <= -0.2 ) {
{ fixed_x -= fontRenderer.getStringWidth(text);
fixed_x -= fontRenderer.getStringWidth( text ); } else if ( -0.2 <= x && x <= 0.2 ) {
} fixed_x -= fontRenderer.getStringWidth(text) / 2;
else if ( -0.2 <= x && x <= 0.2 )
{
fixed_x -= fontRenderer.getStringWidth( text ) / 2;
} }
fontRenderer.drawStringWithShadow( text, (int) middle_x + fixed_x, (int) middle_y + fixed_y, 0xffffffff ); fontRenderer.drawStringWithShadow(text, (int) middleX + fixed_x, (int) middleY + fixed_y, 0xffffffff);
} }
} }
for ( final MenuButton btn : btns ) for (final MenuButton btn : buttons) {
{ if (btn.highlighted) {
if ( btn.highlighted )
{
final String text = btn.name; final String text = btn.name;
if ( btn.textSide == EnumFacing.WEST ) if (btn.textSide == EnumFacing.WEST) {
{
fontRenderer.drawStringWithShadow( text, (int) ( middle_x + btn.x1 - 8 ) - fontRenderer.getStringWidth( text ), (int) ( middle_y + btn.y1 + 6 ), 0xffffffff ); fontRenderer.drawStringWithShadow( text, (int) ( middleX + btn.x1 - 8 ) - fontRenderer.getStringWidth( text ),
} (int) ( middleY + btn.y1 + 6 ), 0xffffffff );
else if ( btn.textSide == EnumFacing.EAST )
{ } else if (btn.textSide == EnumFacing.EAST) {
fontRenderer.drawStringWithShadow( text, (int) ( middle_x + btn.x2 + 8 ), (int) ( middle_y + btn.y1 + 6 ), 0xffffffff );
} fontRenderer.drawStringWithShadow( text, (int) ( middleX + btn.x2 + 8 ),
else if ( btn.textSide == EnumFacing.UP ) (int) ( middleY + btn.y1 + 6 ), 0xffffffff );
{
fontRenderer.drawStringWithShadow( text, (int) ( middle_x + ( btn.x1 + btn.x2 ) * 0.5 - fontRenderer.getStringWidth( text ) * 0.5 ), (int) ( middle_y + btn.y1 - 14 ), 0xffffffff ); } else if (btn.textSide == EnumFacing.UP) {
}
else if ( btn.textSide == EnumFacing.DOWN ) fontRenderer.drawStringWithShadow( text, (int) ( middleX + ( btn.x1 + btn.x2 ) * 0.5 - fontRenderer.getStringWidth( text ) * 0.5 ),
{ (int) ( middleY + btn.y1 - 14 ), 0xffffffff );
fontRenderer.drawStringWithShadow( text, (int) ( middle_x + ( btn.x1 + btn.x2 ) * 0.5 - fontRenderer.getStringWidth( text ) * 0.5 ), (int) ( middle_y + btn.y1 + 24 ), 0xffffffff );
} else if (btn.textSide == EnumFacing.DOWN) {
fontRenderer.drawStringWithShadow( text, (int) ( middleX + ( btn.x1 + btn.x2 ) * 0.5 - fontRenderer.getStringWidth( text ) * 0.5 ),
(int) ( middleY + btn.y1 + 24 ), 0xffffffff );
} }
} }
@@ -411,42 +372,26 @@ public class RadialMenu extends GuiScreen
GlStateManager.popMatrix(); GlStateManager.popMatrix();
} }
private boolean inTriangle( private boolean inTriangle(final double x1, final double y1, final double x2, final double y2,
final double x1, final double x3, final double y3, final double x, final double y ) {
final double y1, final double ab = (x1 - x) * (y2 - y) - (x2 - x) * (y1 - y);
final double x2, final double bc = (x2 - x) * (y3 - y) - (x3 - x) * (y2 - y);
final double y2, final double ca = (x3 - x) * (y1 - y) - (x1 - x) * (y3 - y);
final double x3, return sign(ab) == sign(bc) && sign(bc) == sign(ca);
final double y3,
final double x,
final double y )
{
final double ab = ( x1 - x ) * ( y2 - y ) - ( x2 - x ) * ( y1 - y );
final double bc = ( x2 - x ) * ( y3 - y ) - ( x3 - x ) * ( y2 - y );
final double ca = ( x3 - x ) * ( y1 - y ) - ( x1 - x ) * ( y3 - y );
return sign( ab ) == sign( bc ) && sign( bc ) == sign( ca );
} }
private int sign( private int sign(final double n) {
final double n )
{
return n > 0 ? 1 : -1; return n > 0 ? 1 : -1;
} }
/** /**
* Called when the mouse is clicked. Args : mouseX, mouseY, clickedButton * Called when the mouse is clicked. Args : mouseX, mouseY, clickedButton
*/ */
protected void mouseClicked( protected void mouseClicked(int mouseX, int mouseY, int mouseButton ) {
int mouseX, if (mouseButton == 0) {
int mouseY, this.mc.displayGuiScreen(null);
int mouseButton ) throws IOException
{
if ( mouseButton == 0 )
{
this.mc.displayGuiScreen( (GuiScreen) null );
if ( this.mc.currentScreen == null ) if (this.mc.currentScreen == null) {
{
this.mc.setIngameFocus(); this.mc.setIngameFocus();
} }
} }

View File

@@ -1,544 +0,0 @@
package nl.requios.effortlessbuilding.helper;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.BuildConfig;
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.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.buildmodifier.Mirror;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.RadialMirror;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import org.lwjgl.opengl.ARBMultitexture;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import org.lwjgl.util.Color;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
@Mod.EventBusSubscriber(Side.CLIENT)
public class RenderHelper implements IWorldEventListener {
private static final Color colorX = new Color(255, 72, 52);
private static final Color colorY = new Color(67, 204, 51);
private static final Color colorZ = new Color(52, 247, 255);
private static final Color colorRadial = new Color(52, 247, 255);
private static final int lineAlpha = 200;
private static final int planeAlpha = 75;
private static final Vec3d epsilon = new Vec3d(0.001, 0.001, 0.001); //prevents z-fighting
private static List<BlockPos> previousCoordinates;
private static final int secondaryTextureUnit = 7;
private static void begin(float partialTicks) {
EntityPlayer player = Minecraft.getMinecraft().player;
double playerX = player.prevPosX + (player.posX - player.prevPosX) * partialTicks;
double playerY = player.prevPosY + (player.posY - player.prevPosY) * partialTicks;
double playerZ = player.prevPosZ + (player.posZ - player.prevPosZ) * partialTicks;
Vec3d playerPos = new Vec3d(playerX, playerY, playerZ);
GL11.glPushMatrix();
GL11.glTranslated(-playerPos.x, -playerPos.y, -playerPos.z);
GL11.glDepthMask(false);
}
private static void beginLines() {
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glLineWidth(2);
}
private static void endLines() {
GL11.glPopAttrib();
}
private static void beginBlockPreviews() {
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_color.png"));
Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png"));
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL14.glBlendColor(1F, 1F, 1F, 0.8f);
}
private static void endBlockPreviews() {
ShaderHelper.releaseShader();
GlStateManager.disableBlend();
GL11.glPopAttrib();
}
private static void end() {
GL11.glDepthMask(true);
GL11.glPopMatrix();
}
private static void renderBlockPreview(BlockRendererDispatcher dispatcher, BlockPos blockPos, IBlockState blockState) {
GlStateManager.pushMatrix();
GlStateManager.translate(blockPos.getX(), blockPos.getY(), blockPos.getZ());
GlStateManager.rotate(-90.0F, 0.0F, 1.0F, 0.0F);
GlStateManager.translate(-0.005f, -0.005f, 0.005f);
GlStateManager.scale(1.01f, 1.01f, 1.01f);
dispatcher.renderBlockBrightness(blockState, 0.85f);
GlStateManager.popMatrix();
}
public static void renderBlockOutline(BlockPos pos) {
renderBlockOutline(pos, pos);
}
//Renders outline. Pos1 has to be minimal x,y,z and pos2 maximal x,y,z
public static void renderBlockOutline(BlockPos pos1, BlockPos pos2) {
GL11.glLineWidth(2);
AxisAlignedBB aabb = new AxisAlignedBB(pos1, pos2.add(1, 1, 1)).grow(0.0020000000949949026);
RenderGlobal.drawSelectionBoundingBox(aabb, 0f, 0f, 0f, 0.4f);
}
@SubscribeEvent
public static void onRender(RenderWorldLastEvent event) {
EntityPlayer player = Minecraft.getMinecraft().player;
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
begin(event.getPartialTicks());
beginLines();
//Mirror lines and areas
Mirror.MirrorSettings m = modifierSettings.getMirrorSettings();
if (m != null && m.enabled && (m.mirrorX || m.mirrorY || m.mirrorZ))
{
Vec3d pos = m.position.add(epsilon);
int radius = m.radius;
if (m.mirrorX)
{
Vec3d posA = new Vec3d(pos.x, pos.y - radius, pos.z - radius);
Vec3d posB = new Vec3d(pos.x, pos.y + radius, pos.z + radius);
drawMirrorPlane(posA, posB, colorX, m.drawLines, m.drawPlanes, true);
}
if (m.mirrorY)
{
Vec3d posA = new Vec3d(pos.x - radius, pos.y, pos.z - radius);
Vec3d posB = new Vec3d(pos.x + radius, pos.y, pos.z + radius);
drawMirrorPlaneY(posA, posB, colorY, m.drawLines, m.drawPlanes);
}
if (m.mirrorZ)
{
Vec3d posA = new Vec3d(pos.x - radius, pos.y - radius, pos.z);
Vec3d posB = new Vec3d(pos.x + radius, pos.y + radius, pos.z);
drawMirrorPlane(posA, posB, colorZ, m.drawLines, m.drawPlanes, true);
}
//Draw axis coordinated colors if two or more axes are enabled
//(If only one is enabled the lines are that planes color)
if (m.drawLines && ((m.mirrorX && m.mirrorY) || (m.mirrorX && m.mirrorZ) || (m.mirrorY && m.mirrorZ)))
{
drawMirrorLines(m);
}
}
//Radial mirror lines and areas
RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings();
if (r != null && r.enabled)
{
Vec3d pos = r.position.add(epsilon);
int radius = r.radius;
float angle = 2f * ((float) Math.PI) / r.slices;
Vec3d relStartVec = new Vec3d(radius, 0, 0);
if (r.slices%4 == 2) relStartVec = relStartVec.rotateYaw(angle / 2f);
for (int i = 0; i < r.slices; i++) {
Vec3d relNewVec = relStartVec.rotateYaw(angle * i);
Vec3d newVec = pos.add(relNewVec);
Vec3d posA = new Vec3d(pos.x, pos.y - radius, pos.z);
Vec3d posB = new Vec3d(newVec.x, pos.y + radius, newVec.z);
drawMirrorPlane(posA, posB, colorRadial, r.drawLines, r.drawPlanes, false);
}
}
endLines();
//Render block previews
RayTraceResult lookingAt = ClientProxy.getLookingAt(player);
if (modeSettings.getBuildMode() == BuildModes.BuildModeEnum.Normal) lookingAt = Minecraft.getMinecraft().objectMouseOver;
ItemStack mainhand = player.getHeldItemMainhand();
boolean toolInHand = !(!mainhand.isEmpty() && (mainhand.getItem() instanceof ItemBlock || mainhand.getItem() instanceof ItemRandomizerBag));
BlockPos startPos = null;
EnumFacing sideHit = null;
Vec3d 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.typeOfHit == RayTraceResult.Type.BLOCK) {
startPos = lookingAt.getBlockPos();
//Check if tool (or none) in hand
boolean replaceable = player.world.getBlockState(startPos).getBlock().isReplaceable(player.world, startPos);
if (!modifierSettings.doQuickReplace() && !toolInHand && !replaceable) {
startPos = startPos.offset(lookingAt.sideHit);
}
//Get under tall grass and other replaceable blocks
if (modifierSettings.doQuickReplace() && !toolInHand && replaceable) {
startPos = startPos.down();
}
sideHit = lookingAt.sideHit;
hitVec = lookingAt.hitVec;
}
//Dont render if in normal mode and modifiers are disabled
//Unless alwaysShowBlockPreview is true in config
if (modeSettings.getBuildMode() != BuildModes.BuildModeEnum.Normal ||
(startPos != null && BuildModifiers.isEnabled(modifierSettings, startPos)) ||
BuildConfig.visuals.alwaysShowBlockPreview) {
beginBlockPreviews();
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) {
BlockRendererDispatcher dispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher();
float percentile = ClientProxy.ticksInGame / 50f % 1f;
//TODO test
percentile = 1f;
//get coordinates
List<BlockPos> startCoordinates = BuildModes.findCoordinates(player, startPos);
BlockPos firstPos = BlockPos.ORIGIN, secondPos = BlockPos.ORIGIN;
//remember first and last pos for highlighting
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);
Collections.sort(newCoordinates, (lhs, rhs) -> {
// -1 - less than, 1 - greater than, 0 - equal
double lhsDistanceToPlayer = new Vec3d(lhs).subtract(player.getPositionEyes(1f)).lengthSquared();
double rhsDistanceToPlayer = new Vec3d(rhs).subtract(player.getPositionEyes(1f)).lengthSquared();
return (int) Math.signum(lhsDistanceToPlayer - rhsDistanceToPlayer);
});
//check if they are different from previous
if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) {
previousCoordinates = newCoordinates;
//if so, renew randomness of randomizer bag
ItemRandomizerBag.renewRandomness();
}
hitVec = new Vec3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)),
Math.abs(hitVec.z - ((int) hitVec.z)));
List<ItemStack> itemStacks = new ArrayList<>();
List<IBlockState> blockStates = BuildModifiers.findBlockStates(player, startCoordinates, hitVec, lookingAt.sideHit, itemStacks);
//check if valid blockstates
if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) {
for (int i = newCoordinates.size() - 1; i >= 0; i--) {
BlockPos blockPos = newCoordinates.get(i);
IBlockState blockState = blockStates.get(i);
ItemStack itemstack = itemStacks.get(i);
//Check if can place
if (!itemstack.isEmpty() && SurvivalHelper.canPlayerEdit(player, player.world, blockPos, itemstack) &&
SurvivalHelper.mayPlace(player.world, Block.getBlockFromItem(itemstack.getItem()), blockState, blockPos, true, EnumFacing.UP, player) &&
SurvivalHelper.canReplace(player.world, player, blockPos)) {
ShaderHelper.useShader(ShaderHelper.dissolve, generateShaderCallback(percentile,
new Vec3d(blockPos), new Vec3d(firstPos), new Vec3d(secondPos),
/*blockPos == firstPos ||*/ blockPos == secondPos));
renderBlockPreview(dispatcher, blockPos, blockState);
}
}
}
}
endBlockPreviews();
beginLines();
//Draw outlines if tool in hand
//Find proper raytrace: either normal range or increased range depending on canBreakFar
RayTraceResult objectMouseOver = Minecraft.getMinecraft().objectMouseOver;
RayTraceResult breakingRaytrace = ReachHelper.canBreakFar(player) ? lookingAt : objectMouseOver;
if (toolInHand && breakingRaytrace != null && breakingRaytrace.typeOfHit == RayTraceResult.Type.BLOCK) {
List<BlockPos> breakCoordinates = BuildModifiers.findCoordinates(player, breakingRaytrace.getBlockPos());
//Only render first outline if further than normal reach
boolean excludeFirst = objectMouseOver != null && objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK;
for (int i = excludeFirst ? 1 : 0; i < breakCoordinates.size(); i++) {
BlockPos coordinate = breakCoordinates.get(i);
IBlockState blockState = player.world.getBlockState(coordinate);
if (!blockState.getBlock().isAir(blockState, player.world, coordinate)) {
if (SurvivalHelper.canBreak(player.world, player, coordinate) || i == 0) {
renderBlockOutline(coordinate);
}
}
}
}
endLines();
}
end();
}
//----Mirror----
public static void drawMirrorPlane(Vec3d posA, Vec3d posB, Color c, boolean drawLines, boolean drawPlanes, boolean drawVerticalLines) {
GL11.glColor4d(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha);
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
if (drawPlanes) {
bufferBuilder.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(posA.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posA.x, posB.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posB.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posB.x, posB.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
tessellator.draw();
}
if (drawLines) {
Vec3d middle = posA.add(posB).scale(0.5);
bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(posA.x, middle.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(posB.x, middle.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
if (drawVerticalLines) {
bufferBuilder.pos(middle.x, posA.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(middle.x, posB.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
}
tessellator.draw();
}
}
public static void drawMirrorPlaneY(Vec3d posA, Vec3d posB, Color c, boolean drawLines, boolean drawPlanes) {
GL11.glColor4d(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha());
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
if (drawPlanes) {
bufferBuilder.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(posA.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posA.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posB.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posB.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
tessellator.draw();
}
if (drawLines) {
Vec3d middle = posA.add(posB).scale(0.5);
bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(middle.x, middle.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(middle.x, middle.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(posA.x, middle.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(posB.x, middle.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
tessellator.draw();
}
}
public static void drawMirrorLines(Mirror.MirrorSettings m) {
Vec3d pos = m.position.add(epsilon);
GL11.glColor4d(100, 100, 100, 255);
GL11.glLineWidth(2);
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(pos.x - m.radius, pos.y, pos.z).color(colorX.getRed(), colorX.getGreen(), colorX.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x + m.radius, pos.y, pos.z).color(colorX.getRed(), colorX.getGreen(), colorX.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x, pos.y - m.radius, pos.z).color(colorY.getRed(), colorY.getGreen(), colorY.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x, pos.y + m.radius, pos.z).color(colorY.getRed(), colorY.getGreen(), colorY.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x, pos.y, pos.z - m.radius).color(colorZ.getRed(), colorZ.getGreen(), colorZ.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x, pos.y, pos.z + m.radius).color(colorZ.getRed(), colorZ.getGreen(), colorZ.getBlue(), lineAlpha).endVertex();
tessellator.draw();
}
private static Consumer<Integer> generateShaderCallback(final float percentile, final Vec3d blockpos, final Vec3d firstpos, final Vec3d secondpos, final boolean highlight) {
Minecraft mc = Minecraft.getMinecraft();
return (Integer shader) -> {
int percentileUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "percentile");
int highlightUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "highlight");
int blockposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "blockpos");
int firstposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "firstpos");
int secondposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "secondpos");
int imageUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "image");
int maskUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "mask");
//image
OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).getGlTextureId());
ARBShaderObjects.glUniform1iARB(imageUniform, 0);
OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit);
GlStateManager.enableTexture2D();
GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
//mask
GL11.glBindTexture(GL11.GL_TEXTURE_2D,
mc.renderEngine.getTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png")).getGlTextureId());
ARBShaderObjects.glUniform1iARB(maskUniform, secondaryTextureUnit);
//blockpos
ARBShaderObjects.glUniform3fARB(blockposUniform, (float) blockpos.x, (float) blockpos.y, (float) blockpos.z);
ARBShaderObjects.glUniform3fARB(firstposUniform, (float) firstpos.x, (float) firstpos.y, (float) firstpos.z);
ARBShaderObjects.glUniform3fARB(secondposUniform, (float) secondpos.x, (float) secondpos.y, (float) secondpos.z);
//percentile
ARBShaderObjects.glUniform1fARB(percentileUniform, percentile);
//highlight
ARBShaderObjects.glUniform1iARB(highlightUniform, highlight ? 1 : 0);
};
}
//IWORLDEVENTLISTENER IMPLEMENTATION
@Override
public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) {
}
@Override
public void notifyLightSet(BlockPos pos) {
}
@Override
public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {
}
@Override
public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category,
double x, double y, double z, float volume, float pitch) {
}
@Override
public void playRecord(SoundEvent soundIn, BlockPos pos) {
}
@Override
public void spawnParticle(int particleID, boolean ignoreRange, double xCoord, double yCoord, double zCoord,
double xSpeed, double ySpeed, double zSpeed, int... parameters) {
}
@Override
public void spawnParticle(int id, boolean ignoreRange, boolean p_190570_3_, double x, double y, double z,
double xSpeed, double ySpeed, double zSpeed, int... parameters) {
}
@Override
public void onEntityAdded(Entity entityIn) {
}
@Override
public void onEntityRemoved(Entity entityIn) {
}
@Override
public void broadcastSound(int soundID, BlockPos pos, int data) {
}
@Override
public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) {
}
//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.getMinecraft();
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);
}
}
}
}

View File

@@ -44,19 +44,9 @@ public class SurvivalHelper {
itemstack = ItemRandomizerBag.findStack(bagInventory, Item.getItemFromBlock(blockState.getBlock())); itemstack = ItemRandomizerBag.findStack(bagInventory, Item.getItemFromBlock(blockState.getBlock()));
} }
//Check if itemstack is correct
if (!(itemstack.getItem() instanceof ItemBlock) || Block.getBlockFromItem(itemstack.getItem()) != blockState.getBlock()) {
EffortlessBuilding.log(player, "Cannot (re)place block", true);
EffortlessBuilding.log("SurvivalHelper#placeBlock: itemstack " + itemstack.toString() + " does not match blockstate " + blockState.toString());
return false;
}
Block block = ((ItemBlock) itemstack.getItem()).getBlock(); Block block = ((ItemBlock) itemstack.getItem()).getBlock();
if (!itemstack.isEmpty() && canPlayerEdit(player, world, pos, itemstack) && if (canPlace(world, player, pos, blockState, itemstack, skipCollisionCheck, facing.getOpposite())) {
mayPlace(world, block, blockState, pos, skipCollisionCheck, facing.getOpposite(), player) &&
canReplace(world, player, pos))
{
//Drop existing block //Drop existing block
//TODO check if can replace //TODO check if can replace
dropBlock(world, player, pos); dropBlock(world, player, pos);
@@ -108,6 +98,107 @@ public class SurvivalHelper {
return false; return false;
} }
//Gives items directly to player
public static void dropBlock(World world, EntityPlayer player, BlockPos pos){
if (player.isCreative()) return;
IBlockState blockState = world.getBlockState(pos);
int fortune = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, player.getHeldItemMainhand());
List<ItemStack> drops = blockState.getBlock().getDrops(world, pos, blockState, fortune);
for (ItemStack drop : drops)
{
ItemHandlerHelper.giveItemToPlayer(player, drop);
}
}
/**
* Check if player can place a block.
* Turn randomizer bag into itemstack inside before.
* @param world
* @param player
* @param pos
* @param newBlockState the blockstate that is going to be placed
* @param itemStack the itemstack used for placing
* @param skipCollisionCheck skips collision check with entities
* @param sidePlacedOn
* @return Whether the player may place the block at pos with itemstack
*/
public static boolean canPlace(World world, EntityPlayer player, BlockPos pos, IBlockState newBlockState, ItemStack itemStack, boolean skipCollisionCheck, EnumFacing sidePlacedOn) {
//Check if itemstack is correct
if (!(itemStack.getItem() instanceof ItemBlock) || Block.getBlockFromItem(itemStack.getItem()) != newBlockState.getBlock()) {
EffortlessBuilding.log(player, "Cannot (re)place block", true);
EffortlessBuilding.log("SurvivalHelper#placeBlock: itemstack " + itemStack.toString() + " does not match blockstate " + newBlockState.toString());
return false;
}
Block block = ((ItemBlock) itemStack.getItem()).getBlock();
return !itemStack.isEmpty() && canPlayerEdit(player, world, pos, itemStack) &&
mayPlace(world, block, newBlockState, pos, skipCollisionCheck, sidePlacedOn, player) &&
canReplace(world, player, pos);
}
//Can be harvested with hand? (or in creative)
private static boolean canReplace(World world, EntityPlayer player, BlockPos pos){
if (player.isCreative()) return true;
IBlockState state = world.getBlockState(pos);
state = state.getBlock().getActualState(state, world, pos);
if (state.getMaterial().isToolNotRequired()) return true;
return false;
}
//From EntityPlayer#canPlayerEdit
private static boolean canPlayerEdit(EntityPlayer player, World world, BlockPos pos, ItemStack stack)
{
if (player.capabilities.allowEdit)
{
//True in creative and survival mode
return true;
}
else
{
//Adventure mode
Block block = world.getBlockState(pos).getBlock();
return stack.canPlaceOn(block) || stack.canEditBlocks();
}
}
//From World#mayPlace
private static boolean mayPlace(World world, Block blockIn, IBlockState newBlockState, BlockPos pos, boolean skipCollisionCheck, EnumFacing sidePlacedOn, @Nullable Entity placer)
{
IBlockState iblockstate1 = world.getBlockState(pos);
AxisAlignedBB axisalignedbb = skipCollisionCheck ? null : blockIn.getDefaultState().getCollisionBoundingBox(world, pos);
if (axisalignedbb != Block.NULL_AABB && !world.checkNoEntityCollision(axisalignedbb.offset(pos), placer))
{
return false;
}
//Check if same block
//Necessary otherwise extra items will be dropped
if (iblockstate1 == newBlockState) {
return false;
}
if (iblockstate1.getMaterial() == Material.CIRCUITS && blockIn == Blocks.ANVIL)
{
return true;
}
//Check quickreplace
if (placer instanceof EntityPlayer && ModifierSettingsManager.getModifierSettings(((EntityPlayer) placer)).doQuickReplace()) {
return true;
}
return iblockstate1.getBlock().isReplaceable(world, pos) && blockIn.canPlaceBlockOnSide(world, pos, sidePlacedOn);
}
//Can break using held tool? (or in creative) //Can break using held tool? (or in creative)
public static boolean canBreak(World world, EntityPlayer player, BlockPos pos) { public static boolean canBreak(World world, EntityPlayer player, BlockPos pos) {
IBlockState blockState = world.getBlockState(pos); IBlockState blockState = world.getBlockState(pos);
@@ -151,75 +242,4 @@ public class SurvivalHelper {
return toolLevel >= block.getHarvestLevel(state); return toolLevel >= block.getHarvestLevel(state);
} }
//Can be harvested with hand? (or in creative)
public static boolean canReplace(World world, EntityPlayer player, BlockPos pos){
if (player.isCreative()) return true;
IBlockState state = world.getBlockState(pos);
state = state.getBlock().getActualState(state, world, pos);
if (state.getMaterial().isToolNotRequired()) return true;
return false;
}
//Gives items directly to player
public static void dropBlock(World world, EntityPlayer player, BlockPos pos){
if (player.isCreative()) return;
IBlockState blockState = world.getBlockState(pos);
int fortune = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, player.getHeldItemMainhand());
List<ItemStack> drops = blockState.getBlock().getDrops(world, pos, blockState, fortune);
for (ItemStack drop : drops)
{
ItemHandlerHelper.giveItemToPlayer(player, drop);
}
}
//From EntityPlayer#canPlayerEdit
public static boolean canPlayerEdit(EntityPlayer player, World world, BlockPos pos, ItemStack stack)
{
if (player.capabilities.allowEdit)
{
//True in creative and survival mode
return true;
}
else
{
//Adventure mode
Block block = world.getBlockState(pos).getBlock();
return stack.canPlaceOn(block) || stack.canEditBlocks();
}
}
//From World#mayPlace
public static boolean mayPlace(World world, Block blockIn, IBlockState newBlockState, BlockPos pos, boolean skipCollisionCheck, EnumFacing sidePlacedOn, @Nullable Entity placer)
{
IBlockState iblockstate1 = world.getBlockState(pos);
AxisAlignedBB axisalignedbb = skipCollisionCheck ? null : blockIn.getDefaultState().getCollisionBoundingBox(world, pos);
if (axisalignedbb != Block.NULL_AABB && !world.checkNoEntityCollision(axisalignedbb.offset(pos), placer))
{
return false;
}
//Check if same block
//Necessary otherwise extra items will be dropped
if (iblockstate1 == newBlockState) {
return false;
}
if (iblockstate1.getMaterial() == Material.CIRCUITS && blockIn == Blocks.ANVIL)
{
return true;
}
//Check quickreplace
if (placer instanceof EntityPlayer && ModifierSettingsManager.getModifierSettings(((EntityPlayer) placer)).doQuickReplace()) {
return true;
}
return iblockstate1.getBlock().isReplaceable(world, pos) && blockIn.canPlaceBlockOnSide(world, pos, sidePlacedOn);
}
} }

View File

@@ -13,6 +13,9 @@ import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
/***
* Sends a message to the server indicating that a player wants to break a block
*/
public class BlockBrokenMessage implements IMessage { public class BlockBrokenMessage implements IMessage {
private boolean blockHit; private boolean blockHit;

View File

@@ -13,7 +13,12 @@ import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.proxy.ClientProxy;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer;
/***
* Sends a message to the server indicating that a player wants to place a block.
* Received clientside: server has placed blocks and its letting the client know.
*/
public class BlockPlacedMessage implements IMessage { public class BlockPlacedMessage implements IMessage {
private boolean blockHit; private boolean blockHit;
@@ -81,8 +86,11 @@ public class BlockPlacedMessage implements IMessage {
if (ctx.side == Side.CLIENT){ if (ctx.side == Side.CLIENT){
//Received clientside //Received clientside
//Send back your info EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
return new BlockPlacedMessage(ClientProxy.previousLookAt); //Nod RenderHandler to do the dissolve shader effect
BlockPreviewRenderer.onBlocksPlaced();
});
return null;
} else { } else {
//Received serverside //Received serverside
EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> { EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {

View File

@@ -9,6 +9,9 @@ import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
/**
* Sends a message to the server indicating that a buildmode needs to be canceled for a player
*/
public class CancelModeMessage implements IMessage { public class CancelModeMessage implements IMessage {
@Override @Override

View File

@@ -3,8 +3,6 @@ package nl.requios.effortlessbuilding.network;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.IThreadListener; import net.minecraft.util.IThreadListener;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
@@ -14,6 +12,9 @@ import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.*; import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.*;
/**
* Shares mode settings (see ModeSettingsManager) between server and client
*/
public class ModeSettingsMessage implements IMessage { public class ModeSettingsMessage implements IMessage {
private ModeSettings modeSettings; private ModeSettings modeSettings;

View File

@@ -16,6 +16,9 @@ import nl.requios.effortlessbuilding.buildmodifier.RadialMirror;
import static nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.*; import static nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.*;
/**
* Shares modifier settings (see ModifierSettingsManager) between server and client
*/
public class ModifierSettingsMessage implements IMessage { public class ModifierSettingsMessage implements IMessage {
private ModifierSettings modifierSettings; private ModifierSettings modifierSettings;

View File

@@ -0,0 +1,50 @@
package nl.requios.effortlessbuilding.network;
import io.netty.buffer.ByteBuf;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
/***
* Sends a message to the client asking for its lookat (objectmouseover) data.
* This is then sent back with a BlockPlacedMessage.
*/
public class RequestLookAtMessage implements IMessage {
public RequestLookAtMessage() {
}
@Override
public void toBytes(ByteBuf buf) {
}
@Override
public void fromBytes(ByteBuf buf) {
}
// The params of the IMessageHandler are <REQ, REPLY>
public static class MessageHandler implements IMessageHandler<RequestLookAtMessage, IMessage> {
// Do note that the default constructor is required, but implicitly defined in this case
@Override
public IMessage onMessage(RequestLookAtMessage message, MessageContext ctx) {
//EffortlessBuilding.log("message received on " + ctx.side + " side");
if (ctx.side == Side.CLIENT){
//Received clientside
//Send back your info
return new BlockPlacedMessage(ClientProxy.previousLookAt);
}
return null;
}
}
}

View File

@@ -9,6 +9,7 @@ import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.texture.TextureUtil; import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResource;
@@ -52,8 +53,8 @@ import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu; import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu;
import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui; import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.RenderHelper; import nl.requios.effortlessbuilding.render.RenderHandler;
import nl.requios.effortlessbuilding.helper.ShaderHelper; import nl.requios.effortlessbuilding.render.ShaderHandler;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import nl.requios.effortlessbuilding.network.*; import nl.requios.effortlessbuilding.network.*;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
@@ -72,11 +73,11 @@ public class ClientProxy implements IProxy {
public static int ticksInGame = 0; public static int ticksInGame = 0;
private static final HashMap<BuildModes.BuildModeEnum, RadialMenu.SpriteIconPositioning> buildModeIcons = new HashMap<>(); private static final HashMap<BuildModes.BuildModeEnum, TextureAtlasSprite> buildModeIcons = new HashMap<>();
@Override @Override
public void preInit(FMLPreInitializationEvent event) { public void preInit(FMLPreInitializationEvent event) {
ShaderHelper.init(); ShaderHandler.init();
} }
@Override @Override
@@ -131,7 +132,7 @@ public class ClientProxy implements IProxy {
@SubscribeEvent @SubscribeEvent
public static void onEntityJoinWorld(EntityJoinWorldEvent event) { public static void onEntityJoinWorld(EntityJoinWorldEvent event) {
if (event.getEntity() == Minecraft.getMinecraft().player) { if (event.getEntity() == Minecraft.getMinecraft().player) {
event.getWorld().addEventListener(new RenderHelper()); event.getWorld().addEventListener(new RenderHandler());
} }
} }
@@ -142,67 +143,12 @@ public class ClientProxy implements IProxy {
for ( final BuildModes.BuildModeEnum mode : BuildModes.BuildModeEnum.values() ) for ( final BuildModes.BuildModeEnum mode : BuildModes.BuildModeEnum.values() )
{ {
loadIcon( map, mode ); final ResourceLocation sprite = new ResourceLocation("effortlessbuilding", "icons/" + mode.name().toLowerCase());
buildModeIcons.put( mode, map.registerSprite(sprite));
} }
} }
/** public static TextureAtlasSprite getBuildModeIcon(BuildModes.BuildModeEnum mode) {
* From Chisels and Bits by AlgorithmX2
* https://github.com/AlgorithmX2/Chisels-and-Bits/blob/1.12/src/main/java/mod/chiselsandbits/core/ClientSide.java
*/
private static void loadIcon(final TextureMap map, final BuildModes.BuildModeEnum mode) {
final RadialMenu.SpriteIconPositioning sip = new RadialMenu.SpriteIconPositioning();
final ResourceLocation sprite = new ResourceLocation( "effortlessbuilding", "icons/" + mode.name().toLowerCase() );
final ResourceLocation png = new ResourceLocation( "effortlessbuilding", "textures/icons/" + mode.name().toLowerCase() + ".png" );
sip.sprite = map.registerSprite( sprite );
try
{
final IResource iresource = Minecraft.getMinecraft().getResourceManager().getResource( png );
final BufferedImage bi = TextureUtil.readBufferedImage( iresource.getInputStream() );
int bottom = 0;
int right = 0;
sip.left = bi.getWidth();
sip.top = bi.getHeight();
for ( int x = 0; x < bi.getWidth(); x++ )
{
for ( int y = 0; y < bi.getHeight(); y++ )
{
final int color = bi.getRGB( x, y );
final int a = color >> 24 & 0xff;
if ( a > 0 )
{
sip.left = Math.min( sip.left, x );
right = Math.max( right, x );
sip.top = Math.min( sip.top, y );
bottom = Math.max( bottom, y );
}
}
}
sip.height = bottom - sip.top + 1;
sip.width = right - sip.left + 1;
sip.left /= bi.getWidth();
sip.width /= bi.getWidth();
sip.top /= bi.getHeight();
sip.height /= bi.getHeight();
} catch (final IOException e) {
sip.height = 1;
sip.width = 1;
sip.left = 0;
sip.top = 0;
}
buildModeIcons.put( mode, sip );
}
public static RadialMenu.SpriteIconPositioning getBuildModeIcon(BuildModes.BuildModeEnum mode) {
return buildModeIcons.get(mode); return buildModeIcons.get(mode);
} }
@@ -295,8 +241,6 @@ public class ClientProxy implements IProxy {
//QuickReplace toggle //QuickReplace toggle
if (keyBindings[1].isPressed()) { if (keyBindings[1].isPressed()) {
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace()); modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace());
EffortlessBuilding.log(player, "Set "+ TextFormatting.GOLD + "Quick Replace " + TextFormatting.RESET + ( EffortlessBuilding.log(player, "Set "+ TextFormatting.GOLD + "Quick Replace " + TextFormatting.RESET + (
@@ -315,8 +259,10 @@ public class ClientProxy implements IProxy {
if (keyBindings[4].isPressed()) { if (keyBindings[4].isPressed()) {
//TODO remove //TODO remove
ShaderHelper.init(); ShaderHandler.init();
EffortlessBuilding.log(player, "Reloaded shaders"); EffortlessBuilding.log(player, "Reloaded shaders");
//player.playSound(SoundEvents.UI_BUTTON_CLICK, 1f, 1f);
player.playSound(EffortlessBuilding.SOUND_BUILD_CLICK, 1f, 1f);
} }
} }

View File

@@ -0,0 +1,285 @@
package nl.requios.effortlessbuilding.render;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import nl.requios.effortlessbuilding.BuildConfig;
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.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import org.lwjgl.opengl.ARBMultitexture;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.GL11;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
@SideOnly(Side.CLIENT)
public class BlockPreviewRenderer {
private static List<BlockPos> previousCoordinates;
private static List<IBlockState> previousBlockStates;
private static List<ItemStack> previousItemStacks;
private static BlockPos previousFirstPos;
private static BlockPos previousSecondPos;
private static int soundTime = 0;
static class PlacedData {
float time;
List<BlockPos> coordinates;
List<IBlockState> blockStates;
List<ItemStack> itemStacks;
BlockPos firstPos;
BlockPos secondPos;
public PlacedData(float time, List<BlockPos> coordinates, List<IBlockState> blockStates, List<ItemStack> itemStacks, BlockPos firstPos, BlockPos secondPos) {
this.time = time;
this.coordinates = coordinates;
this.blockStates = blockStates;
this.itemStacks = itemStacks;
this.firstPos = firstPos;
this.secondPos = secondPos;
}
}
private static List<PlacedData> placedDataList = new ArrayList<>();
private static final int secondaryTextureUnit = 7;
public static void render(EntityPlayer player, ModifierSettingsManager.ModifierSettings modifierSettings, ModeSettingsManager.ModeSettings modeSettings) {
//Render placed blocks with dissolve effect
for (int i = 0; i < placedDataList.size(); i++) {
PlacedData placed = placedDataList.get(i);
if (placed.coordinates != null && !placed.coordinates.isEmpty()) {
RenderHandler.beginBlockPreviews();
float dissolve = (ClientProxy.ticksInGame - placed.time) / (float) BuildConfig.visuals.dissolveTime;
renderBlockPreviews(placed.coordinates, placed.blockStates, placed.itemStacks, dissolve, placed.firstPos, placed.secondPos, false);
RenderHandler.endBlockPreviews();
}
}
//Expire
placedDataList.removeIf(placed -> placed.time + BuildConfig.visuals.dissolveTime < ClientProxy.ticksInGame);
//Render block previews
RayTraceResult lookingAt = ClientProxy.getLookingAt(player);
if (modeSettings.getBuildMode() == BuildModes.BuildModeEnum.Normal) lookingAt = Minecraft.getMinecraft().objectMouseOver;
ItemStack mainhand = player.getHeldItemMainhand();
boolean toolInHand = !(!mainhand.isEmpty() && (mainhand.getItem() instanceof ItemBlock || mainhand.getItem() instanceof ItemRandomizerBag));
BlockPos startPos = null;
EnumFacing sideHit = null;
Vec3d 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.typeOfHit == RayTraceResult.Type.BLOCK) {
startPos = lookingAt.getBlockPos();
//Check if tool (or none) in hand
boolean replaceable = player.world.getBlockState(startPos).getBlock().isReplaceable(player.world, startPos);
if (!modifierSettings.doQuickReplace() && !toolInHand && !replaceable) {
startPos = startPos.offset(lookingAt.sideHit);
}
//Get under tall grass and other replaceable blocks
if (modifierSettings.doQuickReplace() && !toolInHand && replaceable) {
startPos = startPos.down();
}
sideHit = lookingAt.sideHit;
hitVec = lookingAt.hitVec;
}
//Dont render if in normal mode and modifiers are disabled
//Unless alwaysShowBlockPreview is true in config
if (modeSettings.getBuildMode() != BuildModes.BuildModeEnum.Normal ||
(startPos != null && BuildModifiers.isEnabled(modifierSettings, startPos)) ||
BuildConfig.visuals.alwaysShowBlockPreview) {
RenderHandler.beginBlockPreviews();
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) {
//get coordinates
List<BlockPos> startCoordinates = BuildModes.findCoordinates(player, startPos);
BlockPos firstPos = BlockPos.ORIGIN, secondPos = BlockPos.ORIGIN;
//Remember first and last pos for the shader
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);
Collections.sort(newCoordinates, (lhs, rhs) -> {
// -1 - less than, 1 - greater than, 0 - equal
double lhsDistanceToPlayer = new Vec3d(lhs).subtract(player.getPositionEyes(1f)).lengthSquared();
double rhsDistanceToPlayer = new Vec3d(rhs).subtract(player.getPositionEyes(1f)).lengthSquared();
return (int) Math.signum(lhsDistanceToPlayer - rhsDistanceToPlayer);
});
hitVec = new Vec3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)),
Math.abs(hitVec.z - ((int) hitVec.z)));
List<ItemStack> itemStacks = new ArrayList<>();
List<IBlockState> 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
ItemRandomizerBag.renewRandomness();
//and play sound (max once every tick)
if (newCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientProxy.ticksInGame - 0) {
soundTime = ClientProxy.ticksInGame;
//player.playSound(EffortlessBuilding.SOUND_BUILD_CLICK, 0.2f, 1f);
player.playSound(blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.world,
newCoordinates.get(0), player).getPlaceSound(), 0.3f, 1f);
}
}
//Render block previews
if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) {
renderBlockPreviews(newCoordinates, blockStates, itemStacks, 0f, firstPos, secondPos, true);
}
}
RenderHandler.endBlockPreviews();
RenderHandler.beginLines();
//Draw outlines if tool in hand
//Find proper raytrace: either normal range or increased range depending on canBreakFar
RayTraceResult objectMouseOver = Minecraft.getMinecraft().objectMouseOver;
RayTraceResult breakingRaytrace = ReachHelper.canBreakFar(player) ? lookingAt : objectMouseOver;
if (toolInHand && breakingRaytrace != null && breakingRaytrace.typeOfHit == RayTraceResult.Type.BLOCK) {
List<BlockPos> breakCoordinates = BuildModifiers.findCoordinates(player, breakingRaytrace.getBlockPos());
//Only render first outline if further than normal reach
boolean excludeFirst = objectMouseOver != null && objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK;
for (int i = excludeFirst ? 1 : 0; i < breakCoordinates.size(); i++) {
BlockPos coordinate = breakCoordinates.get(i);
IBlockState blockState = player.world.getBlockState(coordinate);
if (!blockState.getBlock().isAir(blockState, player.world, coordinate)) {
if (SurvivalHelper.canBreak(player.world, player, coordinate) || i == 0) {
RenderHandler.renderBlockOutline(coordinate);
}
}
}
}
RenderHandler.endLines();
}
}
protected static void renderBlockPreviews(List<BlockPos> coordinates, List<IBlockState> blockStates,
List<ItemStack> itemStacks, float dissolve, BlockPos firstPos,
BlockPos secondPos, boolean checkCanPlace) {
EntityPlayer player = Minecraft.getMinecraft().player;
BlockRendererDispatcher dispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher();
for (int i = coordinates.size() - 1; i >= 0; i--) {
BlockPos blockPos = coordinates.get(i);
IBlockState blockState = blockStates.get(i);
ItemStack itemstack = itemStacks.get(i);
//Check if can place
//If check is turned off, check if blockstate is the same (for dissolve effect)
if (SurvivalHelper.canPlace(player.world, player, blockPos, blockState, itemstack, true, EnumFacing.UP) ||
(!checkCanPlace && player.world.getBlockState(blockPos) == blockState)) {
ShaderHandler.useShader(ShaderHandler.dissolve, generateShaderCallback(dissolve,
new Vec3d(blockPos), new Vec3d(firstPos), new Vec3d(secondPos),
blockPos == secondPos));
RenderHandler.renderBlockPreview(dispatcher, blockPos, blockState);
}
}
}
public static void onBlocksPlaced() {
//Save current coordinates, blockstates and itemstacks
placedDataList.add(new PlacedData(ClientProxy.ticksInGame, previousCoordinates, previousBlockStates,
previousItemStacks, previousFirstPos, previousSecondPos));
}
private static Consumer<Integer> generateShaderCallback(final float dissolve, final Vec3d blockpos, final Vec3d firstpos, final Vec3d secondpos, final boolean highlight) {
Minecraft mc = Minecraft.getMinecraft();
return (Integer shader) -> {
int percentileUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "dissolve");
int highlightUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "highlight");
int blockposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "blockpos");
int firstposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "firstpos");
int secondposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "secondpos");
int imageUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "image");
int maskUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "mask");
//image
OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).getGlTextureId());
ARBShaderObjects.glUniform1iARB(imageUniform, 0);
OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit);
GlStateManager.enableTexture2D();
GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
//mask
GL11.glBindTexture(GL11.GL_TEXTURE_2D,
mc.renderEngine.getTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png")).getGlTextureId());
ARBShaderObjects.glUniform1iARB(maskUniform, secondaryTextureUnit);
//blockpos
ARBShaderObjects.glUniform3fARB(blockposUniform, (float) blockpos.x, (float) blockpos.y, (float) blockpos.z);
ARBShaderObjects.glUniform3fARB(firstposUniform, (float) firstpos.x, (float) firstpos.y, (float) firstpos.z);
ARBShaderObjects.glUniform3fARB(secondposUniform, (float) secondpos.x, (float) secondpos.y, (float) secondpos.z);
//dissolve
ARBShaderObjects.glUniform1fARB(percentileUniform, dissolve);
//highlight
ARBShaderObjects.glUniform1iARB(highlightUniform, highlight ? 1 : 0);
};
}
}

View File

@@ -0,0 +1,175 @@
package nl.requios.effortlessbuilding.render;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import nl.requios.effortlessbuilding.buildmodifier.Mirror;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.RadialMirror;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.Color;
@SideOnly(Side.CLIENT)
public class ModifierRenderer {
protected static final Color colorX = new Color(255, 72, 52);
protected static final Color colorY = new Color(67, 204, 51);
protected static final Color colorZ = new Color(52, 247, 255);
protected static final Color colorRadial = new Color(52, 247, 255);
protected static final int lineAlpha = 200;
protected static final int planeAlpha = 75;
protected static final Vec3d epsilon = new Vec3d(0.001, 0.001, 0.001); //prevents z-fighting
public static void render(ModifierSettingsManager.ModifierSettings modifierSettings) {
RenderHandler.beginLines();
//Mirror lines and areas
Mirror.MirrorSettings m = modifierSettings.getMirrorSettings();
if (m != null && m.enabled && (m.mirrorX || m.mirrorY || m.mirrorZ))
{
Vec3d pos = m.position.add(epsilon);
int radius = m.radius;
if (m.mirrorX)
{
Vec3d posA = new Vec3d(pos.x, pos.y - radius, pos.z - radius);
Vec3d posB = new Vec3d(pos.x, pos.y + radius, pos.z + radius);
drawMirrorPlane(posA, posB, colorX, m.drawLines, m.drawPlanes, true);
}
if (m.mirrorY)
{
Vec3d posA = new Vec3d(pos.x - radius, pos.y, pos.z - radius);
Vec3d posB = new Vec3d(pos.x + radius, pos.y, pos.z + radius);
drawMirrorPlaneY(posA, posB, colorY, m.drawLines, m.drawPlanes);
}
if (m.mirrorZ)
{
Vec3d posA = new Vec3d(pos.x - radius, pos.y - radius, pos.z);
Vec3d posB = new Vec3d(pos.x + radius, pos.y + radius, pos.z);
drawMirrorPlane(posA, posB, colorZ, m.drawLines, m.drawPlanes, true);
}
//Draw axis coordinated colors if two or more axes are enabled
//(If only one is enabled the lines are that planes color)
if (m.drawLines && ((m.mirrorX && m.mirrorY) || (m.mirrorX && m.mirrorZ) || (m.mirrorY && m.mirrorZ)))
{
drawMirrorLines(m);
}
}
//Radial mirror lines and areas
RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings();
if (r != null && r.enabled)
{
Vec3d pos = r.position.add(epsilon);
int radius = r.radius;
float angle = 2f * ((float) Math.PI) / r.slices;
Vec3d relStartVec = new Vec3d(radius, 0, 0);
if (r.slices%4 == 2) relStartVec = relStartVec.rotateYaw(angle / 2f);
for (int i = 0; i < r.slices; i++) {
Vec3d relNewVec = relStartVec.rotateYaw(angle * i);
Vec3d newVec = pos.add(relNewVec);
Vec3d posA = new Vec3d(pos.x, pos.y - radius, pos.z);
Vec3d posB = new Vec3d(newVec.x, pos.y + radius, newVec.z);
drawMirrorPlane(posA, posB, colorRadial, r.drawLines, r.drawPlanes, false);
}
}
RenderHandler.endLines();
}
//----Mirror----
protected static void drawMirrorPlane(Vec3d posA, Vec3d posB, Color c, boolean drawLines, boolean drawPlanes, boolean drawVerticalLines) {
GL11.glColor4d(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha);
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
if (drawPlanes) {
bufferBuilder.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(posA.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posA.x, posB.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posB.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posB.x, posB.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
tessellator.draw();
}
if (drawLines) {
Vec3d middle = posA.add(posB).scale(0.5);
bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(posA.x, middle.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(posB.x, middle.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
if (drawVerticalLines) {
bufferBuilder.pos(middle.x, posA.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(middle.x, posB.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
}
tessellator.draw();
}
}
protected static void drawMirrorPlaneY(Vec3d posA, Vec3d posB, Color c, boolean drawLines, boolean drawPlanes) {
GL11.glColor4d(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha());
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
if (drawPlanes) {
bufferBuilder.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(posA.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posA.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posB.x, posA.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
bufferBuilder.pos(posB.x, posA.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), planeAlpha).endVertex();
tessellator.draw();
}
if (drawLines) {
Vec3d middle = posA.add(posB).scale(0.5);
bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(middle.x, middle.y, posA.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(middle.x, middle.y, posB.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(posA.x, middle.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(posB.x, middle.y, middle.z).color(c.getRed(), c.getGreen(), c.getBlue(), lineAlpha).endVertex();
tessellator.draw();
}
}
protected static void drawMirrorLines(Mirror.MirrorSettings m) {
Vec3d pos = m.position.add(epsilon);
GL11.glColor4d(100, 100, 100, 255);
GL11.glLineWidth(2);
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
bufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
bufferBuilder.pos(pos.x - m.radius, pos.y, pos.z).color(colorX.getRed(), colorX.getGreen(), colorX.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x + m.radius, pos.y, pos.z).color(colorX.getRed(), colorX.getGreen(), colorX.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x, pos.y - m.radius, pos.z).color(colorY.getRed(), colorY.getGreen(), colorY.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x, pos.y + m.radius, pos.z).color(colorY.getRed(), colorY.getGreen(), colorY.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x, pos.y, pos.z - m.radius).color(colorZ.getRed(), colorZ.getGreen(), colorZ.getBlue(), lineAlpha).endVertex();
bufferBuilder.pos(pos.x, pos.y, pos.z + m.radius).color(colorZ.getRed(), colorZ.getGreen(), colorZ.getBlue(), lineAlpha).endVertex();
tessellator.draw();
}
}

View File

@@ -0,0 +1,213 @@
package nl.requios.effortlessbuilding.render;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import javax.annotation.Nullable;
import java.util.List;
/***
* Main render class for Effortless Building
*/
@Mod.EventBusSubscriber(Side.CLIENT)
public class RenderHandler implements IWorldEventListener {
@SubscribeEvent
public static void onRender(RenderWorldLastEvent event) {
EntityPlayer player = Minecraft.getMinecraft().player;
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
begin(event.getPartialTicks());
//Mirror and radial mirror lines and areas
ModifierRenderer.render(modifierSettings);
//Render block previews
BlockPreviewRenderer.render(player, modifierSettings, modeSettings);
end();
}
private static void begin(float partialTicks) {
EntityPlayer player = Minecraft.getMinecraft().player;
double playerX = player.prevPosX + (player.posX - player.prevPosX) * partialTicks;
double playerY = player.prevPosY + (player.posY - player.prevPosY) * partialTicks;
double playerZ = player.prevPosZ + (player.posZ - player.prevPosZ) * partialTicks;
Vec3d playerPos = new Vec3d(playerX, playerY, playerZ);
GL11.glPushMatrix();
GL11.glTranslated(-playerPos.x, -playerPos.y, -playerPos.z);
GL11.glDepthMask(false);
}
protected static void beginLines() {
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glLineWidth(2);
}
protected static void endLines() {
GL11.glPopAttrib();
}
protected static void beginBlockPreviews() {
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_color.png"));
Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png"));
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL14.glBlendColor(1F, 1F, 1F, 0.8f);
}
protected static void endBlockPreviews() {
ShaderHandler.releaseShader();
GlStateManager.disableBlend();
GL11.glPopAttrib();
}
private static void end() {
GL11.glDepthMask(true);
GL11.glPopMatrix();
}
protected static void renderBlockPreview(BlockRendererDispatcher dispatcher, BlockPos blockPos, IBlockState blockState) {
GlStateManager.pushMatrix();
GlStateManager.translate(blockPos.getX(), blockPos.getY(), blockPos.getZ());
GlStateManager.rotate(-90.0F, 0.0F, 1.0F, 0.0F);
GlStateManager.translate(-0.005f, -0.005f, 0.005f);
GlStateManager.scale(1.01f, 1.01f, 1.01f);
dispatcher.renderBlockBrightness(blockState, 0.85f);
GlStateManager.popMatrix();
}
protected static void renderBlockOutline(BlockPos pos) {
renderBlockOutline(pos, pos);
}
//Renders outline. Pos1 has to be minimal x,y,z and pos2 maximal x,y,z
protected static void renderBlockOutline(BlockPos pos1, BlockPos pos2) {
GL11.glLineWidth(2);
AxisAlignedBB aabb = new AxisAlignedBB(pos1, pos2.add(1, 1, 1)).grow(0.0020000000949949026);
RenderGlobal.drawSelectionBoundingBox(aabb, 0f, 0f, 0f, 0.4f);
}
//IWORLDEVENTLISTENER IMPLEMENTATION
@Override
public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) {
}
@Override
public void notifyLightSet(BlockPos pos) {
}
@Override
public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {
}
@Override
public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category,
double x, double y, double z, float volume, float pitch) {
}
@Override
public void playRecord(SoundEvent soundIn, BlockPos pos) {
}
@Override
public void spawnParticle(int particleID, boolean ignoreRange, double xCoord, double yCoord, double zCoord,
double xSpeed, double ySpeed, double zSpeed, int... parameters) {
}
@Override
public void spawnParticle(int id, boolean ignoreRange, boolean p_190570_3_, double x, double y, double z,
double xSpeed, double ySpeed, double zSpeed, int... parameters) {
}
@Override
public void onEntityAdded(Entity entityIn) {
}
@Override
public void onEntityRemoved(Entity entityIn) {
}
@Override
public void broadcastSound(int soundID, BlockPos pos, int data) {
}
@Override
public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) {
}
//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.getMinecraft();
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);
}
}
}
}

View File

@@ -10,27 +10,22 @@
* *
* File Created @ [Apr 9, 2014, 11:20:26 PM (GMT)] * File Created @ [Apr 9, 2014, 11:20:26 PM (GMT)]
*/ */
package nl.requios.effortlessbuilding.helper; package nl.requios.effortlessbuilding.render;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.OpenGlHelper;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.proxy.ClientProxy;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
import org.lwjgl.opengl.*; import org.lwjgl.opengl.*;
import org.lwjgl.util.vector.Matrix4f;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.FloatBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.function.Consumer; import java.util.function.Consumer;
public final class ShaderHelper { public final class ShaderHandler {
private static final int VERT_ST = ARBVertexShader.GL_VERTEX_SHADER_ARB; private static final int VERT_ST = ARBVertexShader.GL_VERTEX_SHADER_ARB;
private static final int FRAG_ST = ARBFragmentShader.GL_FRAGMENT_SHADER_ARB; private static final int FRAG_ST = ARBFragmentShader.GL_FRAGMENT_SHADER_ARB;
@@ -149,7 +144,7 @@ public final class ShaderHelper {
private static String readFileAsString(String filename) throws Exception { private static String readFileAsString(String filename) throws Exception {
StringBuilder source = new StringBuilder(); StringBuilder source = new StringBuilder();
InputStream in = ShaderHelper.class.getResourceAsStream(filename); InputStream in = ShaderHandler.class.getResourceAsStream(filename);
Exception exception = null; Exception exception = null;
BufferedReader reader; BufferedReader reader;

View File

@@ -9,4 +9,6 @@ item.effortlessbuilding:reach_upgrade1.name=Reach Upgrade 1
item.effortlessbuilding:reach_upgrade2.name=Reach Upgrade 2 item.effortlessbuilding:reach_upgrade2.name=Reach Upgrade 2
item.effortlessbuilding:reach_upgrade3.name=Reach Upgrade 3 item.effortlessbuilding:reach_upgrade3.name=Reach Upgrade 3
commands.reach.usage=/reach <level> commands.reach.usage=/reach <level>
effortlessbuilding.subtitle.build_click=Click

View File

@@ -2,7 +2,7 @@
uniform int time; // Passed in, see ShaderHelper.java uniform int time; // Passed in, see ShaderHelper.java
uniform float percentile; // Passed in via Callback uniform float dissolve; // Passed in via Callback
uniform int highlight; uniform int highlight;
uniform vec3 blockpos; uniform vec3 blockpos;
uniform vec3 firstpos; uniform vec3 firstpos;
@@ -44,28 +44,28 @@ void main() {
vec4 maskColor = texture2D(mask, maskcoord); vec4 maskColor = texture2D(mask, maskcoord);
float maskgs = maskColor.r; float maskgs = maskColor.r;
//color.rgb *= gl_Color.rgb; color.rgb *= gl_Color.rgb;
//desaturate //desaturate
color.rgb *= vec3(0.8); color.rgb *= vec3(0.8);
//add blueish hue //add blueish hue
color.rgb += vec3(-0.2, 0.0, 0.3); color.rgb += vec3(-0.1, 0.0, 0.2);
//add pulsing blue //add pulsing blue
float pulse = (sin(time / 5.0) + 1.0) / 2.0; float pulse = (sin(time / 5.0) + 1.0) / 2.0;
color.rgb += (1.0 - color.rgb) * vec3(-0.5, 0.2, 0.6) * pulse; color.rgb += 0.4 * vec3(-0.5, 0.2, 0.6) * pulse;
//add diagonal highlights //add diagonal highlights
float diagTime = mod(time / 40.0, 1.4) - 0.2; float diagTime = mod(time / 40.0, 1.4) - 0.2;
float diag = smoothstep(diagTime - 0.2, diagTime, place) - smoothstep(diagTime, diagTime + 0.2, place); float diag = smoothstep(diagTime - 0.2, diagTime, place) - smoothstep(diagTime, diagTime + 0.2, place);
color.rgb += (1.0 - color.rgb) * diag * vec3(0.0, 0.2, 0.4); color.rgb += 0.2 * diag * vec3(0.0, 0.2, 0.4);
float diagTime2 = mod(time / 70.0, 1.4) - 0.2; float diagTime2 = mod(time / 70.0, 1.4) - 0.2;
float diag2 = smoothstep(diagTime2 - 0.2, diagTime2, place) - smoothstep(diagTime2, diagTime2 + 0.2, place); float diag2 = smoothstep(diagTime2 - 0.2, diagTime2, place) - smoothstep(diagTime2, diagTime2 + 0.2, place);
color.rgb += (1.0 - color.rgb) * diag2 * vec3(0.0, 0.4, 0.8); color.rgb += 0.2 * diag2 * vec3(0.0, 0.4, 0.8);
//add shading //add edge shading
// vec3 p1; // vec3 p1;
// //if (firstpos.x < secondpos.x) // //if (firstpos.x < secondpos.x)
// //
@@ -77,21 +77,16 @@ void main() {
// float distToEdge = min(min(distToEdge1, distToEdge2), distToEdge3); // float distToEdge = min(min(distToEdge1, distToEdge2), distToEdge3);
// color.rgb += vec3(0.5 - smoothstep(0, 0.5, distToEdge)) * 0.5; // color.rgb += vec3(0.5 - smoothstep(0, 0.5, distToEdge)) * 0.5;
//add flat shading
if (abs(normal.x) > 0.5)
color.rgb -= 0.0;
if (abs(normal.y) > 0.5)
color.rgb += 0.05;
if (abs(normal.z) > 0.5)
color.rgb -= 0.05;
// pulse = 1.0;//pulse / 2.0 + 0.5;
// vec4 pulseColor = texture2D(mask, maskcoord + time / 700.0);
// vec4 pulseColor2 = texture2D(mask, vec2(maskcoord.x + time / 600.0, maskcoord.y - time / 600.0));
// float pulseGreyScale = pulseColor.r + pulseColor2.r / 2.0;
//
// color.r -= color.r * pulseColor.r * pulse * 0.2;
// color.g += (1.0 - color.g) * pulseColor.r * pulse * 0.2;
// color.b += (1.0 - color.b) * pulseColor.r * pulse * 0.8;
//
// color.r -= color.r * pulseColor2.r * pulse * 0.4;
// color.g += (1.0 - color.g) * pulseColor2.r * pulse * 0.2;
// color.b += (1.0 - color.b) * pulseColor2.r * pulse;
if(highlight == 1) { if(highlight == 1 && dissolve == 0.0) {
color.r += 0.0; color.r += 0.0;
color.g += 0.1; color.g += 0.1;
color.b -= 0.2; color.b -= 0.2;
@@ -101,7 +96,7 @@ void main() {
color.g = max(0, min(1, color.g)); color.g = max(0, min(1, color.g));
color.b = max(0, min(1, color.b)); color.b = max(0, min(1, color.b));
if (maskgs * 0.3 + place * 0.7 <= percentile) if (maskgs * 0.3 + place * 0.7 <= dissolve)
gl_FragColor = color; gl_FragColor = vec4(texcolor.rgb, 0.0);
else gl_FragColor = vec4(texcolor.rgb, 0.0); else gl_FragColor = color;
} }

View File

@@ -2,7 +2,7 @@
uniform int time; // Passed in, see ShaderHelper.java uniform int time; // Passed in, see ShaderHelper.java
uniform float percentile; // Passed in via Callback uniform float dissolve; // Passed in via Callback
uniform int highlight; uniform int highlight;
uniform vec3 blockpos; uniform vec3 blockpos;
uniform vec3 firstpos; uniform vec3 firstpos;
@@ -15,6 +15,8 @@ varying vec3 normal;
void main() { void main() {
gl_Position = ftransform();//gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; gl_Position = ftransform();//gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_FrontColor = gl_Color;
gl_BackColor = gl_Color;
position = gl_Vertex; position = gl_Vertex;
normal = gl_Normal; normal = gl_Normal;

View File

@@ -0,0 +1,11 @@
{
"build_click": {
"category": "block",
"subtitle": "effortlessbuilding.subtitle.build_click",
"sounds": [
{
"name": "effortlessbuilding:build_click"
}
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 B

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 B

After

Width:  |  Height:  |  Size: 309 B