Rift render and right-click improvments
- Highlight rift core when trying to place a door next to a rift, and warn player about instability (place again to confirm placing next to rift) - Clean up LSystem class - Make rifts jitter less - Stop rift particle flicker, lower max age - Make rifts grow a bit slower - Replace option to use old animation with option to highlight the rift core - Make rift render yaw match teleport target yaw
This commit is contained in:
parent
ba887a4066
commit
5f8375a693
12 changed files with 161 additions and 240 deletions
|
@ -6,28 +6,33 @@ import org.poly2tri.geometry.polygon.PolygonPoint;
|
|||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||
|
||||
import java.awt.Point; // TODO: wrong point class!
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.awt.*; // TODO: Wrong point class!
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
public final class LSystem { // TODO: Finish cleaning up this class
|
||||
public static ArrayList<PolygonStorage> curves = new ArrayList<>();
|
||||
public final class LSystem { // TODO: Rewrite this class
|
||||
public static ArrayList<PolygonInfo> curves = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* An array containing the args to generate a curve.
|
||||
* index 0 = rules
|
||||
* index 1 = angle
|
||||
* index 2 = start string
|
||||
*/
|
||||
// https://en.wikipedia.org/wiki/L-system
|
||||
//
|
||||
// System: {rules, angle, start_string}
|
||||
// Rules: rule1:rule_2:...:rule_n
|
||||
// Rule: from_substring>to_substring
|
||||
//
|
||||
// Each iteration, rules are applied to the string. After, string
|
||||
// is interpreted as commands for a pencil on a sheet of paper:
|
||||
// F - move forward by one step
|
||||
// + - turn clockwise by angle
|
||||
// - - turn counter-clockwise by angle
|
||||
// [ - save state (push to stack)
|
||||
// ] - restore state (pop from stack)
|
||||
public static final String[] TERDRAGON = {"F>+F----F++++F-", "60", "F"};
|
||||
public static final String[] DRAGON = {"X>X+YF:Y>FX-Y", "90", "FX"};
|
||||
public static final String[] TWINDRAGON = {"X>X+YF:Y>FX-Y", "90", "FX--FX"};
|
||||
public static final String[] VORTEX = {"X>X+YF:Y>FX-Y", "90", "FX---FX"};
|
||||
|
||||
static { // Used to be in mod init
|
||||
// TODO
|
||||
static {
|
||||
// TODO: Move to separate class
|
||||
LSystem.generateLSystem("terdragon", LSystem.TERDRAGON, 4);
|
||||
LSystem.generateLSystem("terdragon", LSystem.TERDRAGON, 5);
|
||||
//LSystem.generateLSystem("terdragon", LSystem.TERDRAGON, 6); // degenerate
|
||||
|
@ -83,73 +88,23 @@ public final class LSystem { // TODO: Finish cleaning up this class
|
|||
output = generate(args[2], steps, lSystemsRule);
|
||||
|
||||
//get the boundary of the polygon
|
||||
PolygonStorage polygon = getBoundary(convertToPoints(angle, output, steps));
|
||||
List<Point> polygon = getBoundary(convertToPoints(angle, output, steps));
|
||||
|
||||
//replace the boundary of the polygon with a series of points representing triangles for rendering
|
||||
polygon.points = tesselate(polygon);
|
||||
|
||||
curves.add(polygon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Naively returns all of the points comprising the fractal
|
||||
*/
|
||||
public static PolygonStorage getSpaceFillingCurve(ArrayList<double[]> input) {
|
||||
// store max x and y values to create bounding box
|
||||
int maxY = Integer.MIN_VALUE;
|
||||
int maxX = Integer.MIN_VALUE;
|
||||
int minY = Integer.MAX_VALUE;
|
||||
int minX = Integer.MAX_VALUE;
|
||||
|
||||
// store confirmed duplicates here
|
||||
HashSet<Point> duplicates = new HashSet<>();
|
||||
|
||||
// store possible singles here
|
||||
HashSet<Point> singles = new HashSet<>();
|
||||
|
||||
// list to store confirmed singles and output in the correct order
|
||||
ArrayList<Point> output = new ArrayList<>();
|
||||
|
||||
// sort into Hashmaps and hashsets to make contains operations possible,
|
||||
// while testing for duplicates
|
||||
for (double[] point : input) {
|
||||
// convert doubles to ints and record min/max values
|
||||
|
||||
int xCoord = (int) Math.round(point[0]);
|
||||
int yCoord = (int) Math.round(point[1]);
|
||||
|
||||
if (xCoord > maxX) {
|
||||
maxX = xCoord;
|
||||
}
|
||||
if (xCoord < minX) {
|
||||
minX = xCoord;
|
||||
}
|
||||
|
||||
if (yCoord > maxY) {
|
||||
maxY = yCoord;
|
||||
}
|
||||
if (yCoord < minY) {
|
||||
minY = yCoord;
|
||||
}
|
||||
output.add(new Point(xCoord, yCoord));
|
||||
}
|
||||
return new PolygonStorage(output, maxX, maxY, minX, minY);
|
||||
curves.add(new PolygonInfo(tesselate(polygon)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an unordered list of points comprising a fractal curve and builds a
|
||||
* closed polygon around it
|
||||
*/
|
||||
public static PolygonStorage getBoundary(ArrayList<double[]> input) {
|
||||
public static List<Point> getBoundary(ArrayList<double[]> input) {
|
||||
// store max x and y values to create bounding box
|
||||
int maxY = Integer.MIN_VALUE;
|
||||
int maxX = Integer.MIN_VALUE;
|
||||
int minY = Integer.MAX_VALUE;
|
||||
int minX = Integer.MAX_VALUE;
|
||||
|
||||
// store confirmed duplicates here
|
||||
HashSet<Point> duplicates = new HashSet<>();
|
||||
|
||||
// store possible singles here
|
||||
HashSet<Point> singles = new HashSet<>();
|
||||
|
||||
|
@ -159,24 +114,14 @@ public final class LSystem { // TODO: Finish cleaning up this class
|
|||
// sort into Hashmaps and hashsets to make contains operations possible,
|
||||
// while testing for duplicates
|
||||
for (double[] point : input) {
|
||||
// convert doubles to ints and record min/max values
|
||||
|
||||
int xCoord = (int) Math.round(point[0]);
|
||||
int yCoord = (int) Math.round(point[1]);
|
||||
|
||||
if (xCoord > maxX) {
|
||||
maxX = xCoord;
|
||||
}
|
||||
if (xCoord < minX) {
|
||||
minX = xCoord;
|
||||
}
|
||||
if (xCoord > maxX) maxX = xCoord;
|
||||
if (xCoord < minX) minX = xCoord;
|
||||
if (yCoord > maxY) maxY = yCoord;
|
||||
if (yCoord < minY) minY = yCoord;
|
||||
|
||||
if (yCoord > maxY) {
|
||||
maxY = yCoord;
|
||||
}
|
||||
if (yCoord < minY) {
|
||||
minY = yCoord;
|
||||
}
|
||||
singles.add(new Point(xCoord, yCoord));
|
||||
}
|
||||
|
||||
|
@ -235,7 +180,7 @@ public final class LSystem { // TODO: Finish cleaning up this class
|
|||
}
|
||||
while (!(output.get(output.size() - 1).equals(firstPoint) && output.size() > 1) && output.size() < singles.size());
|
||||
|
||||
return new PolygonStorage(output, maxX, maxY, minX, minY);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -341,30 +286,50 @@ public final class LSystem { // TODO: Finish cleaning up this class
|
|||
}
|
||||
|
||||
// a data container class to transmit the important information about the polygon
|
||||
public static class PolygonStorage {
|
||||
public PolygonStorage(ArrayList<Point> points, int maxX, int maxY, int minX, int minY) {
|
||||
this.points = points;
|
||||
this.maxX = maxX;
|
||||
this.maxY = maxY;
|
||||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
}
|
||||
|
||||
public ArrayList<Point> points;
|
||||
public static class PolygonInfo {
|
||||
public final ArrayList<Point> points;
|
||||
|
||||
public int maxX;
|
||||
public int maxY;
|
||||
public int minX;
|
||||
public int minY;
|
||||
public final int maxY;
|
||||
public final int minX;
|
||||
public final int minY;
|
||||
|
||||
public PolygonInfo(ArrayList<Point> points) {
|
||||
int minX, minY, maxX, maxY;
|
||||
minX = minY = maxX = maxY = 0;
|
||||
|
||||
// Find bounding box of the polygon
|
||||
this.points = points;
|
||||
if (points.size() > 0) {
|
||||
Point firstPoint = points.get(0);
|
||||
minX = firstPoint.x;
|
||||
minY = firstPoint.y;
|
||||
maxX = firstPoint.x;
|
||||
maxY = firstPoint.y;
|
||||
|
||||
for (Point point : points) {
|
||||
if (point.x < minX) minX = point.x;
|
||||
if (point.y < minY) minY = point.y;
|
||||
if (point.x > maxX) maxX = point.x;
|
||||
if (point.y > maxY) maxY = point.y;
|
||||
}
|
||||
}
|
||||
|
||||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
this.maxX = maxX;
|
||||
this.maxY = maxY;
|
||||
}
|
||||
}
|
||||
|
||||
public static ArrayList<Point> tesselate(PolygonStorage polygon) {
|
||||
// TODO: Use the GLU tesselator (GPU) instead of poly2tri (CPU): http://wiki.lwjgl.org/wiki/Using_GLU_Tesselator.html
|
||||
public static ArrayList<Point> tesselate(List<Point> polygon) {
|
||||
ArrayList<Point> points = new ArrayList<>();
|
||||
|
||||
ArrayList<PolygonPoint> polyPoints = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < polygon.points.size(); i++) {
|
||||
polyPoints.add(new PolygonPoint(polygon.points.get(i).x, polygon.points.get(i).y));
|
||||
for (Point p : polygon) {
|
||||
polyPoints.add(new PolygonPoint(p.x, p.y));
|
||||
}
|
||||
|
||||
Polygon poly = new Polygon(polyPoints);
|
||||
|
@ -379,88 +344,4 @@ public final class LSystem { // TODO: Finish cleaning up this class
|
|||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
// TODO: Figure out what this was meant to be
|
||||
/*
|
||||
public static ArrayList<Point> tesselate(Polygon polygon) {
|
||||
ArrayList<Point> points = new ArrayList<>();
|
||||
|
||||
Tessellator tess = new Tessellator();
|
||||
double[] verticesC1 = new double[polygon.points.size() * 3];
|
||||
for (int i = 0; i < verticesC1.length; i += 3) {
|
||||
Point point = polygon.points.get(i / 3);
|
||||
verticesC1[i] = point.x;
|
||||
verticesC1[i + 1] = point.y;
|
||||
verticesC1[i + 2] = 0;
|
||||
}
|
||||
|
||||
tess.glBeginPolygon();
|
||||
|
||||
for (int i = 0; i < polygon.points.size(); i++) {
|
||||
tess.gluTessVertex(verticesC1, i * 3, i);
|
||||
}
|
||||
|
||||
tess.gluEndPolygon();
|
||||
|
||||
|
||||
//Prints out the result of the tessellation.
|
||||
for (int i = 0; i < tess.primitives.size(); i++) {
|
||||
System.out.println(tess.primitives.get(i).toString());
|
||||
}
|
||||
//To draw the shape it is now a simple matter to put the vertex data you passed in initially into a VBO, and the indices returned
|
||||
//into an IBO (Index VBO). You have the types of the primitives and the number of indices for each one. Drawing the result should
|
||||
//be a walk in the park, as long as you have read the appropriate tutorials here or elsewhere.
|
||||
|
||||
|
||||
for (int i = 0; i < tess.primitives.size(); i++) {
|
||||
|
||||
Primitives.Primitive prim = tess.primitives.get(i);
|
||||
ArrayList<Integer> vIndex = prim.vertices;
|
||||
|
||||
if (prim.type == GL11.GL_TRIANGLE_STRIP) {
|
||||
for (int ii = 0; ii < vIndex.size() - 1; ii++) {
|
||||
points.add(new Point((int) verticesC1[vIndex.get(ii) * 3], (int) verticesC1[vIndex.get(ii) * 3 + 1]));
|
||||
points.add(new Point((int) verticesC1[vIndex.get(ii + 1) * 3], (int) verticesC1[vIndex.get(ii + 1) * 3 + 1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (prim.type == GL11.GL_TRIANGLES) {
|
||||
for (int ii = 0; ii < vIndex.size(); ii++) {
|
||||
points.add(new Point((int) verticesC1[vIndex.get(ii) * 3], (int) verticesC1[vIndex.get(ii) * 3 + 1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (prim.type == GL11.GL_TRIANGLE_FAN) {
|
||||
Integer firstIndex = vIndex.get(0);
|
||||
// points.add(new Point((int)verticesC1[vIndex.get(firstIndex)],(int) verticesC1[vIndex.get(firstIndex)+1]));
|
||||
|
||||
Integer[] vertexList = new Integer[vIndex.size() * 3];
|
||||
for (Integer ii = 0; ii < vIndex.size() - 2; ii++) {
|
||||
vertexList[ii * 3] = vIndex.get(0);
|
||||
vertexList[ii * 3 + 1] = vIndex.get(ii + 1);
|
||||
vertexList[ii * 3 + 2] = vIndex.get(ii + 2);
|
||||
}
|
||||
|
||||
for (Integer vertex : vertexList) {
|
||||
if (vertex != null) {
|
||||
points.add(new Point((int) verticesC1[vertex * 3], (int) verticesC1[vertex * 3 + 1]));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.out.println(vertexList);
|
||||
}
|
||||
|
||||
// points.add(new Point((int)verticesC1[vIndex.get(firstIndex)],(int) verticesC1[vIndex.get(firstIndex)+1]));
|
||||
// points.add(new Point((int)verticesC1[vIndex.get(ii)*3],(int) verticesC1[vIndex.get(ii)+1]));
|
||||
// points.add(new Point((int)verticesC1[vIndex.get(ii+1)*3],(int) verticesC1[vIndex.get(ii+1)*3+1]));
|
||||
|
||||
// points.add(new Point((int)verticesC1[index],(int)verticesC1[index+1]));
|
||||
// System.out.println(verticesC1[index]+","+verticesC1[index+1]+","+verticesC1[index+2]);
|
||||
|
||||
|
||||
//System.out.println(tess.primitives.get(i).toString());
|
||||
}
|
||||
return points;
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.dimdev.dimdoors;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import org.dimdev.dimdoors.shared.ModConfig;
|
||||
|
@ -85,8 +86,9 @@ public class DimDoors {
|
|||
}
|
||||
|
||||
public static void sendTranslatedMessage(Entity entity, String text, Object... translationArgs) {
|
||||
if (entity instanceof EntityPlayerMP) {
|
||||
EntityPlayerMP player = (EntityPlayerMP) entity;
|
||||
// TODO: check if too long and split into several messages?
|
||||
if (entity instanceof EntityPlayer) {
|
||||
EntityPlayer player = (EntityPlayer) entity;
|
||||
player.sendStatusMessage(new TextComponentTranslation(text, translationArgs), ModConfig.general.useStatusBar);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package org.dimdev.dimdoors.client;
|
||||
|
||||
import org.dimdev.dimdoors.shared.world.ModDimensions;
|
||||
import net.minecraft.client.particle.ParticleSimpleAnimated;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.dimdev.dimdoors.shared.world.ModDimensions;
|
||||
|
||||
// This has exactly the same appearence as the 1.6.4 mod.
|
||||
@SideOnly(Side.CLIENT)
|
||||
|
@ -14,35 +14,33 @@ public class ParticleRiftEffect extends ParticleSimpleAnimated { // TODO: colors
|
|||
|
||||
private float colorMultiplier;
|
||||
|
||||
public ParticleRiftEffect(World world, double x, double y, double z, double motionX, double motionY, double motionZ, float nonPocketColorMultiplier, float pocketColorMultiplier, float scale, int size, int spread) {
|
||||
public ParticleRiftEffect(World world, double x, double y, double z, double motionX, double motionY, double motionZ, float nonPocketColorMultiplier, float pocketColorMultiplier, float scale, int averageAge, int ageSpread) {
|
||||
super(world, x, y, z, 160, 8, 0);
|
||||
this.motionX = motionX;
|
||||
this.motionY = motionY;
|
||||
this.motionZ = motionZ;
|
||||
|
||||
particleScale *= scale;
|
||||
particleMaxAge = size - spread / 2 + rand.nextInt(spread);
|
||||
particleMaxAge = averageAge - ageSpread / 2 + rand.nextInt(ageSpread);
|
||||
colorMultiplier = ModDimensions.isDimDoorsPocketDimension(world) ? pocketColorMultiplier : nonPocketColorMultiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) {
|
||||
if (particleAge < particleMaxAge / 3 || (particleAge + particleMaxAge) / 3 % 2 == 0) {
|
||||
float oldRed = particleRed;
|
||||
float oldGreen = particleGreen;
|
||||
float oldBlue = particleBlue;
|
||||
float oldAlpha = particleAlpha;
|
||||
setRBGColorF(colorMultiplier * particleRed, colorMultiplier * particleGreen, colorMultiplier * particleBlue);
|
||||
setAlphaF(0.7f);
|
||||
super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
|
||||
setRBGColorF(oldRed, oldGreen, oldBlue);
|
||||
setAlphaF(oldAlpha);
|
||||
}
|
||||
float oldRed = particleRed;
|
||||
float oldGreen = particleGreen;
|
||||
float oldBlue = particleBlue;
|
||||
float oldAlpha = particleAlpha;
|
||||
setRBGColorF(colorMultiplier * particleRed, colorMultiplier * particleGreen, colorMultiplier * particleBlue);
|
||||
setAlphaF(1 - (float) particleAge / particleMaxAge);
|
||||
super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
|
||||
setRBGColorF(oldRed, oldGreen, oldBlue);
|
||||
setAlphaF(oldAlpha);
|
||||
}
|
||||
|
||||
public static class Rift extends ParticleRiftEffect {
|
||||
public Rift(World world, double x, double y, double z, double motionX, double motionY, double motionZ) {
|
||||
super(world, x, y, z, motionX, motionY, motionZ, 0.0f, 0.7f, 0.55f, 3800, 1600);
|
||||
super(world, x, y, z, motionX, motionY, motionZ, 0.0f, 0.7f, 0.55f, 2000, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import static org.lwjgl.opengl.GL11.*;
|
|||
|
||||
public final class RiftCrackRenderer {
|
||||
|
||||
public static void drawCrack(int riftRotation, LSystem.PolygonStorage poly, double size, double xWorld, double yWorld, double zWorld) {
|
||||
public static void drawCrack(float riftRotation, LSystem.PolygonInfo poly, double size, double xWorld, double yWorld, double zWorld) {
|
||||
// Calculate the proper size for the rift render
|
||||
double scale = size / (poly.maxX - poly.minX);
|
||||
|
||||
|
@ -39,11 +39,11 @@ public final class RiftCrackRenderer {
|
|||
double[] jitters = new double[jCount];
|
||||
|
||||
|
||||
double aggroScaling = size * size * size / 700f;
|
||||
double jitterScale = size * size * size / 1300f;
|
||||
// We use random constants here on purpose just to get different wave forms
|
||||
double xJitter = aggroScaling * Math.sin(1.1f * time*size) * Math.sin(0.8f * time);
|
||||
double yJitter = aggroScaling * Math.sin(1.2f * time*size) * Math.sin(0.9f * time);
|
||||
double zJitter = aggroScaling * Math.sin(1.3f * time*size) * Math.sin(0.7f * time);
|
||||
double xJitter = jitterScale * Math.sin(1.1f * time*size) * Math.sin(0.8f * time);
|
||||
double yJitter = jitterScale * Math.sin(1.2f * time*size) * Math.sin(0.9f * time);
|
||||
double zJitter = jitterScale * Math.sin(1.3f * time*size) * Math.sin(0.7f * time);
|
||||
|
||||
// generate a series of waveforms
|
||||
for (int i = 0; i < jCount; i += 1) {
|
||||
|
|
|
@ -18,17 +18,22 @@ public class TileEntityFloatingRiftRenderer extends TileEntitySpecialRenderer<Ti
|
|||
private static final ResourceLocation tesseract_path = new ResourceLocation(DimDoors.MODID + ":textures/other/tesseract.png");
|
||||
|
||||
private static final Tesseract tesseract = new Tesseract();
|
||||
public static long showRiftCoreUntil = 0;
|
||||
|
||||
@Override
|
||||
public void render(TileEntityFloatingRift rift, double x, double y, double z, float partialTicks, int destroyStage, float alpha) {
|
||||
if (ModConfig.graphics.tesseractRifts) {
|
||||
renderTesseract(rift, x, y, z, partialTicks, destroyStage, alpha);
|
||||
if (ModConfig.graphics.showRiftCore) {
|
||||
renderTesseract(rift, x, y, z, partialTicks);
|
||||
} else {
|
||||
renderCrack(rift, x, y, z, partialTicks, destroyStage, alpha);
|
||||
long timeLeft = showRiftCoreUntil - System.currentTimeMillis();
|
||||
if (timeLeft >= 0/*3000 || timeLeft >= 0 && timeLeft / 500 % 2 == 0*/) {
|
||||
renderTesseract(rift, x, y, z, partialTicks);
|
||||
}
|
||||
}
|
||||
renderCrack(rift, x, y, z);
|
||||
}
|
||||
|
||||
private void renderCrack(TileEntityFloatingRift rift, double x, double y, double z, float partialTicks, int destroyStage, float alpha) {
|
||||
private void renderCrack(TileEntityFloatingRift rift, double x, double y, double z) {
|
||||
GL11.glPushMatrix();
|
||||
// TODO: Make the sky get dark when a player approaches a rift?
|
||||
|
||||
|
@ -37,11 +42,8 @@ public class TileEntityFloatingRiftRenderer extends TileEntitySpecialRenderer<Ti
|
|||
GlStateManager.disableCull();
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.enableBlend();
|
||||
// TODO: This was commented out in the old code, what does it do?
|
||||
//GlStateManager.colorLogicOp(GlStateManager.LogicOp.INVERT);
|
||||
//GlStateManager.enableColorLogic();
|
||||
|
||||
RiftCrackRenderer.drawCrack(rift.riftRotation, rift.getCurve(), rift.growth / 90, x + 0.5, y + 1.5, z + 0.5);
|
||||
RiftCrackRenderer.drawCrack(rift.riftYaw, rift.getCurve(), rift.size / 120, x + 0.5, y + 1.5, z + 0.5);
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableTexture2D();
|
||||
|
@ -51,7 +53,7 @@ public class TileEntityFloatingRiftRenderer extends TileEntitySpecialRenderer<Ti
|
|||
GL11.glPopMatrix();
|
||||
}
|
||||
|
||||
private void renderTesseract(TileEntityFloatingRift rift, double x, double y, double z, float partialTicks, int destroyStage, float alpha) {
|
||||
private void renderTesseract(TileEntityFloatingRift rift, double x, double y, double z, float partialTicks) {
|
||||
double radian = updateTesseractAngle(rift, partialTicks) * TrigMath.DEG_TO_RAD;
|
||||
RGBA color = rift.getColor();
|
||||
if (color == null) color = new RGBA(1, 0.5f, 1, 1);
|
||||
|
|
|
@ -124,9 +124,14 @@ public final class ModConfig {
|
|||
}
|
||||
|
||||
public static class Graphics {
|
||||
@Name("tesseractRifts")
|
||||
@LangKey("dimdoors.graphics.tesseractRifts")
|
||||
public boolean tesseractRifts = false;
|
||||
@Name("showRiftCore")
|
||||
@LangKey("dimdoors.graphics.showRiftCore")
|
||||
public boolean showRiftCore = false;
|
||||
|
||||
@Name("highlightRiftCoreFor")
|
||||
@LangKey("dimdoors.graphics.highlightRiftCoreFor")
|
||||
@RangeInt(min = -1)
|
||||
public int highlightRiftCoreFor = 15000;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ public class BlockFloatingRift extends BlockSpecialAir implements ITileEntityPro
|
|||
public static final String ID = "rift";
|
||||
|
||||
public BlockFloatingRift() {
|
||||
// super();
|
||||
setRegistryName(new ResourceLocation(DimDoors.MODID, ID));
|
||||
setUnlocalizedName(ID);
|
||||
setTickRandomly(true);
|
||||
|
@ -58,7 +57,6 @@ public class BlockFloatingRift extends BlockSpecialAir implements ITileEntityPro
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, IBlockAccess world, BlockPos pos) {
|
||||
if (ModConfig.general.riftBoundingBoxInCreative) {
|
||||
EntityPlayer player = DimDoors.proxy.getLocalPlayer();
|
||||
|
@ -104,6 +102,7 @@ public class BlockFloatingRift extends BlockSpecialAir implements ITileEntityPro
|
|||
rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D));
|
||||
}
|
||||
|
||||
// TODO: depend on size, direction of particles should be rift orientation
|
||||
FMLClientHandler.instance().getClient().effectRenderer.addEffect(new ParticleRiftEffect.Rift(
|
||||
world,
|
||||
pos.getX() + .5, pos.getY() + 1.5, pos.getZ() + .5,
|
||||
|
|
|
@ -5,6 +5,9 @@ import net.minecraft.client.util.ITooltipFlag;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.dimdev.dimdoors.DimDoors;
|
||||
import org.dimdev.dimdoors.client.TileEntityFloatingRiftRenderer;
|
||||
import org.dimdev.dimdoors.shared.ModConfig;
|
||||
import org.dimdev.dimdoors.shared.blocks.IRiftProvider;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
|
@ -21,7 +24,7 @@ import org.dimdev.dimdoors.shared.tileentities.TileEntityFloatingRift;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ItemDimensionalDoor extends ItemDoor { // TODO: Biomes O' Plenty doors
|
||||
public abstract class ItemDimensionalDoor extends ItemDoor { // TODO: All wood types, Biome O' Plenty support
|
||||
|
||||
public <T extends Block & IRiftProvider<TileEntityEntranceRift>> ItemDimensionalDoor(T block) {
|
||||
super(block);
|
||||
|
@ -29,18 +32,33 @@ public abstract class ItemDimensionalDoor extends ItemDoor { // TODO: Biomes O'
|
|||
|
||||
@Override
|
||||
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
|
||||
BlockPos originalPos = pos; // super.onItemUse needs the actual position
|
||||
if (!world.getBlockState(pos).getBlock().isReplaceable(world, pos)) pos = pos.offset(facing);
|
||||
boolean placedOnRift = world.getBlockState(pos).getBlock().equals(ModBlocks.RIFT);
|
||||
|
||||
if (!placedOnRift && isRiftNear(world, pos)) {
|
||||
if (world.isRemote) {
|
||||
DimDoors.chat(player, "rifts.entrances.rift_too_close"); // TODO: Linebreaks don't work in status message.
|
||||
TileEntityFloatingRiftRenderer.showRiftCoreUntil = System.currentTimeMillis() + ModConfig.graphics.highlightRiftCoreFor;
|
||||
}
|
||||
return EnumActionResult.FAIL;
|
||||
}
|
||||
|
||||
if (world.isRemote) return EnumActionResult.FAIL;
|
||||
boolean replaceable = world.getBlockState(pos).getBlock().isReplaceable(world, pos);
|
||||
|
||||
|
||||
// Store the rift entity if there's a rift block there that may be broken
|
||||
TileEntityFloatingRift rift = null;
|
||||
if (world.getBlockState(replaceable ? pos : pos.offset(facing)).getBlock().equals(ModBlocks.RIFT)) {
|
||||
rift = (TileEntityFloatingRift) world.getTileEntity(replaceable ? pos : pos.offset(facing));
|
||||
rift.setUnregisterDisabled(true);
|
||||
if (placedOnRift) {
|
||||
if (canBePlacedOnRift()) {
|
||||
rift = (TileEntityFloatingRift) world.getTileEntity(pos);
|
||||
rift.setUnregisterDisabled(true);
|
||||
} else {
|
||||
DimDoors.sendTranslatedMessage(player, "rifts.entrances.cannot_be_placed_on_rift");
|
||||
}
|
||||
}
|
||||
|
||||
EnumActionResult result = super.onItemUse(player, world, pos, hand, facing, hitX, hitY, hitZ);
|
||||
if (!replaceable) pos = pos.offset(facing);
|
||||
EnumActionResult result = super.onItemUse(player, world, originalPos, hand, facing, hitX, hitY, hitZ);
|
||||
if (result == EnumActionResult.SUCCESS) {
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
if (rift == null) {
|
||||
|
@ -66,6 +84,22 @@ public abstract class ItemDimensionalDoor extends ItemDoor { // TODO: Biomes O'
|
|||
return result;
|
||||
}
|
||||
|
||||
public static boolean isRiftNear(World world, BlockPos pos) {
|
||||
// TODO: This is called every right click server-side! Is this efficient enough? Maybe use rift registry?
|
||||
for (int x = pos.getX() - 5; x < pos.getX() + 5; x++) {
|
||||
for (int y = pos.getY() - 5; y < pos.getY() + 5; y++) {
|
||||
for (int z = pos.getZ() - 5; z < pos.getZ() + 5; z++) {
|
||||
BlockPos searchPos = new BlockPos(x, y, z);
|
||||
if (world.getBlockState(searchPos).getBlock() == ModBlocks.RIFT) {
|
||||
TileEntityFloatingRift rift = (TileEntityFloatingRift) world.getTileEntity(searchPos);
|
||||
if (Math.sqrt(pos.distanceSq(searchPos)) < rift.size / 250) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void addInformation(ItemStack stack, World world, List<String> tooltip, ITooltipFlag flag) {
|
||||
|
|
|
@ -18,7 +18,6 @@ import net.minecraft.world.World;
|
|||
import org.dimdev.ddutils.RotatedLocation;
|
||||
import org.dimdev.dimdoors.shared.blocks.ModBlocks;
|
||||
import org.dimdev.dimdoors.shared.rifts.DestinationMaker;
|
||||
import org.dimdev.dimdoors.shared.rifts.destinations.GlobalDestination;
|
||||
import org.dimdev.dimdoors.shared.sound.ModSounds;
|
||||
import org.dimdev.dimdoors.shared.tileentities.TileEntityFloatingRift;
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.dimdev.dimdoors.DimDoors;
|
|||
import org.dimdev.ddutils.RotatedLocation;
|
||||
import org.dimdev.dimdoors.shared.blocks.ModBlocks;
|
||||
import org.dimdev.dimdoors.shared.rifts.DestinationMaker;
|
||||
import org.dimdev.dimdoors.shared.rifts.destinations.GlobalDestination;
|
||||
import org.dimdev.dimdoors.shared.sound.ModSounds;
|
||||
import org.dimdev.dimdoors.shared.tileentities.TileEntityFloatingRift;
|
||||
|
||||
|
|
|
@ -37,20 +37,20 @@ import java.util.Random;
|
|||
|
||||
// TODO: Some of these properties will need to persist when converting to door and then back to rift!
|
||||
//Need to be saved:
|
||||
@Saved /*package-private*/ int updateTimer;
|
||||
@Saved public boolean closing = false; // TODO: maybe we could have a closingSpeed instead?
|
||||
@Saved public int spawnedEndermenID = 0;
|
||||
@Saved public float growth = 0;
|
||||
@Saved protected float teleportTargetYaw;
|
||||
@Saved protected float teleportTargetPitch;
|
||||
@Saved public float size = 0; // TODO: store size in blocks
|
||||
@Saved public float riftYaw = random.nextInt(360);
|
||||
@Saved protected float teleportTargetPitch; // TODO: also render rift rotated on pitch axis?
|
||||
@Saved public int curveId = random.nextInt(LSystem.curves.size());
|
||||
@Saved public int riftRotation = random.nextInt(360);
|
||||
|
||||
// Don't need to be saved
|
||||
@Setter private boolean unregisterDisabled = false;
|
||||
int updateTimer;
|
||||
|
||||
@SideOnly(Side.CLIENT) public double renderAngle; // This is @SideOnly(Side.CLIENT), don't initialize the field ( = 0), or class initialization won't work on the server!
|
||||
@SideOnly(Side.CLIENT) private int cachedCurveId;
|
||||
@SideOnly(Side.CLIENT) private LSystem.PolygonStorage curve; // Cache the curve for efficiency
|
||||
@SideOnly(Side.CLIENT) private LSystem.PolygonInfo curve; // Cache the curve for efficiency
|
||||
|
||||
public TileEntityFloatingRift() {
|
||||
updateTimer = random.nextInt(UPDATE_PERIOD);
|
||||
|
@ -67,8 +67,8 @@ import java.util.Random;
|
|||
// Check if this rift should render white closing particles and
|
||||
// spread the closing effect to other rifts nearby.
|
||||
if (closing) {
|
||||
if (growth > 0) {
|
||||
growth -= ModConfig.general.riftCloseSpeed;
|
||||
if (size > 0) {
|
||||
size -= ModConfig.general.riftCloseSpeed;
|
||||
} else {
|
||||
world.setBlockToAir(pos);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ import java.util.Random;
|
|||
// Logarithmic growth
|
||||
for (int n = 0; n < 10; n++) {
|
||||
// TODO: growthSpeed and growthSize config options
|
||||
growth += 1F / (growth + 1);
|
||||
size += 1F / (size + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ import java.util.Random;
|
|||
}
|
||||
|
||||
public void setTeleportTargetRotation(float yaw, float pitch) {
|
||||
teleportTargetYaw = yaw;
|
||||
riftYaw = yaw;
|
||||
teleportTargetPitch = pitch;
|
||||
markDirty();
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ import java.util.Random;
|
|||
}
|
||||
|
||||
@Override public float getDestinationYaw(float entityYaw) {
|
||||
return teleportTargetYaw;
|
||||
return riftYaw;
|
||||
}
|
||||
|
||||
@Override public float getDestinationPitch(float entityPitch) {
|
||||
|
@ -188,7 +188,7 @@ import java.util.Random;
|
|||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public LSystem.PolygonStorage getCurve() {
|
||||
public LSystem.PolygonInfo getCurve() {
|
||||
if (curve != null && curveId == cachedCurveId) {
|
||||
return curve;
|
||||
}
|
||||
|
|
|
@ -118,6 +118,8 @@ rifts.destinations.escape.did_not_use_rift=You didn't use a rift to enter the po
|
|||
rifts.destinations.escape.rift_has_closed=The rift you used to enter the pocket dimension has closed and you ended up in Limbo!
|
||||
rifts.destinations.private_pocket_exit.did_not_use_rift=You didn't use a rift to enter the pocket dimension and you ended up in Limbo!
|
||||
rifts.destinations.private_pocket_exit.rift_has_closed=The rift you used to enter the pocket dimension has closed and you ended up in Limbo!
|
||||
rifts.entrances.rift_too_close=Placing a door this close to a tear in the world would be dangerous. Either place it on the rift's core (tesseract) or further away. Or use a rift signature to make a rift anyway, at your own risk!
|
||||
rifts.entrances.cannot_be_placed_on_rift=This type of door can't be placed on a rift.
|
||||
|
||||
dimdoors.general=General Options
|
||||
dimdoors.general.tooltip=General configuration options for the mod
|
||||
|
|
Loading…
Reference in a new issue