diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildMode.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildMode.java new file mode 100644 index 0000000..2d76ec0 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildMode.java @@ -0,0 +1,13 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.math.BlockPos; + +import java.util.List; + +public interface BuildMode { + + List onRightClick(EntityPlayer player, BlockPos startPos); + + List findCoordinates(EntityPlayer player, BlockPos startPos); +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java new file mode 100644 index 0000000..b681dc7 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java @@ -0,0 +1,45 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import nl.requios.effortlessbuilding.EffortlessBuilding; + +public class BuildModes { + + public enum BuildModeEnum { + Normal ("Normal", new Normal()), + NormalPlus ("Normal+", new NormalPlus()), + Line ("Line", new Line()), + Wall ("Wall", new Wall()), + Floor ("Floor", new Floor()) + ; +// DiagonalLine, +// DiagonalWall, +// SlopedFloor, +// Cube; + + public String name; + public final BuildMode instance; + + BuildModeEnum(String name, BuildMode instance) { + this.name = name; + this.instance = instance; + } + } + + protected static BuildModeEnum buildMode = BuildModeEnum.Normal; + + public static BuildModeEnum getBuildMode() { + return buildMode; + } + + public static void setBuildMode(EntityPlayer player, BuildModeEnum buildMode) { + if (player.world.isRemote) { + //TODO send to server + BuildModes.buildMode = buildMode; + EffortlessBuilding.log(player, BuildModes.buildMode.name, true); + } else { + //TODO cancel previous mode's action + BuildModes.buildMode = buildMode; + } + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java new file mode 100644 index 0000000..e643b29 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java @@ -0,0 +1,18 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.math.BlockPos; + +import java.util.List; + +public class Floor implements BuildMode { + @Override + public List onRightClick(EntityPlayer player, BlockPos startPos) { + return null; + } + + @Override + public List findCoordinates(EntityPlayer player, BlockPos startPos) { + return null; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Line.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Line.java new file mode 100644 index 0000000..d833e14 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Line.java @@ -0,0 +1,18 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.math.BlockPos; + +import java.util.List; + +public class Line implements BuildMode { + @Override + public List onRightClick(EntityPlayer player, BlockPos startPos) { + return null; + } + + @Override + public List findCoordinates(EntityPlayer player, BlockPos startPos) { + return null; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Normal.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Normal.java new file mode 100644 index 0000000..e002492 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Normal.java @@ -0,0 +1,23 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.math.BlockPos; + +import java.util.ArrayList; +import java.util.List; + +public class Normal implements BuildMode { + @Override + public List onRightClick(EntityPlayer player, BlockPos startPos) { + List list = new ArrayList<>(); + list.add(startPos); + return list; + } + + @Override + public List findCoordinates(EntityPlayer player, BlockPos startPos) { + List list = new ArrayList<>(); + list.add(startPos); + return list; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/NormalPlus.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/NormalPlus.java new file mode 100644 index 0000000..baf91ef --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/NormalPlus.java @@ -0,0 +1,23 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.math.BlockPos; + +import java.util.ArrayList; +import java.util.List; + +public class NormalPlus implements BuildMode { + @Override + public List onRightClick(EntityPlayer player, BlockPos startPos) { + List list = new ArrayList<>(); + list.add(startPos); + return list; + } + + @Override + public List findCoordinates(EntityPlayer player, BlockPos startPos) { + List list = new ArrayList<>(); + list.add(startPos); + return list; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java new file mode 100644 index 0000000..f6a6792 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java @@ -0,0 +1,18 @@ +package nl.requios.effortlessbuilding.buildmode; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.math.BlockPos; + +import java.util.List; + +public class Wall implements BuildMode { + @Override + public List onRightClick(EntityPlayer player, BlockPos startPos) { + return null; + } + + @Override + public List findCoordinates(EntityPlayer player, BlockPos startPos) { + return null; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/ArraySettingsGui.java b/src/main/java/nl/requios/effortlessbuilding/gui/ArraySettingsGui.java index 62c3204..fccdb64 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/ArraySettingsGui.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/ArraySettingsGui.java @@ -8,6 +8,9 @@ import net.minecraftforge.fml.client.config.GuiCheckBox; import nl.requios.effortlessbuilding.BuildSettingsManager; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmodifier.Array; +import nl.requios.effortlessbuilding.gui.elements.GuiCollapsibleScrollEntry; +import nl.requios.effortlessbuilding.gui.elements.GuiNumberField; +import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane; import nl.requios.effortlessbuilding.helper.ReachHelper; import java.io.IOException; diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/MirrorSettingsGui.java b/src/main/java/nl/requios/effortlessbuilding/gui/MirrorSettingsGui.java index 4c3dee5..01017d1 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/MirrorSettingsGui.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/MirrorSettingsGui.java @@ -9,6 +9,10 @@ import net.minecraftforge.fml.client.config.GuiCheckBox; import nl.requios.effortlessbuilding.BuildSettingsManager; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmodifier.Mirror; +import nl.requios.effortlessbuilding.gui.elements.GuiCollapsibleScrollEntry; +import nl.requios.effortlessbuilding.gui.elements.GuiIconButton; +import nl.requios.effortlessbuilding.gui.elements.GuiNumberField; +import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane; import nl.requios.effortlessbuilding.helper.ReachHelper; import java.io.IOException; diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/RadialMenu.java b/src/main/java/nl/requios/effortlessbuilding/gui/RadialMenu.java new file mode 100644 index 0000000..8291513 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/gui/RadialMenu.java @@ -0,0 +1,456 @@ +package nl.requios.effortlessbuilding.gui; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +import nl.requios.effortlessbuilding.buildmode.BuildModes; +import nl.requios.effortlessbuilding.proxy.ClientProxy; +import org.lwjgl.opengl.GL11; + +import com.google.common.base.Stopwatch; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.client.model.ModelLoader; + +import static nl.requios.effortlessbuilding.buildmode.BuildModes.*; + +/** + * 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 + */ +public class RadialMenu extends GuiScreen +{ + + private final float TIME_SCALE = 0.01f; + public static final RadialMenu instance = new RadialMenu(); + + private float visibility = 0.0f; + private Stopwatch lastChange = Stopwatch.createStarted(); + public BuildModeEnum switchTo = null; + //public ButtonAction doAction = null; + public boolean actionUsed = false; + + private float clampVis( + final float f ) + { + return Math.max( 0.0f, Math.min( 1.0f, f ) ); + } + + public void raiseVisibility() + { + visibility = clampVis( visibility + lastChange.elapsed( TimeUnit.MILLISECONDS ) * TIME_SCALE ); + lastChange = Stopwatch.createStarted(); + } + + public void decreaseVisibility() + { + visibility = clampVis( visibility - lastChange.elapsed( TimeUnit.MILLISECONDS ) * TIME_SCALE ); + lastChange = Stopwatch.createStarted(); + } + + public boolean isVisible() + { + return visibility > 0.001; + } + + public void configure( + final int scaledWidth, + final int scaledHeight ) + { + mc = Minecraft.getMinecraft(); + fontRenderer = mc.fontRenderer; + width = scaledWidth; + height = scaledHeight; + } + + private static class MenuButton + { + + public double x1, x2; + public double y1, y2; + public boolean highlighted; + + //public final ButtonAction action; + public TextureAtlasSprite icon; + public int color; + public String name; + public EnumFacing textSide; + + public MenuButton( + final String name, + //final ButtonAction action, + final double x, + final double y, + final TextureAtlasSprite ico, + final EnumFacing textSide ) + { + this.name = name; + //this.action = action; + x1 = x; + x2 = x + 18; + y1 = y; + y2 = y + 18; + icon = ico; + color = 0xffffff; + this.textSide = textSide; + } + + public MenuButton( + final String name, + //final ButtonAction action, + final double x, + final double y, + final int col, + final EnumFacing textSide ) + { + this.name = name; + //this.action = action; + x1 = x; + x2 = x + 18; + y1 = y; + y2 = y + 18; + color = col; + this.textSide = textSide; + } + + } + + static class MenuRegion + { + + public final BuildModeEnum mode; + public double x1, x2; + public double y1, y2; + public boolean highlighted; + + public MenuRegion( + final BuildModeEnum mode ) + { + this.mode = mode; + } + + } + + public static class SpriteIconPositioning + { + public TextureAtlasSprite sprite; + + public double left; + public double top; + public double width; + public double height; + } + + @Override + public void drawScreen( + final int mouseX, + final int mouseY, + final float partialTicks ) + { + //TODO chisels compat +// final ChiselToolType tool = ClientSide.instance.getHeldToolType( EnumHand.MAIN_HAND ); +// +// if ( tool != null ) +// { +// return; +// } + + GlStateManager.pushMatrix(); + GlStateManager.translate( 0.0F, 0.0F, 200.0F ); + + final int start = (int) ( visibility * 98 ) << 24; + final int end = (int) ( visibility * 128 ) << 24; + + drawGradientRect( 0, 0, width, height, start, end ); + + GlStateManager.disableTexture2D(); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0 ); + GlStateManager.shadeModel( GL11.GL_SMOOTH ); + final Tessellator tessellator = Tessellator.getInstance(); + final BufferBuilder buffer = tessellator.getBuffer(); + + buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR ); + + final double vecX = mouseX - width / 2; + final double vecY = mouseY - height / 2; + double radians = Math.atan2( vecY, vecX ); + + final double ring_inner_edge = 20; + final double ring_outer_edge = 50; + final double text_distnace = 65; + final double quarterCircle = Math.PI / 2.0; + + if ( radians < -quarterCircle ) + { + radians = radians + Math.PI * 2; + } + + final double middle_x = width / 2; + final double middle_y = height / 2; + + final ArrayList modes = new ArrayList(); + final ArrayList btns = new ArrayList(); + +// btns.add( new MenuButton( "mod.chiselsandbits.other.undo", ButtonAction.UNDO, text_distnace, -20, ClientSide.undoIcon, EnumFacing.EAST ) ); +// btns.add( new MenuButton( "mod.chiselsandbits.other.redo", ButtonAction.REDO, text_distnace, 4, ClientSide.redoIcon, EnumFacing.EAST ) ); + + for ( final BuildModeEnum mode : BuildModeEnum.values() ) + { + modes.add( new MenuRegion( mode ) ); + } + + switchTo = null; + //doAction = null; + + if ( !modes.isEmpty() ) + { + final int totalModes = Math.max( 3, modes.size() ); + int currentMode = 0; + final double fragment = Math.PI * 0.005; + final double fragment2 = Math.PI * 0.0025; + final double perObject = 2.0 * Math.PI / totalModes; + + for ( final MenuRegion mnuRgn : modes ) + { + final double begin_rad = currentMode * perObject - quarterCircle; + final double end_rad = ( currentMode + 1 ) * perObject - quarterCircle; + + mnuRgn.x1 = Math.cos( begin_rad ); + mnuRgn.x2 = Math.cos( end_rad ); + mnuRgn.y1 = Math.sin( begin_rad ); + mnuRgn.y2 = Math.sin( end_rad ); + + final double x1m1 = Math.cos( begin_rad + fragment ) * ring_inner_edge; + final double x2m1 = Math.cos( end_rad - fragment ) * ring_inner_edge; + final double y1m1 = Math.sin( begin_rad + fragment ) * ring_inner_edge; + final double y2m1 = Math.sin( end_rad - fragment ) * ring_inner_edge; + + final double x1m2 = Math.cos( begin_rad + fragment2 ) * ring_outer_edge; + final double x2m2 = Math.cos( end_rad - fragment2 ) * ring_outer_edge; + final double y1m2 = Math.sin( begin_rad + fragment2 ) * ring_outer_edge; + final double y2m2 = Math.sin( end_rad - fragment2 ) * ring_outer_edge; + + final float a = 0.5f; + float f = 0f; + + final boolean quad = inTriangle( + x1m1, y1m1, + x2m2, y2m2, + x2m1, y2m1, + vecX, vecY ) || inTriangle( + x1m1, y1m1, + x1m2, y1m2, + x2m2, y2m2, + 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(); + buffer.pos( middle_x + x2m1, middle_y + y2m1, zLevel ).color( f, f, f, a ).endVertex(); + buffer.pos( middle_x + x2m2, middle_y + y2m2, zLevel ).color( f, f, f, a ).endVertex(); + buffer.pos( middle_x + x1m2, middle_y + y1m2, zLevel ).color( f, f, f, a ).endVertex(); + + currentMode++; + } + } + + for ( final MenuButton btn : btns ) + { + final float a = 0.5f; + float f = 0f; + + if ( btn.x1 <= vecX && btn.x2 >= vecX && btn.y1 <= vecY && btn.y2 >= vecY ) + { + f = 1; + btn.highlighted = true; + //doAction = btn.action; + } + + buffer.pos( middle_x + btn.x1, middle_y + 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( middle_x + btn.x2, middle_y + 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(); + } + + tessellator.draw(); + + GlStateManager.shadeModel( GL11.GL_FLAT ); + + GlStateManager.translate( 0.0F, 0.0F, 5.0F ); + GlStateManager.enableTexture2D(); + GlStateManager.color( 1, 1, 1, 1.0f ); + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.bindTexture( Minecraft.getMinecraft().getTextureMapBlocks().getGlTextureId() ); + + buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR ); + + 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 scalex = 15 * sip.width * 0.5; + final double scaley = 15 * sip.height * 0.5; + final double x1 = x - scalex; + final double x2 = x + scalex; + final double y1 = y - scaley; + final double y2 = y + scaley; + + final TextureAtlasSprite sprite = sip.sprite; + + final float f = 1.0f; + final float a = 1.0f; + + final double u1 = sip.left * 16.0; + final double u2 = ( sip.left + sip.width ) * 16.0; + final double v1 = sip.top * 16.0; + final double v2 = ( sip.top + sip.height ) * 16.0; + + 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 ) + { + final float f = switchTo == null ? 1.0f : 0.5f; + final float a = 1.0f; + + final double u1 = 0; + final double u2 = 16; + final double v1 = 0; + final double v2 = 16; + + final TextureAtlasSprite sprite = btn.icon == null ? Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( ModelLoader.White.LOCATION.toString() ) : btn.icon; + + final double btnx1 = btn.x1 + 1; + final double btnx2 = btn.x2 - 1; + final double btny1 = btn.y1 + 1; + final double btny2 = btn.y2 - 1; + + final float red = f * ( ( btn.color >> 16 & 0xff ) / 255.0f ); + final float green = f * ( ( btn.color >> 8 & 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( middle_x + btnx1, middle_y + 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( middle_x + btnx2, middle_y + btny1, zLevel ).tex( sprite.getInterpolatedU( u2 ), sprite.getInterpolatedV( v1 ) ).color( red, green, blue, a ).endVertex(); + } + + tessellator.draw(); + + 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 ); + final int fixed_y = (int) ( y * text_distnace ); + final String text = mnuRgn.mode.name; + + if ( x <= -0.2 ) + { + fixed_x -= fontRenderer.getStringWidth( text ); + } + 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 ); + } + } + + for ( final MenuButton btn : btns ) + { + if ( btn.highlighted ) + { + final String text = btn.name; + + if ( btn.textSide == EnumFacing.WEST ) + { + fontRenderer.drawStringWithShadow( text, (int) ( middle_x + btn.x1 - 8 ) - fontRenderer.getStringWidth( text ), (int) ( middle_y + btn.y1 + 6 ), 0xffffffff ); + } + else if ( btn.textSide == EnumFacing.EAST ) + { + fontRenderer.drawStringWithShadow( text, (int) ( middle_x + btn.x2 + 8 ), (int) ( middle_y + btn.y1 + 6 ), 0xffffffff ); + } + else if ( btn.textSide == EnumFacing.UP ) + { + 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.DOWN ) + { + fontRenderer.drawStringWithShadow( text, (int) ( middle_x + ( btn.x1 + btn.x2 ) * 0.5 - fontRenderer.getStringWidth( text ) * 0.5 ), (int) ( middle_y + btn.y1 + 24 ), 0xffffffff ); + } + + } + } + + GlStateManager.popMatrix(); + } + + private boolean inTriangle( + final double x1, + final double y1, + final double x2, + final double y2, + final double x3, + 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( + final double n ) + { + return n > 0 ? 1 : -1; + } + + /** + * Called when the mouse is clicked. Args : mouseX, mouseY, clickedButton + */ + protected void mouseClicked( + int mouseX, + int mouseY, + int mouseButton ) throws IOException + { + if ( mouseButton == 0 ) + { + this.mc.displayGuiScreen( (GuiScreen) null ); + + if ( this.mc.currentScreen == null ) + { + this.mc.setIngameFocus(); + } + } + } +} + diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/RadialMirrorSettingsGui.java b/src/main/java/nl/requios/effortlessbuilding/gui/RadialMirrorSettingsGui.java index 83dc81e..1473b4f 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/RadialMirrorSettingsGui.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/RadialMirrorSettingsGui.java @@ -9,6 +9,10 @@ import net.minecraftforge.fml.client.config.GuiCheckBox; import nl.requios.effortlessbuilding.BuildSettingsManager; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; +import nl.requios.effortlessbuilding.gui.elements.GuiCollapsibleScrollEntry; +import nl.requios.effortlessbuilding.gui.elements.GuiIconButton; +import nl.requios.effortlessbuilding.gui.elements.GuiNumberField; +import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane; import nl.requios.effortlessbuilding.helper.ReachHelper; import java.io.IOException; diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/SettingsGui.java b/src/main/java/nl/requios/effortlessbuilding/gui/SettingsGui.java index 2a83890..91886e7 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/SettingsGui.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/SettingsGui.java @@ -7,6 +7,7 @@ import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmodifier.Array; import nl.requios.effortlessbuilding.buildmodifier.Mirror; import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; +import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane; import nl.requios.effortlessbuilding.network.BuildSettingsMessage; import nl.requios.effortlessbuilding.proxy.ClientProxy; diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/GuiCollapsibleScrollEntry.java b/src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiCollapsibleScrollEntry.java similarity index 97% rename from src/main/java/nl/requios/effortlessbuilding/gui/GuiCollapsibleScrollEntry.java rename to src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiCollapsibleScrollEntry.java index deb0031..a123163 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/GuiCollapsibleScrollEntry.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiCollapsibleScrollEntry.java @@ -1,4 +1,4 @@ -package nl.requios.effortlessbuilding.gui; +package nl.requios.effortlessbuilding.gui.elements; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/GuiIconButton.java b/src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiIconButton.java similarity index 98% rename from src/main/java/nl/requios/effortlessbuilding/gui/GuiIconButton.java rename to src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiIconButton.java index 0da85a3..9dbd0dc 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/GuiIconButton.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiIconButton.java @@ -1,4 +1,4 @@ -package nl.requios.effortlessbuilding.gui; +package nl.requios.effortlessbuilding.gui.elements; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/GuiNumberField.java b/src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiNumberField.java similarity index 95% rename from src/main/java/nl/requios/effortlessbuilding/gui/GuiNumberField.java rename to src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiNumberField.java index ac0fd2a..6f87587 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/GuiNumberField.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiNumberField.java @@ -1,4 +1,4 @@ -package nl.requios.effortlessbuilding.gui; +package nl.requios.effortlessbuilding.gui.elements; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.*; @@ -12,8 +12,8 @@ import java.util.List; public class GuiNumberField extends Gui { - int x, y, width, height; - int buttonWidth = 10; + public int x, y, width, height; + public int buttonWidth = 10; protected GuiTextField textField; protected GuiButton minusButton, plusButton; @@ -106,7 +106,7 @@ public class GuiNumberField extends Gui { } - protected void actionPerformed(GuiButton button) { + public void actionPerformed(GuiButton button) { float valueChanged = 1f; if (GuiScreen.isCtrlKeyDown()) valueChanged = 5f; if (GuiScreen.isShiftKeyDown()) valueChanged = 10f; @@ -123,7 +123,7 @@ public class GuiNumberField extends Gui { textField.updateCursorCounter(); } - protected void keyTyped(char typedChar, int keyCode) throws IOException { + public void keyTyped(char typedChar, int keyCode) throws IOException { if (!textField.isFocused()) return; // if (Character.isDigit(typedChar) || typedChar == '.' || typedChar == '-' || keyCode == Keyboard.KEY_BACK // || keyCode == Keyboard.KEY_DELETE || keyCode == Keyboard.KEY_LEFT || keyCode == Keyboard.KEY_RIGHT diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/GuiScrollPane.java b/src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiScrollPane.java similarity index 99% rename from src/main/java/nl/requios/effortlessbuilding/gui/GuiScrollPane.java rename to src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiScrollPane.java index bbf21e0..7cdf5ab 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/GuiScrollPane.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/elements/GuiScrollPane.java @@ -1,4 +1,4 @@ -package nl.requios.effortlessbuilding.gui; +package nl.requios.effortlessbuilding.gui.elements; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; diff --git a/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java b/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java index 2c05e69..b034a4b 100644 --- a/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java +++ b/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java @@ -4,21 +4,30 @@ import net.minecraft.block.Block; import net.minecraft.block.SoundType; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.client.resources.IResource; import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.SoundEvents; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.IThreadListener; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundCategory; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.fml.client.registry.ClientRegistry; @@ -36,7 +45,9 @@ import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; import net.minecraftforge.fml.relauncher.Side; import nl.requios.effortlessbuilding.BuildSettingsManager; import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; +import nl.requios.effortlessbuilding.gui.RadialMenu; import nl.requios.effortlessbuilding.gui.SettingsGui; import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.RenderHelper; @@ -45,6 +56,11 @@ import nl.requios.effortlessbuilding.network.BlockBrokenMessage; import nl.requios.effortlessbuilding.network.BlockPlacedMessage; import nl.requios.effortlessbuilding.network.BuildSettingsMessage; import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.HashMap; @Mod.EventBusSubscriber(Side.CLIENT) public class ClientProxy implements IProxy { @@ -53,6 +69,8 @@ public class ClientProxy implements IProxy { public static RayTraceResult currentLookAt; private static int breakCooldown = 0; + private static final HashMap buildModeIcons = new HashMap<>(); + @Override public void preInit(FMLPreInitializationEvent event) { } @@ -60,12 +78,13 @@ public class ClientProxy implements IProxy { @Override public void init(FMLInitializationEvent event) { // register key bindings - keyBindings = new KeyBinding[3]; + keyBindings = new KeyBinding[4]; // instantiate the key bindings keyBindings[0] = new KeyBinding("key.effortlessbuilding.hud.desc", Keyboard.KEY_ADD, "key.effortlessbuilding.category"); keyBindings[1] = new KeyBinding("key.effortlessbuilding.replace.desc", Keyboard.KEY_SUBTRACT, "key.effortlessbuilding.category"); keyBindings[2] = new KeyBinding("key.effortlessbuilding.creative.desc", Keyboard.KEY_F4, "key.effortlessbuilding.category"); + keyBindings[3] = new KeyBinding("key.effortlessbuilding.mode.desc", Keyboard.KEY_LMENU, "key.effortlessbuilding.category"); // register all the key bindings for (int i = 0; i < keyBindings.length; ++i) { @@ -111,11 +130,80 @@ public class ClientProxy implements IProxy { } } + @SubscribeEvent + public static void onTextureStitch(final TextureStitchEvent.Pre event) { + //register icon textures + final TextureMap map = event.getMap(); + + for ( final BuildModes.BuildModeEnum mode : BuildModes.BuildModeEnum.values() ) + { + loadIcon( map, mode ); + } + } + + 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); + } + @SubscribeEvent public static void onMouseInput(InputEvent.MouseInputEvent event) { Minecraft mc = Minecraft.getMinecraft(); EntityPlayerSP player = mc.player; + if (Minecraft.getMinecraft().currentScreen != null) return; + if (!BuildModifiers.isEnabled(BuildSettingsManager.getBuildSettings(player), player.getPosition())) return; if (mc.gameSettings.keyBindUseItem.isPressed()) { @@ -206,6 +294,7 @@ public class ClientProxy implements IProxy { player.sendChatMessage("/gamemode 1"); } } + } @SubscribeEvent @@ -235,6 +324,82 @@ public class ClientProxy implements IProxy { } } + @SubscribeEvent + public static void onRenderGameOverlay(final RenderGameOverlayEvent.Post event ) { + //final ChiselToolType tool = getHeldToolType( lastHand ); + final RenderGameOverlayEvent.ElementType type = event.getType(); + //TODO check if chisel tool in hand (and has menu) + if (type == RenderGameOverlayEvent.ElementType.ALL) + { + final boolean wasVisible = RadialMenu.instance.isVisible(); + + if ( keyBindings[3].isKeyDown() ) + { + RadialMenu.instance.actionUsed = false; + RadialMenu.instance.raiseVisibility(); + } + else + { + if ( !RadialMenu.instance.actionUsed ) + { + if ( RadialMenu.instance.switchTo != null ) + { + ClientProxy.playRadialMenuSound(); + BuildModes.setBuildMode(Minecraft.getMinecraft().player, RadialMenu.instance.switchTo); + } + + //TODO change buildmode settings + + ClientProxy.playRadialMenuSound(); + } + + RadialMenu.instance.actionUsed = true; + RadialMenu.instance.decreaseVisibility(); + } + + if ( RadialMenu.instance.isVisible() ) + { + final ScaledResolution res = event.getResolution(); + RadialMenu.instance.configure( res.getScaledWidth(), res.getScaledHeight() ); + + if ( wasVisible == false ) + { + RadialMenu.instance.mc.inGameHasFocus = false; + RadialMenu.instance.mc.mouseHelper.ungrabMouseCursor(); + } + + if ( RadialMenu.instance.mc.inGameHasFocus ) + { + KeyBinding.unPressAllKeys(); + } + + final int k1 = Mouse.getX() * res.getScaledWidth() / RadialMenu.instance.mc.displayWidth; + final int l1 = res.getScaledHeight() - Mouse.getY() * res.getScaledHeight() / RadialMenu.instance.mc.displayHeight - 1; + + net.minecraftforge.client.ForgeHooksClient.drawScreen( RadialMenu.instance, k1, l1, event.getPartialTicks() ); + } + else + { + if ( wasVisible ) + { + RadialMenu.instance.mc.setIngameFocus(); + } + } + } + } + + public static void playRadialMenuSound() + { + final float volume = 0.1f; + if ( volume >= 0.0001f ) + { + final PositionedSoundRecord psr = new PositionedSoundRecord( SoundEvents.UI_BUTTON_CLICK, SoundCategory.MASTER, + volume, 1.0f, Minecraft.getMinecraft().player.getPosition() ); + Minecraft.getMinecraft().getSoundHandler().playSound(psr); + } + } + + public static RayTraceResult getLookingAt(EntityPlayer player) { // World world = player.world; diff --git a/src/main/resources/assets/effortlessbuilding/lang/en_us.lang b/src/main/resources/assets/effortlessbuilding/lang/en_us.lang index 3e24125..d7b8d3b 100644 --- a/src/main/resources/assets/effortlessbuilding/lang/en_us.lang +++ b/src/main/resources/assets/effortlessbuilding/lang/en_us.lang @@ -2,6 +2,7 @@ key.effortlessbuilding.category=Effortless Building key.effortlessbuilding.hud.desc=Open Settings key.effortlessbuilding.replace.desc=Toggle QuickReplace key.effortlessbuilding.creative.desc=Toggle Survival/Creative Mode +key.effortlessbuilding.mode.desc=Radial Menu item.effortlessbuilding:randomizer_bag.name=Randomizer Bag item.effortlessbuilding:reach_upgrade1.name=Reach Upgrade 1 diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/floor.png b/src/main/resources/assets/effortlessbuilding/textures/icons/floor.png new file mode 100644 index 0000000..613217d Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/icons/floor.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/line.png b/src/main/resources/assets/effortlessbuilding/textures/icons/line.png new file mode 100644 index 0000000..7805d40 Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/icons/line.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/normal.png b/src/main/resources/assets/effortlessbuilding/textures/icons/normal.png new file mode 100644 index 0000000..8b81303 Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/icons/normal.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/normalplus.png b/src/main/resources/assets/effortlessbuilding/textures/icons/normalplus.png new file mode 100644 index 0000000..3b7244f Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/icons/normalplus.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/wall.png b/src/main/resources/assets/effortlessbuilding/textures/icons/wall.png new file mode 100644 index 0000000..613217d Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/icons/wall.png differ